Shipping a Safari Web Extension on macOS: Signing, Notarization & the .claude Folder Myth
- Safari
- macOS
- Browser Extensions
- Distribution
When I shipped NorthLab Folders — a browser extension that adds a real folder sidebar to claude.ai and chatgpt.com — the Chrome Web Store side was straightforward. You build a Manifest V3 extension, upload the zip, wait for review. Done. Safari was a different planet.
Here's what I learned about the Safari distribution path: wrapping, code-signing, notarization, direct DMG delivery, and the Gatekeeper trust dance that follows. And along the way, I'll clear up a confusion I kept bumping into while building this that has nothing to do with distribution — but everything to do with how Mac naming trips people up.
Safari Extensions Are Native Apps
This is the first thing that trips up anyone coming from Chrome's world. On macOS, a Safari web extension isn't a bare .crx or directory of files that the browser reads directly. It lives inside a native macOS application bundle. The browser extension is hosted by the app. The app is the distribution unit.
Apple provides tooling to scaffold this — you give it your existing extension source and it generates a Xcode project wrapping a native app shell around your web extension. The Manifest V3 extension code lives inside that app bundle. From that point on, you're in native Mac territory: you need a Developer ID certificate, you need to sign everything, and you need to notarize.
I already had a Manifest V3 extension working well across Chrome, Edge, Brave, Arc, and Opera. That part ported without meaningful changes — the same content scripts, the same background service worker, the same permissions model. The work was entirely in the distribution layer.
Signing and Notarizing: The Honest Version
The signing step attaches your Developer ID to every piece of the bundle — the app itself, any frameworks, the extension within it. If anything is missing a valid signature, the whole thing can fail notarization or fail at launch.
Notarization is Apple's automated scan. You upload the signed build to Apple's notarization service, it runs checks, and if it passes, you staple the resulting ticket to the DMG before distributing it. That staple is what lets Gatekeeper verify the build offline — without it, a user opening the DMG on an airplane would get a different experience than one with a network connection.
What I'll say honestly: the exact command sequence matters a lot, the tooling is finicky about the order of operations (sign before notarize, staple after notarize, never the reverse), and error messages from the notarization service are sometimes cryptic. There were several iteration cycles before I had a clean pipeline. But the conceptual model is simple: sign with your identity, let Apple audit it, stamp the result.
Why Not the Mac App Store?
The Mac App Store was the obvious alternative. Apple handles discovery, trust, and updates. But the tradeoffs didn't work for what I was building.
Safari web extensions on the App Store go through App Review — not just automated checks but human review of the extension's behavior. Content scripts that read page content, even for entirely local in-page purposes, can require additional justification. The extension reads conversation titles in-page to render the folder sidebar and generate exports, but never sends that content anywhere. Explaining that during review, iterating, and managing the timeline felt like the wrong bet for a solo indie project.
Direct distribution with a notarized DMG gives users the same Gatekeeper trust signal — "Apple checked this developer's signature" — without App Store latency. The privacy story is the same: NorthLab Folders is local-first by design. Folder structure and chat IDs live in the browser's local extension storage. Conversation content is only read in-page. There is no backend, no account, no analytics. The only outbound network call is the Pro license check (via Lemon Squeezy's API). A direct DMG fits that story cleanly.
What Users Actually Experience
After downloading and opening a notarized DMG, a user runs the app once. That's the step that registers the extension with Safari. Then they go to Safari's settings, find the Extensions tab, and enable NorthLab Folders explicitly.
That last step — manually enabling the extension in Safari's preferences — surprises some users. It's by design: Safari requires users to consciously opt in to each extension, even after it's been installed. From a privacy standpoint it's a reasonable default; from a UX standpoint it's a friction point you have to document clearly. I wrote a step-by-step guide on the product site covering exactly this flow for Mac users, because "I installed it, now what?" support questions were predictable.
The ~/.claude Confusion Worth Clearing Up
While building this I noticed a recurring pattern in forums and support threads: people finding a ~/.claude folder on their Mac and assuming it contains their Claude chat history. It doesn't. That folder is Claude Code's configuration directory — Anthropic's CLI tool for developers. It holds things like project memory files, settings, and hooks for the coding assistant. It has nothing to do with claude.ai chat sessions, which live server-side.
This is a useful example of how platform naming creates genuine confusion at scale. "Claude" as a brand spans several distinct products with different storage models: the web app (no local storage), Claude Desktop (connects to local tools via MCP but still no chat-history folder on disk), and Claude Code (a CLI that does write local config). Users conflate them because the name is shared. If you're building in this space — extensions, integrations, anything that touches Claude's surface area — expect to spend real time on disambiguation in your docs.
The folder extension I built is browser-local by nature, which sidesteps some of this. But the ~/.claude question still comes up: users wonder if the extension can somehow read their Claude Code config. It can't — a browser extension has no filesystem access. That boundary is enforced by the browser sandbox, not by anything I built.
The Verification Mindset
One thing I internalized shipping across Chrome, Edge, and Safari: each platform has its own verification loop, and you have to care about each one independently. The Chrome Web Store review is not a proxy for Safari notarization. A clean notarization is not a proxy for "it actually loads in Safari correctly." And "it works on my machine" is not a proxy for Gatekeeper behavior on a user's machine.
For Safari specifically: test on a clean macOS profile with Gatekeeper at default settings. Test the exact DMG you'll distribute, after stapling, not the build artifact from your machine. The difference between "works on dev machine" and "works for a first-time user who downloaded from your site" is exactly the set of steps you'll have skipped.
That's the distribution path. It's more work than the Chrome Web Store. It's also the only realistic path if you want to ship to Safari without App Store constraints — and for a local-first, privacy-first extension, direct distribution with a notarized DMG is the right call.