Safari Web Extension Manifest V3 starter: web layer and Xcode wrapper
Minimal MV3 files for a Safari Web Extension on macOS, including manifest, service worker, popup, and how the Xcode app target embeds them before Payhook checkout.
#manifest-v3#safari#macos#web-extension#getting-started
Safari Web Extensions combine a standard WebExtension folder (Manifest V3) with a small macOS app built in Xcode. This post covers the web layer - the same foundation Payhook assumes before you add hosted checkout. For Chrome-only anatomy, see Chrome extension Manifest V3 starter.
What you will build
- WebExtension
manifest.json(MV3) background.jsservice workerpopup.html+popup.js- Understanding of how Xcode embeds these files in a Safari Web Extension App target
You still need Xcode to run the extension on your Mac; Safari does not load arbitrary unpacked folders like chrome://extensions.
WebExtension manifest.json
{
"manifest_version": 3,
"name": "My Safari Extension",
"version": "0.1.0",
"description": "Starter Safari Web Extension",
"action": {
"default_popup": "popup.html",
"default_title": "My Extension"
},
"background": {
"service_worker": "background.js"
},
"permissions": ["storage"]
}
Safari may require additional keys as APIs evolve - if Xcode or Safari warns at build time, paste the message into your AI assistant and update the manifest.
Typical project layout
MyExtensionApp/
├── MyExtensionApp.xcodeproj
├── MyExtensionApp/ # Containing macOS app (minimal Swift)
│ └── ...
└── Shared (Extension)/ # Name varies by Xcode template
├── manifest.json
├── background.js
├── popup.html
├── popup.js
└── icons/
Create the wrapper with File → New → Project → Safari Web Extension App in Xcode, or ask Claude Code to generate an equivalent structure (Safari with Claude Code tutorial).
Enable in Safari
- Build and Run the app target on My Mac in Xcode
- Open Safari → Settings → Extensions
- Enable your extension and grant site permissions
- Open the toolbar popup on a test page
After editing web files, rebuild in Xcode. Use Product → Clean Build Folder if Safari shows stale behavior.
Popup vs background
| Surface | Use for |
|---|---|
| Popup | Buttons, upgrade CTA, quick settings |
| Service worker | Entitlement checks, messaging, alarms |
Safari supports many MV3 APIs but not every Chrome experimental flag. Keep permissions minimal for App Review and user trust.
Payments (preview)
Do not embed card forms in the popup. Pro monetization uses hosted checkout:
Upgrade button in popup → unlock.payhook.link (Stripe) → entitlement check → Pro features unlock
Full wiring: Monetize a browser extension without a payment backend.
Next steps
- Create your first Safari extension with Claude Code
- Create a Safari extension without coding
- Publish a Safari extension to the Mac App Store
- Stripe Connect for extension builders
Related: Payhook docs, acme-extension sample.