Browser extensions · Updated

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

RequirementNotes
Claude CodeTerminal CLI (claude --version should work)
Google ChromeNeeded for loading unpacked extensions; optional Claude in Chrome for claude --chrome testing
Empty project foldere.g. ~/projects/focus-tab-extension
Claude accountPro, 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.

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

  1. Open chrome://extensions
  2. Enable Developer mode (top right)
  3. Click Load unpacked
  4. 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:

  1. Install Claude in Chrome and sign in with the same account as Claude Code
  2. Start a session with browser tools:
claude --chrome
  1. Inside the session, run /chrome to confirm the connection
  2. 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

CheckHow
Popup opensClick the extension icon in the toolbar
Timer runsStart a session; countdown updates
Blocking worksVisit a blocked site during an active session
State survives reloadStop 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:

  1. Connect Stripe in dashboard.payhook.link
  2. Follow Stripe Connect for extension builders
  3. 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

Questions while building? Payhook and @payhook/extension cover the payment path once your extension works in Chrome.