If you sell a desktop app on Gumroad, it hands every buyer a license key. But Gumroad stops there — checking that key inside your app is entirely up to you. Here's how to do it properly in Node/Electron, plus the three traps that catch almost everyone.
We'll use gumroad-license-lite, a tiny, zero-dependency, MIT-licensed helper (you can npm install it or just copy its ~120 lines).
Turn on license keys in Gumroad
On your product, enable "Generate a unique license key per sale," then grab your product_id (in the product settings / API). Every buyer now gets a key on their receipt.Verify a key
const { verifyGumroadLicense } = require('gumroad-license-lite');
const result = await verifyGumroadLicense({
productId: 'YOUR_PRODUCT_ID',
licenseKey,
});
if (result.valid) {
unlockApp(result.email);
}
result.valid is true only if the key is real and the sale wasn't refunded, disputed, or a cancelled subscription — not just "does this key exist," which is gotcha #1 below.
- Gate your app on launch You don't want to call Gumroad on every launch, and you want the app to survive a flaky connection. LicenseGate caches the result and re-checks periodically:
const path = require('node:path');
const { LicenseGate } = require('gumroad-license-lite');
const gate = new LicenseGate({
productId: 'YOUR_PRODUCT_ID',
storageFile: path.join(app.getPath('userData'), 'license.json'),
recheckEveryDays: 3,
offlineGraceDays: 14,
});
// on your activation screen:
await gate.activate(userEnteredKey);
// on every launch:
const status = await gate.check();
if (!status.licensed) showActivationScreen();
The 3 gotchas
"Valid" isn't the same as "exists." A refunded or charged-back sale still has a real, working key. If you only check that the key exists, people can buy, copy the key, refund, and keep your app forever. Always check the refund / dispute / subscription flags (the helper above does this for you).
The uses counter is global, not per-device. Gumroad tracks a uses count, but it can't tell you which machines — so you can't actually enforce "3 devices per license." One key can quietly unlock a hundred installs.
Offline means locked out. A pure online check fails the moment your user has no internet — on a plane, on hotel wifi — and your paying customer can't open the app. A local cache (like above) softens this, but a plain JSON cache is editable, so it's friction-reduction, not real protection.
When you outgrow the basic check
An online check is genuinely fine for a lot of apps. But when those three gotchas start costing real money, you need cryptographically signed, device-bound tokens that verify offline and automatic lockout on refunds and chargebacks. That's a meaningfully bigger build — a signing server, client SDKs, a refund webhook — so I packaged it as KeyGate for people who'd rather not assemble it from scratch. Either way, the free tool above is the right place to start.
TL;DR
Enable license keys and grab your product_id
Check validity, not just existence
Cache for offline use — but know its limits
Free tool: https://github.com/apecollective/gumroad-license-lite
How do you handle licensing for the apps you sell on Gumroad? Genuinely curious what others are doing.




















