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

How to Launch a Mac App Outside the App Store

7 min read Nicolas Demanez — Founder

If you’ve already decided to skip the Mac App Store, the question shifts from should I? to what are the actual steps? This post is the playbook. If you’re still in the decision phase — weighing commission, discovery, and customer ownership — start with how to sell a Mac app outside the App Store and come back here when you’re ready to ship.

Below are the six steps to take a finished Mac app from your build folder to a launched product with paying customers.

Step 1: Sign and notarize with Developer ID

macOS will not cleanly open an app that isn’t signed by an identified developer and notarized by Apple. This is non-negotiable — without it, your customers see a “cannot be opened because the developer cannot be verified” warning, and most will close the dialog and ask for a refund.

You need three things:

  • An Apple Developer Program membership ($99/year).
  • A Developer ID Application certificate, downloaded from your developer account and installed in your keychain.
  • A notarization step in your release pipeline that uploads the signed build to Apple, waits for the green light, and staples the ticket to the app.

The signing and notarization steps are scriptable. A typical release script looks like:

# Sign with hardened runtime
codesign --deep --force --options runtime \
  --sign "Developer ID Application: Your Name (TEAMID)" \
  MyApp.app

# Submit to Apple's notary service and wait for result
xcrun notarytool submit MyApp.zip \
  --apple-id [email protected] \
  --team-id TEAMID \
  --password "@keychain:AC_PASSWORD" \
  --wait

# Staple the notarization ticket so the app validates offline
xcrun stapler staple MyApp.app

Run this once locally to confirm it works, then move it into CI so every release is signed and notarized automatically. From a Gatekeeper standpoint, a notarized Developer ID app and a Mac App Store app are equivalent — both open cleanly on a fresh Mac.

Step 2: Take payments with Stripe (or another processor)

With distribution handled, you need a way to take money. The recommended choice is Stripe — you become the legal seller, you own the customer record (email, purchase history, refund history), and fees are roughly 2.9% + $0.30 per transaction instead of the App Store’s 15–30%.

The minimum setup is a Stripe account, a product with at least one price, and either a Payment Link (zero code, paste into your site) or Stripe Checkout (a hosted checkout page you redirect to from a “Buy” button). Both produce the same outcome: when the payment succeeds, Stripe fires a webhook to your server.

That webhook is the source of truth for “a sale happened.” Everything downstream — issuing the license, sending the email, recording the customer — keys off it.

If you’d rather use a merchant of record so someone else handles VAT and sales tax, Paddle and Lemon Squeezy are the established options. They take a larger cut (typically 5–8% of revenue plus per-transaction fees), and they own the customer relationship, but they remove the tax-compliance burden. Gumroad and Polar are lighter alternatives in the same shape. Whichever you pick, the next step is the same — the processor’s webhook tells your licensing layer that a customer paid.

Step 3: Issue and validate license keys

This is the part Apple quietly handles for App Store apps through receipt validation, and the part most developers underestimate when they leave. You need three pieces:

  • A server-side flow that turns “customer paid” into “here’s a license key in their inbox.”
  • A client-side check that decides whether the running app is licensed, on trial, expired, or unactivated.
  • An offline path, so the app opens without a network round-trip every launch.

Keylight handles all three. You point your payment processor’s webhook at Keylight, it issues a key and sends the email, and the macOS SDK validates that key against a signed lease token cached on disk — no internet required after the first activation. Stripe is the default integration, but the webhook contract is generic; Paddle, Lemon Squeezy, Gumroad, and Polar all plug in the same way.

On the Mac side, the SDK surface is small:

import KeylightSDK

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
    )
)

await licensing.checkOnLaunch()

switch licensing.state {
case .licensed:
    unlockFeatures()
case .trial(let daysLeft):
    showTrialBanner(daysLeft: daysLeft)
case .expired:
    showRenewalPrompt()
case .invalid:
    promptForLicenseKey()
}

Create the manager, check on launch, switch on the state. If you want the deeper walkthrough — entitlements, activation UI, multi-device limits — see how to add license keys to a Swift macOS app and how offline license validation works.

Step 4: Ship updates with Sparkle

Outside the App Store, you also own update delivery. The standard tool is Sparkle — battle-tested, free, and used by most of the well-known direct-distributed Mac apps.

