Skip to main content
Migrate Already selling? Move your customers to Keylight without re-issuing a single key.
Keylight

Guide · macOS licensing

How to license your macOS app with license keys outside the App Store

A practical guide to selling a Mac app directly: Apple signing, checkout webhooks, license keys, activation, offline validation, device limits, refunds, and where Keylight fits.

Start Free

Updated May 2026

If you sell a macOS app outside the App Store, you need your own license keys, Stripe or another checkout, activation inside the app, offline validation for launches without internet, device limits, and a way to handle refunds. This guide explains how those pieces fit together and where Keylight belongs in the stack.

Keylight is a license key system for macOS apps sold outside the Mac App Store. It helps developers create, validate, revoke, and manage license keys after a customer pays through Stripe or another checkout system.

A typical macOS licensing flow looks like this:

  1. The developer signs and notarizes the app with Apple Developer ID.
  2. The customer buys the app through Stripe, Paddle, Lemon Squeezy, FastSpring, Polar, or a custom checkout.
  3. The payment provider sends a webhook after purchase.
  4. Keylight creates a license key for that customer.
  5. The customer activates the app with the license key.
  6. The app validates the license and stores an offline-ready signed lease locally.
  7. Keylight tracks devices, activations, refunds, revocations, and renewals.

This page is the hub for the whole model. If you are still deciding whether to sell directly, start with selling a Mac app outside the App Store. If you already know you need keys, the general software license keys guide explains the primitives this page applies to macOS.

How macOS licensing works outside the App Store

Inside the App Store, Apple gives you a receipt. Your app asks Apple’s APIs whether the receipt is valid, and Apple owns the payment, refund, subscription, tax, and customer relationship around that purchase.

Outside the App Store, you replace that receipt with your own entitlement. Usually that entitlement is a license key or a signed license token. The important shift is that payment and licensing become separate systems:

  • the checkout provider charges the customer;
  • the licensing system creates an entitlement after payment;
  • the Mac app activates the current device;
  • the app stores a signed local lease so it can start quickly and work offline;
  • the server remains the source of truth for renewals, refunds, revocations, and activation counts.

That separation is why Stripe alone is not enough. Stripe is excellent at money movement, but it does not issue software keys, sign license payloads, track activated Macs, or validate offline leases. The Stripe license keys guide covers that boundary in more detail.

What Apple still requires: Developer ID, signing, notarization

Selling directly does not mean bypassing macOS security. For a normal downloadable Mac app, you still need to ship something users can open without scary warnings.

In practice, that means:

  1. Enroll in the Apple Developer Program.
  2. Sign the app with a Developer ID certificate.
  3. Notarize the build with Apple.
  4. Staple the notarization ticket where appropriate.
  5. Distribute the signed and notarized app from your website, an updater, or a customer portal.

Developer ID and notarization answer “is this app from a known developer and has Apple checked it for malware?” Licensing answers “is this customer allowed to use the paid product?” They are related in the release flow, but they are not the same layer.

How payment creates a license key

After a customer buys your app, the checkout provider sends an event. With Stripe, the common event is checkout.session.completed. With subscriptions, later events update renewal, cancellation, and payment-failure state.

A licensing system receives that webhook and maps the payment to a product, plan, and customer. It then creates a license key or signed entitlement for that customer. A good system also makes this step idempotent: if the payment provider retries the webhook, the customer gets the same license, not duplicate keys.

The license should contain the practical facts your app needs: product, plan, expiry or renewal status, features, activation limit, revocation state, and signature metadata. Keylight license keys are built around that signed-entitlement model.

How Stripe, Paddle, Lemon Squeezy, FastSpring, Polar, and custom checkouts fit in

Stripe, Paddle, Lemon Squeezy, FastSpring, Polar, and custom checkout flows all sit before licensing. They decide how the customer pays. The licensing layer decides what the paid customer can run.

The clean integration point is a webhook:

  • Stripe Checkout completes and sends an event.
  • Paddle or Lemon Squeezy sends an order, subscription, refund, or license-related event.
  • FastSpring sends a fulfillment event.
  • Polar or a custom checkout sends your own purchase event.
  • Keylight turns the event into a license and keeps later billing events in sync.

That means Keylight does not need to replace every commerce tool. It replaces the licensing layer. If you want the simplest direct-sales setup, Keylight’s Stripe integration connects checkout to license creation while you keep your own Stripe account.

How activation works inside the Mac app

Activation is the first online handshake between the app and the licensing server. The customer enters a key, or the app receives one through a purchase flow. The app sends the key plus a stable device fingerprint to the licensing API.

The server checks that the license exists, is not revoked, covers the right product, and has not exceeded its activation limit. If the activation is allowed, the server records the device and returns a signed license lease for the app to cache.

That lease is what the app reads on future launches. The activation server still owns device counts and support actions, but the launch path should not depend on a network call every time. See device activations for the product side and preventing license key sharing for the customer-experience tradeoffs.

Here is a compact Swift sketch of the app-side shape:

import SwiftUI
import Security

struct LicenseKeyActivationView: View {
    @State private var licenseKey = ""
    @State private var status = "Enter your license key"

    var body: some View {
        VStack(alignment: .leading, spacing: 12) {
            TextField("XXXX-XXXX-XXXX-XXXX", text: $licenseKey)
                .textFieldStyle(.roundedBorder)

            Button("Activate") {
                Task { await activateLicenseKey() }
            }

            Text(status)
        }
        .padding()
    }

