Create your first Safari extension with Claude Code (Mac step-by-step tutorial)
Build a Safari Web Extension on macOS with Claude Code, from manifest and popup to Xcode wrapper, Safari Settings, and Payhook-ready Pro monetization with hosted Stripe checkout.
#claude-code#safari#macos#web-extension#tutorial
Safari extensions on Mac use Safari Web Extensions - WebExtension files (manifest.json, popup, service worker) wrapped in a minimal Xcode app so Safari can install them. Claude Code can generate both the web extension layer and the Xcode scaffolding when you describe the product clearly.
This tutorial builds Focus Tab for Safari (timed site blocking), then links to Payhook for Pro revenue. For a lighter no-code path, see Create a Safari extension without coding.
What you will build
Focus Tab for Safari - a Safari Web Extension that:
- Shows a popup with a 25-minute focus timer
- Blocks distracting domains during an active session
- Persists settings via extension storage APIs
- Runs inside a macOS app target you open in Xcode and enable in Safari Settings
Payment wiring is a separate pass: Monetize a browser extension without a payment backend applies to Safari Web Extensions too.
Prerequisites
| Requirement | Notes |
|---|---|
| Mac with macOS | Safari Web Extensions are built and tested on Mac |
| Xcode | Free from the Mac App Store; required for the wrapper app |
| Claude Code | Terminal CLI in your project folder |
| Apple ID | For local signing; Apple Developer Program for App Store distribution |
| Firefox or Chrome optional | Same WebExtension core can be reused across browsers |
Step 1 - Create a project folder
mkdir -p ~/projects/focus-tab-safari
cd ~/projects/focus-tab-safari
Step 2 - Add context with CLAUDE.md
# Focus Tab - Safari Web Extension (macOS)
- WebExtension layer: manifest_version 3, popup, service worker
- Xcode: Safari Web Extension App target with embedded extension resources
- Minimal permissions; explain each in README
- Test flow: build/run in Xcode → Safari → Settings → Extensions → enable
- Pro monetization will use Payhook hosted checkout (not in-popup cards)
- After web changes, remind me to rebuild in Xcode and reload in Safari
Step 3 - Start Claude Code and send the build prompt
claude
Paste this prompt (adjust names as needed):
Create a Safari Web Extension for macOS called "Focus Tab" in this folder.
WebExtension requirements (Manifest V3):
1. manifest.json with action default_popup popup.html, background service_worker background.js, permissions: storage, declarativeNetRequest as needed
2. popup.html + popup.js: 25-minute focus timer, Start/Stop, show remaining time
3. background.js: block twitter.com, x.com, facebook.com, instagram.com, reddit.com during an active focus session
4. Persist block list and session state in extension storage
5. icons/ with 16, 48, 128 placeholders
Xcode requirements:
6. Generate or document a Safari Web Extension App project structure that embeds the WebExtension files
7. README.md with exact steps for my macOS version: open in Xcode, select scheme, Run on My Mac, enable extension in Safari → Settings → Extensions
8. Plain JavaScript, no bundler for the extension scripts
Assume I am not a Swift developer - keep native code minimal and commented.
Claude Code may create a folder layout like:
focus-tab-safari/
├── CLAUDE.md
├── README.md
├── Focus Tab/ # Xcode project (names vary)
│ └── ...
└── Extension/ # or Resources/ - WebExtension root
├── manifest.json
├── background.js
├── popup.html
├── popup.js
└── icons/
If Claude only generates web files, follow up:
Add the minimal Xcode Safari Web Extension App wrapper so I can run this on my Mac and enable it in Safari Settings.
Step 4 - Open in Xcode and run on your Mac
Exact menu labels shift between Xcode versions; use the README Claude generated. Typical flow:
- Open the
.xcodeprojor.xcworkspacein Xcode - Select the Safari Web Extension app scheme (not a unit test target)
- Choose My Mac as the run destination
- Click Run (▶) - Xcode installs the containing app
- Open Safari → Settings → Extensions
- Enable Focus Tab and allow permissions on a test site
- Click the toolbar icon to open the popup
Paste Xcode or Safari errors back to Claude Code:
Xcode build failed with: [paste error]. Fix the Safari Web Extension project.
Step 5 - Test the extension
| Check | How |
|---|---|
| Extension appears in Safari Settings | Listed and toggle on |
| Popup opens | Toolbar icon on a normal page |
| Timer runs | Start session; UI updates |
| Blocking works | Visit a blocked domain during a session |
| Rebuild after web edits | Run again in Xcode; reload extension if needed |
Safari caches extension bundles. If changes do not show, disable and re-enable the extension in Settings or clean the build folder in Xcode (Product → Clean Build Folder).
Safari-specific issues
Code signing - Local testing uses your Apple ID team. For distribution, enroll in the Apple Developer Program.
API differences - Safari Web Extensions support most MV3 APIs but not every Chrome flag. Prompt: “Replace unsupported APIs with Safari-compatible alternatives and document limitations in README.”
App Store vs direct - Mac App Store distribution goes through App Review; hosted Payhook checkout keeps card data out of your popup (helpful for review narratives). See Publish a Safari extension to the Mac App Store.
Cross-browser reuse - The same manifest.json core often loads in Chrome and Firefox with small diffs. Ask Claude: “Extract shared WebExtension files and add a Firefox gecko id without breaking the Safari wrapper.”
Monetize next (Stripe + Payhook)
- Connect Stripe at dashboard.payhook.link
- Stripe account setup for extension creators
- Monetize a browser extension without a payment backend
Claude Code prompt for payments:
Integrate Payhook into this Safari Web Extension popup and background scripts.
Requirements:
- Payhook UpgradeButton in popup for paid tiers
- Entitlement checks gate Pro features - no custom license server
- Hosted Stripe checkout via unlock.payhook.link (no card fields in the popup)
- Document any Safari-specific content security or extension page constraints
Dashboard: https://dashboard.payhook.link
MCP: https://mcp.payhook.link