For Mac developers selling outside the App Store

Everything between your Mac app and a paying customer.

Licence keys that survive a flight and a refund. Signed, notarised, auto-updating DMGs from one command. And 35 checks that stop the release which would have failed silently on a Mac you don't own.

One-time purchase · Unlimited apps · Kept current as Apple moves

Download FocusTimer.dmg (1.2 MB)

A working menu bar app, built and shipped by this kit — signed, notarised and stapled by ship.sh. No signup, no email. Verify it yourself:

spctl -a -vv -t install /Volumes/FocusTimer/FocusTimer.app

The full run from certificate to notarised DMG, in order.
The log is the tool's own output, word for word.

The App Store does five jobs.
Out here, they're yours.

Sell from your own site and you keep 100% minus payment fees, own your customers, and escape the sandbox. In exchange, Apple hands you this list and no tooling.

The jobHandled aloneWith the kit
Menu bar app shellNo Xcode template exists; tutorials are outdated, LLMs suggest deprecated APIsWorking skeleton, macOS 13+
NotarizationXcode notarises the app. The DMG you actually ship is a separate submission, and every release repeats the GUI by handOne script, both submissions, signature flags checked before the round-trip
DMG packaginghdiutil incantations; the DMG itself must be notarized too, which most guides skipSigned, notarized, stapled
Auto-updatesSparkle setup, EdDSA keys, appcast hosting, three silent failure modesWired, with delta updates
License keysVerification API, offline handling, refund handling, keychain storageGumroad flow, 14-day grace

What's in the box

  • The licence layerGumroad key verification, storage in the Keychain, 14-day offline grace, and defined behaviour for refunds and revoked keys. Everywhere else on this page a mistake costs you an afternoon. Here it costs revenue, and you hear about it months later from the customer it locked out.
  • The Hawser appUnlocks your kit, reads your Developer ID out of the keychain, takes the notary key from a file dialog, and writes the config for you. No text editor required to get shipping.
  • Config.xcconfigThe one file you edit. Name, bundle id, team, versions, update feed, product id. Everything follows it.
  • ship.shBuild → sign → notarize → staple → DMG. Verifies its own signature flags before wasting a round-trip to Apple, and refuses to ship what would silently fail.
  • appcast.shGenerates your signed update feed. Rejects an unsigned one, a failure Sparkle's own tooling lets through without a word.
  • Five guidesWritten from measured runs, not documentation folklore. The troubleshooting page is real incidents with exact fixes.
# you edit one file:
Config.xcconfig
ShipKit.xcodeproj
Sources/
  ExampleFeatureView  ← your app goes here
  SettingsView        launch-at-login, tabs
  UpdaterView         Sparkle wired
  License*            Gumroad + grace period
scripts/
  ship.sh             one command → DMG
  appcast.sh          signed update feed
docs/
  01-quickstart … 05-troubleshooting

You could build this yourself.
Here's what you'd be finding out.

Nothing here is proprietary. Every command is public, and the ten worst ones are written up on this site for free. What you'd be buying is knowing which ones matter before one of them costs you a release.

Building it yourself

23 Dead ends between a working app and a customer who can open it. We wrote each one down the day we hit it.
  • 10written up in full on this site, free: the ones that cost the most to find
  • 2notarization submissions rejected for problems that looked perfectly fine locally
  • 1trap we only found after shipping: our own release, cracked in three commands the next day

Starting from Hawser

61s Source to signed, notarised, stapled DMG. Warm run, measured across three cold installs.
  • 1file to configure: name, bundle id, team, versions, update feed
  • 1command to ship, with both notarization submissions included
  • 35points where the scripts stop and print the fix instead of a status code

Measured July 2026 on a real machine and a real Developer account. Not projected, not "up to". The long version is the ten traps, free and complete.

We fell in the holes so you don't

Three of the ten. Any one of these costs a lost afternoon, or worse, ships broken silently.

The default that expires your certificate

Apple's certificate page pre-selects "Previous Sub-CA". Accept it and your Developer ID dies in February 2027 no matter what the expiry says. The guide walks you past it; ship.sh's error text warns about it too.

The update feed that signs nothing

Add Sparkle after your first release and its own tool generates an unsigned feed with no warning. Updates then fail silently on every user's machine. appcast.sh verifies the signature and refuses to let it through.

The error that names nothing

errSecInternalComponent is codesign's way of saying "keychain permissions". It just never mentions keychains, or permissions. You get the one-line fix in the error message itself, when it happens, not after two hours of searching.

Read all ten, with the exact fix for each →

Building it once is the easy half.

Apple has changed the rules of this pipeline before, and macOS 27 is in beta right now. Every change arrives the same way: a release that worked last month stops working, and nothing tells you why.

Our scripts stay current because we ship our own apps through them. When Apple moves, it breaks our releases first. We find it, fix it, and you get the fix.

A pipeline you assembled yourself gets updated when a customer emails you to say your app won't open.

Fixes and improvements to v1 are free, delivered through your original download link.

One file to configure. One command to ship. Every trap already documented.

$99 one-time

  • Use in unlimited apps, commercial or free
  • No subscription, no per-app fees, no account
  • Full source: readable, commented, yours to modify
Get Hawser · $99

Requires Apple's own Developer Program membership ($99/year, paid to Apple). Everyone shipping Mac apps pays that, kit or not.

Questions, answered straight

What exactly do I get?
The Hawser app. Paste the licence key from your receipt and it unpacks your kit: an Xcode project (the menu bar skeleton), ship.sh and appcast.sh, and five guides. Then it walks you through the certificate and notary setup. Full readable source, no obfuscation. The key is checked once, when you unlock; your copy is stamped with your name and the app never phones home again.
What else do I need?
An Apple Developer Program membership ($99/year, paid to Apple, required for Developer ID signing no matter what tooling you use), Xcode 15 or later, and a Gumroad account only if you want license keys.
Which platforms and versions?
Swift + SwiftUI. Your app targets macOS 13 Ventura or later and builds universal (Apple Silicon + Intel) out of the box. Updates use Sparkle 2.
Can I use it in client work? In several apps?
Yes. Unlimited apps, commercial or free, including apps you build for clients. The only thing you can't do is resell or redistribute the kit itself.
Do I get updates to the kit?
Yes. Fixes and improvements to v1 are free and delivered through your original download link. We ship our own apps through these scripts, so when Apple moves the pipeline it breaks our releases before it reaches yours.
What doesn't it do?
No sandboxed / Mac App Store variant; this is the outside-the-store pipeline. Licensing is Gumroad only; no Paddle, Lemon Squeezy or Stripe. No CI templates: ship.sh runs on your machine, not in GitHub Actions. Swift and SwiftUI only, macOS 13+, no Objective-C skeleton and no iOS. And the licence check runs on the client, so it makes casual copying inconvenient rather than impossible. We say the same thing in the write-up.
Can I get a refund?
No. You receive the complete source the moment you buy, and source code can't be returned. That's the honest reason, and it's exactly why everything is laid out before you pay: the full box contents, measured numbers instead of promises, and this FAQ. If you're unsure, don't buy yet; the page isn't going anywhere.