Claude Code for Chrome Extension Development: Build AI-Powered Browser Tools
Claude Code can scaffold a working Chrome extension in minutes — generating the manifest, content scripts, popup HTML, background service worker, and icons from a single prompt. Chrome extensions follow a strict file structure governed by Manifest V3, and Claude Code understands this structure well enough to produce valid, immediately-loadable extensions. This guide covers the full development workflow: scaffolding, building features, testing, and publishing.
Why Use Claude Code for Chrome Extensions
Chrome extension development has a steep setup curve: Manifest V3 (MV3) changed how background scripts work (service workers vs persistent background pages), content security policies tightened, and the permissions model grew more granular. Claude Code handles this complexity by:
- Generating valid MV3 manifests with correct permission declarations
- Writing content scripts that don't violate CSP
- Structuring service workers that survive browser idle cycles
- Suggesting storage API patterns (not
localStorage) for extension data
Scaffolding a New Extension
Start Claude Code in an empty directory and describe what you want:
mkdir my-extension && cd my-extension
claude "Create a Chrome Manifest V3 extension that:
1. Adds a toolbar popup showing word count of the current page
2. Has a content script that highlights all numbers on the page when activated
3. Stores user preferences (highlight color) with chrome.storage.sync
4. Includes a minimal popup UI with a toggle and color picker"
Claude Code will generate the full file tree:
my-extension/
manifest.json
popup/
popup.html
popup.js
popup.css
content/
content.js
background/
service-worker.js
icons/
icon16.png (placeholder — replace before publishing)
icon48.png
icon128.png
The manifest.json Structure
Claude Code generates MV3-compliant manifests automatically:
{
"manifest_version": 3,
"name": "Page Analyzer",
"version": "1.0.0",
"description": "Word count and number highlighting for any page",
"permissions": [
"activeTab",
"storage",
"scripting"
],
"host_permissions": [
"<all_urls>"
],
"action": {
"default_popup": "popup/popup.html",
"default_title": "Page Analyzer",
"default_icon": {
"16": "icons/icon16.png",
"48": "icons/icon48.png",
"128": "icons/icon128.png"
}
},
"background": {
"service_worker": "background/service-worker.js",
"type": "module"
},
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content/content.js"],
"run_at": "document_idle"
}
]
}
Key MV3 differences from MV2 to be aware of:
background.service_workerreplacesbackground.scriptschrome.actionreplaceschrome.browserAction- Remote code execution is blocked — all JS must be bundled
chrome.scripting.executeScriptreplaceschrome.tabs.executeScript
Building Features with Claude Code
Content Script: Highlight Numbers
claude "In content/content.js, implement:
- Listen for messages from the popup
- When 'highlight' message received, wrap all numbers in the page text with <span class='num-highlight'>
- When 'clear' message received, remove all highlights
- Use TreeWalker to traverse text nodes efficiently"
Generated content script pattern:
// content/content.js
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (message.action === 'highlight') {
highlightNumbers(message.color);
sendResponse({ count: document.querySelectorAll('.num-highlight').length });
} else if (message.action === 'clear') {
clearHighlights();
sendResponse({ count: 0 });
}
return true; // Keep channel open for async response
});
function highlightNumbers(color = '#ffeb3b') {
const walker = document.createTreeWalker(
document.body,
NodeFilter.SHOW_TEXT,
null
);
const nodesToProcess = [];
while (walker.nextNode()) {
if (/\d/.test(walker.currentNode.nodeValue)) {
nodesToProcess.push(walker.currentNode);
}
}
nodesToProcess.forEach(node => {
const span = document.createElement('span');
span.innerHTML = node.nodeValue.replace(
/(\d+(?:[.,]\d+)*)/g,
`<span class="num-highlight" style="background:${color}">$1</span>`
);
node.parentNode.replaceChild(span, node);
});
}
function clearHighlights() {
document.querySelectorAll('.num-highlight').forEach(el => {
el.replaceWith(document.createTextNode(el.textContent));
});
// Normalize adjacent text nodes
document.body.normalize();
}
Service Worker Patterns
MV3 service workers terminate after ~30 seconds of inactivity. Claude Code knows how to work around this:
claude "In background/service-worker.js:
- Handle install event to set default storage values
- Listen for tab updates and badge text changes
- Keep the service worker alive with a chrome.alarms pattern"
// background/service-worker.js
chrome.runtime.onInstalled.addListener(async () => {
await chrome.storage.sync.set({
highlightColor: '#ffeb3b',
enabled: false
});
console.log('Extension installed, defaults set');
});
// Update badge on tab change
chrome.tabs.onActivated.addListener(async ({ tabId }) => {
const tab = await chrome.tabs.get(tabId);
if (tab.url?.startsWith('http')) {
chrome.action.setBadgeText({ text: '', tabId });
}
});
// Keep alive via alarms (fires every 25s)
chrome.alarms.create('keepAlive', { periodInMinutes: 0.4 });
chrome.alarms.onAlarm.addListener((alarm) => {
if (alarm.name === 'keepAlive') {
// Minimal work to prevent service worker termination during active use
}
});
Mid-Article Offer
Building AI-powered browser tools? The Power Prompts 300 ($29) includes JavaScript scaffolding prompts, debugging patterns, and CLAUDE.md templates for browser extension projects that Claude Code reads at the start of every session.
Testing the Extension Locally
claude "Create a test checklist for the extension and run it using Playwright to simulate extension loading"
For manual testing workflow:
- Open
chrome://extensions/ - Enable "Developer mode" (top right)
- Click "Load unpacked" and select your extension directory
- Pin the extension icon to the toolbar
- Open any page and click the extension icon
Claude Code can automate the reload cycle:
claude "Watch for file changes in the extension directory and auto-reload the extension using chrome.runtime.reload() via a native messaging host or a WebSocket dev server"
CLAUDE.md for Chrome Extension Projects
Create a CLAUDE.md in your extension directory so Claude Code understands the project context in every session (see the Claude Code Complete Guide for CLAUDE.md patterns):
# Page Analyzer Chrome Extension
## Manifest version: 3
## Chrome minimum version: 110+
## File structure
- manifest.json — entry point, do not change permissions without asking
- popup/ — toolbar popup UI (HTML/CSS/JS)
- content/ — injected into web pages
- background/ — service worker (stateless, may terminate)
- icons/ — PNG icons (16, 48, 128px)
## Rules
- No remote code, no eval(), no inline scripts in HTML
- Always use chrome.storage.sync for user prefs, never localStorage
- Content scripts must check if highlights already exist before re-running
- Service worker: assume state is lost between invocations
Publishing to the Chrome Web Store
claude "Generate a checklist for submitting this extension to the Chrome Web Store, including privacy policy requirements and screenshot dimensions"
Key requirements Claude Code will flag:
- Screenshots: 1280x800 or 640x400 PNG (at least 1)
- Icons: 128px PNG, no rounded corners (Chrome clips)
- Privacy policy URL required if any
host_permissionsare declared - Justification text required for sensitive permissions (
tabs,history, etc.) - Zip upload:
zip -r extension.zip . --exclude "*.git*"
Benchmark: In a 2025 analysis of Chrome Web Store submissions, extensions with a host_permissions scope of <all_urls> had a 3x longer review time than those with narrower patterns like *://*.example.com/*. Claude Code will suggest the minimum necessary permissions.
Related Guides
- Claude Code Complete Guide — Full reference for Claude Code CLI, CLAUDE.md, hooks, and advanced patterns
- Claude Code for Frontend: Next.js and React — Frontend-focused Claude Code workflows
- Claude API Cost Monitoring Guide — Track spend if the extension calls Claude API directly
- Claude Haiku vs Sonnet vs Opus — Model selection for extension-side API calls
Frequently Asked Questions
Can Claude Code generate a complete Chrome extension from one prompt?
Yes — a well-specified prompt produces a loadable extension with manifest, popup, content script, and service worker. The first generation usually requires minor fixes (CSP issues, missing icon files), which you can ask Claude Code to fix iteratively.
Does Manifest V3 require TypeScript?
No — MV3 works with plain JavaScript. Claude Code can add TypeScript with tsc compilation to dist/ if you prefer type safety. Bundlers like Vite and webpack have Chrome extension plugins (vite-plugin-web-extension, webpack-extension-reloader) that Claude Code can configure.
How do I call the Claude API from a Chrome extension?
Make API calls from the background service worker (not the content script) to keep your API key out of the page context. Store the key in chrome.storage.local (set during onboarding) and read it in the service worker before each API call. Never hardcode the key.
Why does my service worker keep stopping?
MV3 service workers are non-persistent by design — they terminate after ~30 seconds of inactivity. Use chrome.alarms to keep them alive during active user sessions. For operations that must persist (like a streaming response), use chrome.storage to checkpoint progress.
How do I debug content scripts?
Right-click the page, select "Inspect", and open the Console. Content script logs appear here. For the service worker, go to chrome://extensions/, click "Service Worker" under your extension, and a separate DevTools window opens with the worker's context.
What permissions are typically required?
Most extensions need activeTab (access to current tab), storage (user prefs), and scripting (inject content scripts programmatically). Avoid declaring broad host_permissions unless necessary — it triggers longer review times and user trust warnings.
Go Deeper
Power Prompts 300 — $29 — 300 tested prompts including browser extension scaffolding, JavaScript debugging, component generation, and CLAUDE.md templates for 5 project types including browser extensions.
30-day money-back guarantee. Instant download.