Use case · macOS
Licensing for macOS apps sold outside the App Store
Sell your Mac app directly, keep 100% of the relationship, and license it properly — signed keys, offline validation, Stripe checkout.
Start FreeFor indie macOS developers selling apps directly — outside the Mac App Store.
- Apple takes 15–30% and owns the customer relationship.
- Rolling your own license keys means crypto, a server, and a dashboard.
- Customers expect the app to work offline, on a plane, behind a firewall.
Updated March 2026
Selling a Mac app outside the App Store is one of the most commercially sound decisions an indie developer can make — but it requires solving a problem Apple normally handles for you: licensing. This guide walks through why direct distribution is worth it, what licensing actually involves, and how to implement it without becoming a crypto engineer.
Why sell a Mac app outside the App Store
The App Store takes 15% of revenue for qualifying small developers and 30% for everyone else. That fee does buy something — discovery, payment processing, and a trusted install flow — but for many developers the math stops working quickly.
The more significant cost is invisible: Apple owns the customer. When someone buys your app through the App Store, their purchase history, contact details, and renewal relationship all live inside Apple’s ecosystem. You receive a payment notification. You do not receive an email address, a way to contact your users about a major update, or any path to a direct relationship that survives outside Apple’s platform.
Direct distribution flips this completely. Customers pay through Stripe, which means you hold their billing details, can issue receipts, run campaigns, and communicate without an intermediary. You see churn in real time, you can offer coupons, and you can move to a subscription model without waiting for App Store policy changes.
There are real tradeoffs. You give up App Store discovery, you handle your own marketing entirely, and you need to implement licensing yourself — the function Apple was quietly performing via receipt validation. But for productivity tools, developer tools, creative software, and niche utilities with clear audiences, the economics of direct distribution are compelling.
What licensing a direct-sold Mac app requires
App Store receipt validation is a straightforward server call — your app proves to Apple that it was purchased, and Apple confirms. Remove the App Store and you need an equivalent system that is independent of any platform.
A complete licensing implementation for a direct-sold Mac app includes:
Key generation. When a customer completes a purchase, your server mints a unique license key and delivers it — typically by email and shown on a post-purchase page. The key must be unique per customer, tied to the purchase record, and unforgeable.
Cryptographic signing. A plain random string can be shared freely. A cryptographically signed key cannot be forged without the private key that signed it. Modern licensing systems sign an entitlement payload — the customer’s email, the product they purchased, the expiry date, and activation limits — using an asymmetric key pair such as Ed25519. The app holds the public half; only your server holds the private half.
Offline verification. The app verifies the signature locally using the bundled public key. No network call required. If the signature is valid and the entitlement fields match, the license is accepted.
A dashboard. Customers lose keys, need to transfer them to a new machine, or request additional activations. You need an admin surface to look up licenses, reset activations, and handle support requests — plus a customer-facing portal for self-service resets.
Revocation. When a refund is issued or a chargeback arrives, the key must be marked revoked. The next time the app phones home for a revalidation, the server returns a rejection and the app transitions to an unlicensed state.
Building all of this from scratch typically takes weeks. The cryptographic primitives are straightforward, but the operational layer — the dashboard, the email delivery, the Stripe webhook handlers, the customer portal — accumulates fast. Most indie developers end up either under-building (a plain random key with no offline verification) or over-building (a full backend that needs maintaining indefinitely).
Offline-first matters on macOS
Desktop users have a fundamentally different expectation from web users. A web app that requires a live server call to open is normal. A desktop app that refuses to launch without an internet connection feels broken.
macOS users launch apps on planes, in rural areas with spotty connectivity, in corporate environments behind aggressive firewalls, and in the exact moments when the network is temporarily down. An app that can only validate its license through a live server call has no good option there: fail closed, and a meaningful fraction of legitimate customers hit failures that feel like bugs; fail open, and the check enforces nothing, because it can be skipped by blocking the network.
Offline license validation solves this cleanly. Because the license is an Ed25519-signed payload, the app can verify it with only the bundled public key. There is no server call at launch. The signature either validates against the public key or it does not — the result is binary and instant.
Revalidation against the server still happens periodically — typically once every few days when the app launches with connectivity — to pick up revocations and entitlement changes. But the critical startup path is always local. A customer on a flight with a valid license never sees a “could not connect” error.
This architecture is also more resilient for you as the developer. If your server is briefly unavailable, your users are unaffected. The licensing service could be down for an hour and no customer would notice.
Doing it with Keylight
Keylight is the licensing layer that sits on top of Stripe. Stripe handles the payment; Keylight handles everything that happens immediately after — minting the license, signing the key, tracking activations, handling the webhook from Stripe, and providing the dashboard for customer support.
When a customer completes checkout, Stripe fires a payment_intent.succeeded (or checkout.session.completed) webhook. Keylight receives it, creates a signed Ed25519 lease, and delivers the key by email. Your app never needs a webhook handler.
The Swift SDK handles the client side:
import KeylightSDK
// Create the manager once at app startup
let licensing = try! Keylight.manager(
sdkKey: "sdk_live_...",
tenantId: "acme",
productId: "myapp",
keyPrefix: "ACME",
trustedPublicKeyBase64: "<your-public-key>",
trialDurationDays: 14,
branding: .init(appName: "My App", purchaseURL: URL(string: "https://acme.example.com/buy")!, supportEmail: "[email protected]", tintColor: .blue)
)
// At app launch — resolves cached lease, revalidates online if stale
await licensing.checkOnLaunch()
switch licensing.state {
case .licensed:
// Unlock the app
unlockFeatures()
case .trial(let daysLeft):
showTrialBanner(daysLeft: daysLeft)
case .expired:
showRenewalPrompt()
case .invalid:
// No valid license — show activation UI
promptForLicenseKey()
}
The SDK calls the local signature check first. If the cached lease is fresh enough, no network request is made. If a revalidation is due, it happens in the background after the app has already launched. From the user’s perspective, the app is always fast and always works.
Features like per-key device activation limits are baked into the lease payload. Each key carries an activationLimit field; the server tracks activations per device fingerprint. If a customer hits their limit, the activation request is rejected and the manager surfaces the error through activationError so you can show a deactivation prompt or an upgrade nudge.
The Stripe integration is native — Keylight connects directly to your Stripe account. You set your prices in Stripe, your checkout flow lives on Stripe-hosted pages or your own frontend using Stripe Elements, and Keylight receives the events. No re-platformed checkout, no new payment processor to vet.
Getting started
The typical setup takes under an hour. You create a Keylight account, connect your Stripe account, paste in your app’s webhook endpoint, and drop the Swift SDK into your project. The SDK gives you checkOnLaunch() for startup resolution and activate(key:) for user-entered keys; the dashboard gives you license lookup, activation reset, and revocation controls.
Keylight plans start at $19/month on the pricing page. The free tier lets you test the full flow with up to five licenses — enough to validate end to end before you ship.
The hardest part of licensing a direct-sold Mac app is not the cryptography — it is the operational surface that accumulates around it. Using a purpose-built licensing layer means you ship faster, operate with less infrastructure, and give your customers a proper experience from day one.
Frequently asked
Can I license a macOS app sold outside the App Store?+
Yes. A licensing layer issues signed keys your app verifies locally; Stripe handles the payment. No App Store involvement.
Does offline validation work for Mac apps?+
Yes. The app ships with a public key and verifies the signed license locally — no network call at launch.
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