You build a Mac app, it runs fine, you zip it up and send it to a friend. They double-click and macOS tells them the app is damaged and should be moved to the Trash. Nothing is damaged. The file is byte for byte what you sent.
That message is Gatekeeper, and it is the thing most developers discover late, usually the week they meant to launch. Here is what is actually happening, what it takes to hand someone a download that opens, and how to decide between shipping directly and shipping through the App Store.
Why it runs on your machine and nowhere else
By default, a local debug build gets an ad-hoc signature. That is a real signature in the narrow sense that the bundle is hashed and sealed, so the system can tell if the code changed after signing. What it does not carry is an identity. It says this app has not been modified. It does not say who made it.
That is enough on your own Mac, because you built the app there and nothing about it looks like it arrived from the outside. It is not enough anywhere else, because the copy that lands in someone's Downloads folder carries an extra piece of metadata that yours never had.
Quarantine and Gatekeeper, in plain terms
When a browser, mail client, or messaging app writes a file it received from off the machine, it attaches an extended attribute named com.apple.quarantine to that file. The tag means roughly: a person on this Mac did not create this, it came from somewhere else.
The first time anyone opens a quarantined app, macOS stops and inspects it. That inspection is Gatekeeper, and it is asking three things. Is this signed by a developer Apple can identify. Has the code been altered since it was signed. Has Apple already seen this exact build and found nothing malicious in it. An ad-hoc signed app fails the first question instantly, and the user gets a dead end instead of a warning they can reason about.
Two details cause most of the confusion. The quarantine tag is applied by the app doing the downloading, not by the system underneath it, so a build you copy over with scp, or pull out of a repository, often arrives with no tag at all. That is why "it worked when I tested it on the other Mac" is such a common false positive. And the tag is inherited: unzip a quarantined archive and the app inside comes out quarantined too.
The path that works: Developer ID, then notarization
Making a download that opens on a stranger's Mac takes two steps. They are separate things, and conflating them is where people lose a day.
- Developer ID signing: you join the Apple Developer Program, create a Developer ID Application certificate, and sign the app with it. Now the signature carries an identity that traces back to you. This normally means turning on the hardened runtime as well, which switches off a set of behaviors (loading unsigned libraries, injecting code, writable executable memory) that you have to deliberately opt back into with entitlements if you truly need them.
- Notarization: you upload the signed build to Apple's notary service. It runs an automated scan for malware and for signing mistakes, and if the build passes, Apple issues a ticket for it. This is not review. No person looks at your app, nobody comments on your interface, and it generally finishes in minutes rather than days.
Then staple the ticket to the app or the disk image you ship. Stapling attaches the result to the bundle so Gatekeeper can confirm it without a network round trip. Skip that step and your app still opens for most people, and fails for anyone offline or behind a restrictive network. That is a miserable bug to reproduce, because it never happens to you.
The first time through, all of this is a day of reading error messages that do not say what is wrong. After that it is a script you run on every build. Put it in your release process the first time you send a build to anyone, not the week you planned to ship.
The override is not a distribution plan
Users can get past Gatekeeper. For a long time that meant Control-clicking the app and choosing Open from the menu. More recent versions of macOS moved that path into System Settings, under Privacy and Security, where a blocked app shows up with a button to open it anyway.
It works, and it is the wrong thing to build on. You are teaching a person to walk past a security warning in order to run your software, which is exactly the habit you want your users not to have. It also does not scale. The dance repeats on some updates, your support inbox fills with screenshots of a dialog, and every one of those people had a moment where they wondered whether your app was safe.
The App Store is a different trade, not a better one
Shipping through the Mac App Store solves distribution and trust in one move, and charges you for it in capability.
- The sandbox is mandatory. Your app gets a container and has to request access to anything outside it through entitlements and user-initiated file pickers. For a document editor that is a mild inconvenience. For an app whose entire purpose is to read or control another app's window, it is usually a wall.
- Review is a human process. It takes real time, the outcome is a judgment call, and it repeats on every update, which changes how you plan releases.
- Trust and updates come included. No signing pipeline of your own, no update mechanism to write, no Gatekeeper conversation with your users, and a listing people already know how to buy from.
- Apple takes a cut and stands between you and the customer. You get aggregate numbers rather than a relationship, and refund and support policy is largely not yours.
How to decide
Start from what the app has to touch. If it needs Accessibility, screen recording, arbitrary filesystem paths, background helpers, or control over other applications, direct distribution is not a preference, it is the only door. If the app lives inside its own documents and your buyers are consumers who discover software by browsing, the store earns its cut.
The tools we build sit on the first side of that line. Voice is a menu bar dictation app distributed directly by us, and the others in the set lean on permissions that a sandboxed app does not get. That choice means we own signing, notarization, and updates. It is real work, and it is the cost of the app being able to do the job.
One practical note either way: do the signing work early. An app that has never been notarized is an app nobody outside your machine has genuinely used, and the bugs that only appear under the hardened runtime tend to surface at the worst possible moment. If you are weighing the two paths for something you are building, tell us what the app needs to touch and the answer usually falls out of that list.
The takeaway
Gatekeeper is not an obstacle between you and your users. It is the reason a stranger is willing to double-click a file you sent them. Ad hoc signing is for your own machine, Developer ID plus notarization is what makes a download openable, and the App Store is a different bargain that some apps simply cannot make. Pick deliberately, and pick before you have promised anyone a link.
Filed Under
Written by
Isaac Juracich
Full-stack engineer building production software for businesses that need it done right. Based in La Crosse, WI.
More about Isaac