Electron auto-updater for private applications

Learn how to distribute your commercial Electron application.

Requirements

When you create a release on GitHub you will need to upload the build artifacts (binaries). Make sure you don't modify the filenames of your binaries as incorrect filenames may result in your updates being rejected. For example, the following filenames are valid:

  • example-darwin-x64-2.0.0.zip
  • example-darwin-arm64-2.0.0.zip
  • example-win32-arm64-2.0.0.zip
  • example-win32-x64-2.0.0.zip
  • example-linux-x64-2.0.0.zip

Electron License Package

You can license and add auto-update support your Electron application in just a matter of minutes with Anystack's plug-and-play licensing package. Scroll down to the 'Manual configuration' section if you want to manually integrate auto-updates.

Requirements

  • You will need your product ID.
  • A license key with the permissions: license:validate and license:activate.

Installation

To get started, you will need to install Anystack's NPM package:

npm install @anystack/electron-license

Open your main process, like main.js, and initiate Anystack with the following parameters:

1// Electron Forge
2import { autoUpdater } from 'electron';
3// Electron Builder
4import { autoUpdater } from 'electron-updater';
5 
6const Anystack = new (require('@anystack/electron-license'))(
7 {
8 api: {
9 key: 'YOUR-API-KEY',
10 productId: 'YOUR-PRODUCT-ID',
11 },
12 license: {
13 encryptionKey: 'UNIQUE-KEY',
14 }
15 },
16 autoUpdater
17);

The API key and product ID parameters are mandatory. Ensure your API key only has the license:activate and license:validate permission scopes. You can omit the autoUpdater if you don't use Anystack for distribution.

You can enter any random string as the encryption key to encrypt the data on a user's device. The only reason why you would change this key in the future is when the key was breached. If you change the encryption key, all your users will be prompted to enter their license again.

Finally, you will need to provide Anystack with your primary application window. When a valid license is available, Anystack will open your primary window. If no valid license is on your user's device, Anystack will prompt the user to enter their license information.

1const createWindow = () => {
2 
3 const mainWindow = new BrowserWindow({
4 width: 800,
5 height: 600,
6 show: false // Important to set this to false
7 });
8 
9 mainWindow.loadURL(MAIN_WINDOW_WEBPACK_ENTRY);
10 
11 Anystack.ifAuthorized(mainWindow);
12};

Make sure you set show to false for your main window. The main window will "unlock" when a device is authorized.

That's all it takes. Your application will now prompt your users for their license and auto-update their applications.

Set your environment variable

Set NODE_ENV to development during development.
Set NODE_ENV to production when building a production release.

Production

When you are ready to build a production ready release you will need to make sure you Electron application can access the necessary files needed for the license prompt window. This can be achieved by adding the required directory to the extraResources or extraResource config option:

1// Electron Builder
2extraResources: [
3 {
4 from: "./node_modules/@anystack/electron-license/license",
5 to: "license",
6 filter: "**/*"
7 }
8]
9 
10// Electron Native (e.g. Forge)
11packagerConfig: {
12 extraResource: './node_modules/@anystack/electron-license/license'
13}

Additional options

The following options allow you to tweak a couple of configuration options and provide your logo, and copy.

1{
2 "api":{
3 "key":"YOUR-API-KEY",
4 "productId":"YOUR-PRODUCT-ID"
5 },
6 "license":{
7 "requireEmail":false,
8 "checkIn":{
9 "value":24,
10 "unit":"hours"
11 },
12 "encryptionKey":"UNIQUE-KEY",
13 "trial":{
14 "enabled":false,
15 "value":7,
16 "unit":"days"
17 }
18 },
19 "prompt":{
20 "title":"Anystack",
21 "subtitle":"Activate your license to get started",
22 "logo":"https://anystack.sh/img/emblem.svg",
23 "email":"Email address",
24 "licenseKey":"License key",
25 "activateLicense":"Activate license",
26 "trial":"Try Anystack for 7 days",
27 "trialExpired":"Thank you for trying Anystack. Your trial has expired; to continue, please purchase a license.",
28 "errors":{
29 "NOT_FOUND":"Your license information did not match our records.",
30 "SUSPENDED":"Your license has been suspended.",
31 "EXPIRED":"Your license has been expired.",
32 "FINGERPRINT_INVALID":"No license was found for this device.",
33 "FINGERPRINT_ALREADY_EXISTS":"An active license already exists for this device.",
34 "MAX_USAGE_REACHED":"Your license has reached its activation limit.",
35 "RELEASE_CONSTRAINT":"Your license has no access to this version."
36 }
37 },
38 "confirmation":{
39 "title":"You are awesome!",
40 "subtitle":"Thank you for activating your product license."
41 }
42}

If you use Anystack's contacts option together with licensing and want to make sure the license key matches with the contact, you can set license.requireEmail to true. Setting this value to true will prompt users to enter their email.

By default, Anystack will do a license validity check every 24 hours. You can change this by setting the value and unit of the checkIn config.

Manual configuration

You can also choose to manually add auto update support to your Electron application.

Add the following code to your main.js.

1import {app} from 'electron'
2import {autoUpdater} from "electron-updater"
3 
4const server = 'https://dist.anystack.sh/v1/electron'
5const productId = ''
6 
7// If you require a valid license, you will need to pass the user's license key.
8// You will need to store the user's license key somewhere.
9const key = 'a3105b99-e849-412b-ac1c-6f9d6aade946';
10const url = `${server}/${productId}/update/${process.platform}/${process.arch}/${app.getVersion()}?key=${key}`
11 
12// If you don't require a license to download new releases you can omit the key from the url.
13const url = `${server}/${productId}/update/${process.platform}/${process.arch}/${app.getVersion()}`
14 
15autoUpdater.setFeedURL({
16 url: url,
17 serverType: 'json',
18})
19 
20app.on('ready', function() {
21 autoUpdater.checkForUpdates();
22});