Sparkle works off an appcast, an RSS-like XML feed hosted on your site that lists available versions and download URLs. The app polls the feed on a schedule (or when the user clicks “Check for Updates”), downloads the new build, verifies an EdDSA signature to confirm it came from you, and offers to install it.

Two practical notes:

  • Generate an EdDSA key pair once with Sparkle’s generate_keys tool, ship the public key in your Info.plist, and sign every release with the private key. Without signing, anyone who can MITM your appcast URL can ship malware to your users.
  • Host the appcast and the DMG files on a URL you control (your own domain or a CDN). Don’t host them on a third-party file-share — those services change URLs and break updates years later.

This step matters more outside the App Store because there’s no Apple-managed update path. If you don’t ship an update mechanism, customers stay on whatever version they installed forever.

Step 5: Set up support, refunds, and customer comms

Customer support is the part of leaving the App Store that surprises first-time direct sellers. You need a published support email, a refund policy on your site, and a workflow for what happens when someone asks for a refund.

The mechanical piece — refund processed in Stripe, license revoked in your licensing system, customer’s app falls back to trial or unlicensed state — is covered in what happens after a refund in licensed software. Set this up before launch, not after the first refund request.

For comms, the email you send after purchase is doing real work: it’s the download link, the license key, the receipt, and the implicit “here’s how to reach me if something breaks.” Keep it short, plain-text-readable, and make sure the reply-to address is one you actually check.

A reasonable launch-day support setup is:

  • One support email (use a separate inbox or Helpscout/Front if volume justifies it).
  • A one-paragraph refund policy on your site (30 days is typical for indie apps).
  • An automated post-purchase email containing download URL, license key, and support address.
  • A simple FAQ page covering install, activation, and “how do I get my key again.”

Step 6: Launch day

The launch itself is the easy part if you’ve done the previous five steps. Concretely:

  • Landing page is live with a working “Buy” button that flows through to Checkout, a clear screenshot or video above the fold, and a download-the-trial link.
  • Trial path works end-to-end — install, open, see the trial banner, run the app for the trial window, hit the paywall, paste a key, unlock. Walk through it on a fresh Mac.
  • Stripe is in live mode, the webhook is pointed at production, and a real purchase issues a real key.
  • Announcement plan — Product Hunt for general reach, Hacker News if the app has a developer angle, X / Mastodon / Bluesky for your existing audience. Don’t try to launch on all of them on the same day; pick one as primary.

In the first 48 hours, watch four things: Stripe dashboard for charges, your licensing dashboard for activation rate (purchases that actually result in a successful activation — a gap here means the email or the activation UI is broken), support inbox volume, and Sparkle’s update check logs (you want to see them happening). Most launch-day bugs surface in one of those four signals.

That’s the playbook. Signing and notarization, payments through Stripe or your processor of choice, licensing through Keylight, updates through Sparkle, support set up before you need it, and a tight launch-day checklist. None of the individual steps are hard. The work is in not skipping any of them.

If there’s a piece of this you’d like covered in more depth — Sparkle, refund flows, the Stripe webhook plumbing — send us your feedback and we’ll prioritize it.

Frequently asked

Do I need an Apple Developer account to launch outside the App Store?+

Yes. The $99/year Apple Developer Program membership is required for the Developer ID Application certificate and for submitting builds to the notary service. Without it, macOS Gatekeeper will refuse to open your app cleanly.

Can I launch the same app on the App Store and outside?+

Yes, and many indie developers do. You typically maintain two builds from one codebase — one with StoreKit and Apple receipt validation, one with your own license-key system. The shared business logic stays identical.

How do customers actually download the app?+

Most direct sellers host a signed DMG on their own site or a CDN. The post-purchase email contains both the download link and the license key, so the customer downloads, drags into Applications, opens, and pastes the key once.

Do I need to use Stripe specifically?+

No. Stripe is the most common choice because you own the customer relationship and fees are low, but Paddle, Lemon Squeezy, Gumroad, and Polar all work. Your licensing layer should integrate with whatever processor you pick via webhook.

Ready to ship?

Create your account and start licensing your apps in under a minute. Free forever tier included.

Start Free