LicenseManager

Blog

How RabbitGUI sells its Electron app with license keys

5 min read

The RabbitGUI app next to a license key

RabbitGUI is a desktop client for RabbitMQ, built with Electron and sold on macOS, Windows and Linux. Developers use it to browse messages without consuming them, spy on live traffic, replay dead letters and see a broker’s routing graph. It sells as a one-time purchase, 29€ with free updates for life, a 30-day money-back guarantee and no account to create.

That model is simple for the customer. Behind it, until this autumn, sat a license server the RabbitGUI team had written and hosted themselves. This is the story of why they replaced it with LicenseManager.dev, and how the switch went.

The starting point: a homemade license server

When RabbitGUI launched, the team needed three things: create a license when a Stripe payment goes through, activate it on a machine, and check it once in a while so the app keeps working offline. Like many small software teams, they built it themselves. A small backend received Stripe webhooks, stored licenses, handled activations and answered the app’s periodic checks.

It worked. But it came with a list of jobs that had nothing to do with RabbitMQ:

  • Hosting and uptime. If the server is down, nobody can buy the app and new users can’t activate it. Monitoring, backups, upgrades and incidents were all on the team.
  • Security. Signing keys, protecting activation endpoints from abuse, storing customer data and keeping dependencies patched, for a component every paying customer depends on.
  • Refunds by hand. Each refund meant finding the payment, refunding it in Stripe, then remembering to revoke the license.
  • A roadmap blocked by the backend. Customers asked for monthly and yearly plans, often because their company approves recurring expenses more easily than a one-off purchase. Adding renewals, failed payments, cancellations and grace periods would have meant rewriting a large part of the server.

What they needed to keep

Before switching, the team checked that every promise made to existing customers would survive the move:

  • Lifetime licenses with free updates. RabbitGUI ships updates through its built-in auto-updater, and a 2025 buyer must keep getting them.
  • Offline use. Developers often work on locked-down networks. The app should only need to reach the license server once in a while.
  • The money-back guarantee. A refund within 30 days, with the license revoked automatically.
  • No accounts. The customer pays, receives a key by email and pastes it in the app.

LicenseManager.dev covers all four with a single policy: a lifetime duration, updates included, a machine limit, and Stripe connected so that every purchase creates a key and emails it to the customer.

The integration: one object in the main process

RabbitGUI keeps everything that touches the network or the disk in Electron’s main process, and the license check is no exception. The app creates one LicenseManager from the @licenseman/electron SDK with its product id, its public key and the running version:

import { LicenseManager } from '@licenseman/electron'
 
export const licenseManager = new LicenseManager({
  productId: app.isPackaged ? '<live product id>' : '<test product id>',
  publicKey: '<product public key>',
  version: APP_VERSION,
})

The renderer never talks to the license server. It asks the main process over IPC for a snapshot (license state, whether the app is running offline, the latest version this license allows) and receives a new snapshot whenever the state changes. Activation is one call, licenseManager.setLicenseKey(key), and the “Manage my license” button opens the customer portal with licenseManager.getPortalUrl(), where customers can see their purchase and ask for a refund.

Because the SDK validates signed license data locally, the app keeps working without a connection and only refreshes the license when it can.

Migrating existing customers without asking them anything

The part the team worried about most was existing customers. Nobody should have to dig out an old email to re-enter a key.

Their keys were imported into LicenseManager.dev, and the new version of the app migrates them silently on launch. If the app finds a key stored by the old system and no current license, it activates that key with LicenseManager.dev in the background. The old key is deleted only once the server gives a definitive answer, so a network error at that moment simply means another try at the next launch. For customers, the update looked like any other update.

What changed for the team

  • No license server to host. Licensing costs less than hosting their own server did, and the on-call worry is gone: purchases and activations no longer depend on a server the team runs.
  • Refunds are automatic. A refund in the portal refunds the Stripe payment and updates the license, with nobody stepping in.
  • Subscriptions are a configuration change. Monthly and yearly plans are new policies next to the lifetime one, not a backend rewrite. RabbitGUI announced them alongside the switch.
  • Less security surface of their own. Customer data and key signing live in infrastructure built for that purpose. RabbitMQ data was never involved: RabbitGUI connects directly to the user’s brokers, and messages and credentials never reach RabbitGUI or LicenseManager.dev.

The RabbitGUI team tells the story from their side, including what it changes for their users, in We built our own license server. Here’s why we’re ditching it.

Takeaways for your own Electron app

  • Build the product, not the license server. A homemade server works on day one. The cost shows up later, in uptime, security and every pricing change you want to make.
  • Keep the check in the main process. The renderer only needs a state to display.
  • Plan the migration of existing keys before you switch. A silent activation on launch, retried until the server answers, means existing customers never notice.
  • Pick a licensing model you can change. Starting with one-time purchases and adding subscriptions later should be a new policy, not a new backend.

If you sell an Electron app, the Electron guide shows the same integration step by step.

More articles