---
url: https://docs.sunlicense.com/how-to/electron-app.md
description: >-
  How to add license keys to an Electron app - check the buyer's key with the
  SunLicense JavaScript SDK in the main process, show an activation window on a
  rejection, keep working offline with a signed license file, and sell it on
  Gumroad, Lemon Squeezy, Payhip or Stripe.
---

# How to add license keys to an Electron app

**Short answer:** `npm install sunlicense`, check the key in Electron's **main process** when the app is ready, open
your activation window when SunLicense says no, and keep working when it can't be reached (the last good check or an
offline license file). Never check from the renderer: the key and your API key stay out of web content.

```js
// main.js (main process)
import { app, BrowserWindow, dialog } from 'electron';
import { SunLicense } from 'sunlicense';

const sunlicense = new SunLicense({ baseUrl: 'https://api.sunlicense.com', token: API_KEY }); // from your build

app.whenReady().then(async () => {
  const key = readSavedKey();                     // saved under app.getPath('userData') after activation
  if (!key) return showActivationWindow();
  try {
    const r = await sunlicense.validate(key, { host: machineId() });
    if (r.status === 400) {                       // EXPIRED, REVOKED, TOO_MANY_MACHINES…
      dialog.showErrorBox('License', `This license can't be used: ${r.data?.code}`);
      return showActivationWindow();
    }
  } catch {
    // offline: carry on (or require a recent good check / an offline license file)
  }
  new BrowserWindow({ width: 1000, height: 700 }).loadFile('index.html');
});
```

`validate` resolves to `{ valid, status, data }` and throws only when SunLicense can't be reached.

**Or let your AI agent do it:** paste the [setup prompt](https://sunlicense.com/prompt) into Claude Code, Cursor or
Codex in your app's folder. It adds the check and the activation flow and proves them with a test license.

Free plan: 3 products, 100 licenses, no credit card. [Create a free account](https://sunlicense.com/start?ref=docs-howto-electron).

## Step by step

1. **In the dashboard:** a product, a policy (for example *3 machines*: a buyer's desktop and laptop) and an **API key**,
   which can only validate licenses. For trials, add a trial policy; for subscriptions, connect your store and ended
   subscriptions suspend the key on their own.
2. **Activation window.** A small window with one text field; it sends the key to the main process over IPC
   (`ipcMain.handle('activate', …)`), the main process validates it and saves it. Save it in
   `app.getPath('userData')`, encrypted with `safeStorage` if you like; it's the buyer's key, not a secret from them.
3. **Your API key** goes into the build (a generated module from `SUNLICENSE_API_KEY` at packaging time), never git.
4. **Machine id:** a hash of OS, architecture and host name, sent as `host`:

   ```js
   import { createHash } from 'node:crypto';
   import os from 'node:os';
   const machineId = () => createHash('sha256').update(`${os.platform()}|${os.arch()}|${os.hostname()}`).digest('hex');
   ```

   [Choosing a machine id](/guide/sdks#choosing-a-machine-id). Let buyers move to a new computer by freeing a machine
   on the license (dashboard, or the [customer portal](/guide/customer-portal) on Lite and Standard).
5. **Offline.** Desktop apps travel. Either accept a check from the last few days (store its date with the key) or
   give buyers a signed [offline license file](/guide/offline-licenses) that the app verifies with your public key and
   no network.
6. **Results:** 200 opens the app, 400 shows why ([result codes](/guide/concepts#validation-result-codes)) and the
   activation window, anything else carries on. Mask keys in logs and UI (`AX8P-XXXX-XXXX-XXXX`).
7. **Re-check now and then** (at start-up and every few hours while open), so refunds and revokes reach running copies.

## Packaging honestly

Electron apps ship JavaScript that anyone can read inside `app.asar`. A license check stops casual sharing and lets you
revoke leaked keys; it doesn't make the code secret. Run the main-process code through
[obfuscation](/guide/obfuscation) (javascript-obfuscator) and keep a piece of the product behind the license with
[protection](/guide/protection) or [protected files](/guide/protected-files) (Standard).

## Selling it

[Gumroad](/integrations/gumroad), [Lemon Squeezy](/integrations/lemon-squeezy), [Payhip](/integrations/payhip),
[itch.io](/integrations/itch-io) and [Stripe](/integrations/stripe) issue a key per purchase and revoke it on a refund.
More on [licensing desktop apps](https://sunlicense.com/for/desktop-apps/).
