← All guides

Claude Code for Chrome Extension Development: Build AI-Powered Browser Tools

Use Claude Code to build Chrome extensions from scratch — manifest v3, content scripts, background service workers, popup UIs, and publishing to the.

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:


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:


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.

→ Get Power Prompts 300 — $29


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:

  1. Open chrome://extensions/
  2. Enable "Developer mode" (top right)
  3. Click "Load unpacked" and select your extension directory
  4. Pin the extension icon to the toolbar
  5. 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:

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


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.

→ Get Power Prompts 300 — $29

30-day money-back guarantee. Instant download.

Tools and references