    private func activateLicenseKey() async {
        do {
            let response = try await LicensingAPI.activate(
                licenseKey: licenseKey,
                deviceName: Host.current().localizedName ?? "Mac"
            )

            try Keychain.save(
                service: "dev.keylight.example",
                account: "signed-license-token",
                value: response.signedLicenseToken
            )

            status = "Activated"
        } catch {
            status = "Could not activate this license"
        }
    }
}

@MainActor
func checkLicenseOnLaunch() async -> Bool {
    guard let token = try? Keychain.read(
        service: "dev.keylight.example",
        account: "signed-license-token"
    ) else {
        return false
    }

    return LicenseVerifier.verifySignedTokenLocally(token)
}

The exact API names depend on your SDK, but the responsibilities stay the same: collect a license key, call an activation endpoint, store the signed license token in Keychain, and check local license status on app launch.

Where to store license data on macOS

Store sensitive activation data in the macOS Keychain. A signed lease is not a password, but it is still the thing your app uses to prove the customer is licensed. Keychain gives you OS-managed storage, user scoping, and better protection than a plain preferences file.

Use Application Support for non-sensitive cache data: timestamps, last successful refresh metadata, UI hints, or logs that help you debug licensing support cases. Keep the rule simple: if modifying or stealing the value could affect access, prefer Keychain. The guide on where to store license data on macOS goes deeper.

How offline validation works

Offline validation means the app can decide whether the cached license is valid without contacting your server. The usual approach is a signed lease: the server signs a JSON payload, and the app ships with the public key needed to verify it.

On launch, the app reads the cached lease, verifies the signature, checks expiry and revocation fields, and unlocks the right features. Separately, when the device is online and the refresh window is due, the app contacts the server in the background to pick up subscription changes, refunds, device updates, or a new lease.

This avoids the worst desktop-app failure mode: a paying customer opens the app on a plane, in a hotel, or behind a strict corporate firewall and gets locked out because a server call failed. The full mechanics are in offline license validation and how offline license validation works.

How device limits and deactivations work

Device limits stop one license key from becoming a public password. A common indie Mac app policy is one customer, two or three Macs. The server enforces that at activation time by counting distinct device fingerprints attached to the license.

Good device activation systems are strict enough to prevent abuse and forgiving enough for real customers. People replace laptops, reinstall macOS, use a desktop and a laptop, or need support to remove an old machine. That is why deactivation matters as much as activation.

Keylight tracks active devices per license, lets developers or customers deactivate old machines, and keeps the app-side lease model offline-friendly. The device activations feature page explains how that works without forcing a network check on every launch.

How refunds and revocations work

Refunds are normal when you sell software directly. The licensing system should make them boring.

When Stripe or another provider reports a refund, chargeback, cancellation, or failed renewal, the licensing layer marks the license revoked or expired. The app picks that up the next time it refreshes online. Until then, a previously valid offline lease may continue working for a short period. That delay is the deliberate tradeoff that lets legitimate customers keep using the app when they have no network.

For most Mac apps, that tradeoff is worth it: instant revocation requires a server call on every launch, which breaks offline use. Refund revocation covers the support and billing side of this flow.

Where Keylight fits

Keylight sits between your checkout and your app. You keep the payment provider that makes sense for your business. Keylight handles the licensing work that checkout providers do not want to own: key creation, signed leases, activation limits, offline validation, refund revocation, renewals, dashboards, and customer license portals.

For a typical Stripe setup, the stack is:

  1. Your website sends the customer to Stripe Checkout.
  2. Stripe sends Keylight a webhook after payment.
  3. Keylight creates and emails the license key.
  4. Your Mac app activates the key and stores a signed lease.
  5. Your app validates locally on launch and refreshes periodically.
  6. Keylight keeps license state in sync with refunds, renewals, and device changes.

If you are building the full direct-sales funnel, pair this page with the macOS apps use case, the Swift implementation guide on adding license keys to a Swift macOS app, and the broader guide to selling a Mac app outside the App Store.

Keylight plans start at $19/month, with a free tier for testing the full payment-to-license-to-app flow before you ship. See Pricing when you are ready to connect the pieces.

Frequently asked

Can I sell a macOS app outside the App Store?+

Yes. You can sell a macOS app directly from your website, but you should sign it with Developer ID and notarize it so macOS users can install it safely.

How do license keys work for macOS apps?+

After purchase, a payment provider sends a webhook to a licensing system. The licensing system creates a license key. The app validates that key, activates the current device, and stores a signed local license token.

Can I use Stripe for macOS app license keys?+

Yes. Stripe can handle checkout and subscriptions, while Keylight handles license creation, activation, validation, revocation, and device limits.

Can a macOS app validate licenses offline?+

Yes. The app can store a signed local license lease and periodically refresh it with the licensing server.

Where should a Mac app store license data?+

Sensitive activation data should be stored in the macOS Keychain. Non-sensitive cache data can be stored in Application Support.

Does Keylight replace Paddle or Lemon Squeezy?+

Keylight replaces the licensing layer. Developers can use Stripe directly, or connect other payment providers through webhooks.

Start licensing your app today

Drop in the Swift SDK, point it at your dashboard, and sell paid apps in under a minute. Free forever tier included.

Start Free