Create your first Chrome extension with Claude Code (step-by-step tutorial)
Build a Manifest V3 Chrome extension from a plain-English prompt in Claude Code, load it in Chrome, iterate with the browser integration, and prepare to monetize with Stripe and Payhook.
#claude-code#chrome-extension#manifest-v3#ai-coding#tutorial
You do not need to memorize the Chrome Extensions API to ship a working extension. Claude Code is Anthropic’s agentic coding CLI: you describe what you want, it generates manifest.json, popups, service workers, and content scripts, and you load the folder in Chrome in minutes.
This is the first hands-on tutorial on the Payhook blog. We build a small Focus Tab extension (block distracting sites for a timed session), then point you at Stripe and Payhook when you are ready to charge for Pro features.
What you will build
Focus Tab - a Manifest V3 extension that:
- Shows a popup with a 25-minute focus timer and a start/stop button
- Blocks configured distracting domains while a session is active
- Persists your block list in
chrome.storage.sync
No payment code in this post. Monetization comes in Monetize a browser extension without a payment backend.
Prerequisites
| Requirement | Notes |
|---|---|
| Claude Code | Terminal CLI (claude --version should work) |
| Google Chrome | Needed for loading unpacked extensions; optional Claude in Chrome for claude --chrome testing |
| Empty project folder | e.g. ~/projects/focus-tab-extension |
| Claude account | Pro, Max, Team, or Enterprise for Claude Code |
Step 1 - Create a project folder
mkdir -p ~/projects/focus-tab-extension
cd ~/projects/focus-tab-extension
Keep all extension files in this directory. Claude Code will create and edit files here.
Step 2 - Add context with CLAUDE.md (recommended)
A short CLAUDE.md file tells Claude Code how to work in this repo on every session:
# Focus Tab - Chrome MV3 extension
- manifest_version: 3 only (no MV2)
- Use chrome.storage.sync for user settings
- Service worker: background.js (no persistent background page)
- Popup: popup.html + popup.js
- Keep permissions minimal; justify each permission in comments
- After changes, remind me to reload the extension at chrome://extensions
Create it yourself or ask Claude Code: “Add a CLAUDE.md for a Manifest V3 Chrome extension project.”
Step 3 - Start Claude Code and send the build prompt
From the project folder:
claude
Paste this prompt (edit the name or block list if you like):
Create a Chrome Manifest V3 extension called "Focus Tab" in this folder.
Requirements:
1. manifest.json with manifest_version 3, action default_popup popup.html, background service_worker background.js, permissions: storage, declarativeNetRequest (with host_permissions only if needed for blocking)
2. popup.html + popup.js: 25-minute focus timer UI, Start and Stop buttons, show remaining time
3. background.js: when a focus session is active, block navigation to twitter.com, x.com, facebook.com, instagram.com, reddit.com using declarativeNetRequest or equivalent MV3 approach
4. chrome.storage.sync: save block list and session state
5. icons: create simple placeholder PNGs in icons/ (16, 48, 128) or document that I must add them
6. README.md with steps to load unpacked in Chrome
Use plain JavaScript (no bundler). Make the extension loadable immediately in chrome://extensions with Developer mode.
Claude Code will scaffold files, run commands, and fix errors iteratively. First generations sometimes need a follow-up - that is normal.
Useful follow-up prompts
- “Fix manifest errors shown in chrome://extensions.”
- “declarativeNetRequest rules are not blocking - debug and fix.”
- “Add a content script that dims the page title when a session is active.”
Step 4 - Review the file structure
You should end up with something like:
focus-tab-extension/
├── CLAUDE.md
├── README.md
├── manifest.json
├── background.js
├── popup.html
├── popup.js
├── icons/
│ ├── icon16.png
│ ├── icon48.png
│ └── icon128.png
└── (optional) rules.json or scripts for declarativeNetRequest
Open manifest.json and confirm:
"manifest_version": 3"background": { "service_worker": "background.js" }"action": { "default_popup": "popup.html" }
Step 5 - Load the extension in Chrome
- Open
chrome://extensions - Enable Developer mode (top right)
- Click Load unpacked
- Select your project folder (
focus-tab-extension)
If Chrome shows errors, copy the message back into Claude Code:
Chrome reports this error when loading unpacked: [paste error here]. Fix the project.
After code changes, click Reload on the extension card in chrome://extensions.
Step 6 - Test in the browser (optional but powerful)
Claude Code can pair with the Claude in Chrome extension for a build → test loop:
- Install Claude in Chrome and sign in with the same account as Claude Code
- Start a session with browser tools:
claude --chrome
- Inside the session, run
/chrometo confirm the connection - Ask Claude to test your extension, for example:
Open chrome://extensions, confirm Focus Tab is loaded, then open the popup on a normal tab and describe what you see. If anything fails, suggest a code fix.
Official troubleshooting: Use Claude Code with Chrome.
Step 7 - Iterate until it feels shippable
| Check | How |
|---|---|
| Popup opens | Click the extension icon in the toolbar |
| Timer runs | Start a session; countdown updates |
| Blocking works | Visit a blocked site during an active session |
| State survives reload | Stop Chrome, reopen - settings still there |
When you are happy, zip the folder for backup or push to GitHub before adding payments.
Common issues
Missing icons - Chrome requires valid paths in manifest.json. Ask Claude Code to generate minimal PNGs or add your own brand assets under icons/.
Permission errors - MV3 is strict. Prefer declarativeNetRequest with a static rules file over broad <all_urls> host permissions unless you truly need them.
Service worker sleeps - Long timers may need chrome.alarms instead of setInterval in the service worker. Prompt: “Move the focus timer to chrome.alarms so it survives service worker sleep.”
Claude Code vs Claude chat - This tutorial uses the Code CLI in a project folder, not one-off chat snippets. The project on disk is what you load into Chrome.
Monetize next (Stripe + Payhook)
When Focus Tab should have a Pro tier (longer sessions, custom block lists, sync across devices), avoid building Stripe yourself:
- Connect Stripe in dashboard.payhook.link
- Follow Stripe Connect for extension builders
- Add the unlock flow with Monetize a browser extension without a payment backend
Copy this into Claude Code for the payment pass:
Integrate Payhook into this Chrome extension as the premium unlock and payment flow.
Requirements:
- Add the Payhook UpgradeButton in the extension popup for paid tiers
- Gate Pro features with Payhook entitlement checks (no custom license server)
- Open hosted Stripe checkout via unlock.payhook.link - do not build a custom Stripe backend
Use Payhook Agent when helpful:
- Agent endpoint: https://mcp.payhook.link/
- Payhook: https://dashboard.payhook.link
- Deliver: manifest permissions, background PayhookClient setup, popup UpgradeButton, and Pro feature gating wired to live payment state.
Next steps
- How to create a browser extension without coding - product roadmap for non-developers
- Chrome extension Manifest V3 starter - manual skeleton if you want to understand every file
- Publish a Chrome extension to the Chrome Web Store - launch checklist
- Create your first Firefox extension with Claude Code - same Focus Tab flow for AMO
- Create your first Safari extension with Claude Code - Xcode wrapper on Mac
- Monetize a browser extension without a payment backend - hosted checkout and Pro gating
- Sample extension on GitHub - reference implementation
Questions while building? Payhook and docs cover the payment path once your extension works in Chrome.