If you ship your Mac app outside the App Store, you give up StoreKit. There is no Product.purchase() waiting for you, no App Store sheet, no receipt validation. Apple's in-app purchase framework only works for apps distributed through Apple's store, and there is no independent-developer edition of it.
That does not mean you have to send people to a browser to buy your app. It just means you have to assemble the flow yourself, and most people assemble a worse one than they need to.
Why sell outside the store at all
The Mac App Store takes 30% of every sale, or 15% if you qualify for the Small Business Program. That's the number everyone quotes, but the developers I talk to rarely leave over the money alone. They leave because App Review gates every bug fix, because sandboxing rules out what their app actually does, or because they want to know who their customers are.
If you're weighing that trade-off, I wrote a longer piece on distributing a Mac app outside the App Store. This post is about the part that comes after you've decided: getting paid.
What you actually have to build
Selling a license yourself means owning four things that StoreKit handled for you:
- Payments. Taking a card, handling subscriptions, refunds, and failed renewals.
- Tax. VAT and sales tax in every jurisdiction you sell into.
- License keys. Issuing them, delivering them, and revoking them.
- Activation and validation. Deciding, on a Mac that might be offline, whether this copy is paid for.
Miss any one and you feel it. Skip tax and you eventually get a letter. Skip validation and your app shows up on a warez site with a keygen next to it.
The options, honestly
A merchant of record like Paddle or Lemon Squeezy takes payments and tax off your plate entirely, in exchange for a percentage that typically lands in the mid single digits plus a fixed fee per transaction. Cheaper than the App Store, more expensive than Stripe, and you get a reseller sitting between you and your customer.
Gumroad and similar are the fastest thing to set up and the most expensive to keep. Fine for a first hundred sales, painful at a thousand.
Stripe directly is the cheapest per transaction by a wide margin, and it leaves you holding items 3 and 4 on that list, plus tax unless you switch on Stripe's managed payments, which makes Stripe itself the merchant of record.
Rolling everything yourself is a weekend to prototype and a permanent part-time job to run. Key servers get DDoSed, signing keys leak, grace periods turn out to matter the first time your server has an outage while a customer is on a plane.
There's no universally right answer here. But notice that all four leave the same hole.
The hole: the browser handoff
Whatever you pick, the default integration looks like this. Your app shows a paywall with a Buy button. The button opens a browser. Your customer pays. A key arrives by email, eventually. They find the email, copy the key, switch back to your app, and paste it into a text field.
Count the exits. Any tab they already have open, any notification, any point where the email is slow or lands in spam. Every one of those steps loses a fraction of the people who had already decided to pay you. The ones who make it through are also the ones who write to you when the email doesn't arrive, so the flow costs you support time on top of conversions.
The App Store version of this is one sheet and a Touch ID prompt. That gap is the real cost of leaving the store, and it's much bigger than 30%.
What a good flow looks like instead
You can close that gap without StoreKit. The pieces:
- Checkout inside the app. An embedded web view presenting the payment page, so the purchase happens in a sheet rather than in Safari. Sandboxed apps need the outgoing-connections entitlement for this.
- Automatic activation. When payment clears, the app fetches the key and activates it itself. The customer never sees a license key unless they go looking for one.
- Reactive unlocking. Your gate is an observable license status, so the UI unlocks the moment activation succeeds instead of asking anyone to restart.
- Interrupted purchase recovery. This is the one people forget. If the app quits after the card is charged but before the license is stored, you need to resolve that session at next launch, and you need starting a new purchase to join the existing session rather than charging again. Get this wrong and you will double-charge someone.
- Offline validation. A signed token checked locally, with a grace period, so an outage on your side doesn't lock out paying customers.
- A browser escape hatch. Apple Pay requires the external browser, and some customers just prefer it. The app should activate the license either way.
None of that is exotic. It's just several days of work that has nothing to do with the app you actually wanted to build, and the failure modes only show up in production with real money attached.
Doing it with Amore
This is the flow Amore ships. Licensing gives you keys, activation, offline validation, and a customer portal on top of your own Stripe account. AmoreCheckout is the part that keeps the purchase inside your app.
The integration is one modifier:
import AmoreCheckout
let checkout = AmoreCheckout(licensing: licensing)
@State private var buying: Product?
Button("Buy Pro") { buying = product }
.amoreCheckout(item: $buying, checkout: checkout)
When payment completes, the key is fetched and activated on that Mac, and licensing.status flips to .valid, so anything you gate on it unlocks by itself. Recovery for an interrupted purchase is one call at launch:
await checkout.recoverPendingPurchase()
Starting checkout guards the same pending session, so a customer who buys again before recovery runs joins the existing purchase instead of paying twice.
The sheet is a thin layer over an observable object, so if you'd rather build your own paywall, your own success screen, or run checkout in the external browser, you drive the same object and get the same activation. The in-app purchases guide covers each of those, and Pomodoro is an open-source Mac app with the whole thing wired up, updates included.
On cost: payments run through your own Stripe account at Stripe's rates, and Amore's licensing adds 1.5% of monthly tracked revenue once you're over $1,000 in a month, nothing below that. If you want to be out of the tax business, Stripe Managed Payments makes Stripe the merchant of record and the integration doesn't change. The catch worth naming: this is Stripe-only, so if you're committed to a different reseller, it isn't for you.
The short version
StoreKit is off the table outside the App Store, but the thing StoreKit is actually good at, buying without leaving the app, is reproducible. Embedded checkout, automatic activation, and honest handling of interrupted purchases get you most of the way to a first-party feel while keeping your margin, your release schedule, and your customer list.
Get started with in-app purchases or read the licensing guide first if you haven't set up products yet.