Chrome extensions have an architecture that trips up developers who have not built one before. The mental model is different from a standard web app: there are three separate JavaScript contexts (background service worker, content script, popup) that cannot directly share state and communicate only through message passing.
Claude Code understands this architecture. Given a clear description of what your extension needs to do, it generates correctly structured manifest v3 extensions with appropriate context separation and message passing. The key is specifying which context handles which responsibility before prompting.
The most expensive Chrome extension bug is logic in the wrong context: trying to access the DOM from the background service worker, or trying to make cross-origin requests from a content script. Claude Code avoids these mistakes when your prompt specifies the context for each piece of functionality.
Chrome extension structure
The three execution contexts
Understanding these three contexts before prompting Claude Code is the difference between a working extension and an afternoon of debugging context errors.
-
Background service worker. The extension’s persistent background process (in manifest v3, this is a service worker rather than a persistent background page). Handles: cross-origin API calls, long-running operations, message routing between contexts,
chrome.storagereads and writes, alarm scheduling. -
Content script. JavaScript injected into web pages the user visits. Handles: reading and modifying page DOM, extracting page content, injecting UI elements into pages. Cannot make cross-origin requests, must pass data to the background service worker via
chrome.runtime.sendMessage. -
Popup. The UI that appears when the user clicks the extension icon. A standard HTML/CSS/JS web page. Handles: user settings, triggering actions, displaying results. Communicates with the background service worker via message passing.
The manifest v3 file
The manifest.json is the most important file in your extension. It declares permissions, registers your scripts, and defines the extension’s capabilities. Claude Code generates accurate manifest v3 files when you specify your extension’s requirements explicitly.
The build workflow
Step 1: Define your extension’s responsibilities by context
Before opening Claude Code, write down what each context does in your extension. A simple example for a page-summarization extension:
- Content script: extract the page’s main text content.
- Background service worker: call the AI API with the extracted text, store the result.
- Popup: display a “Summarize” button, show the summary result.
This three-line spec is enough to generate a structurally correct scaffold. Without it, Claude Code has to make assumptions about which context handles which responsibility, and those assumptions may be wrong for your use case.
Step 2: Scaffold the project structure
A strong scaffold prompt:
Create a Chrome extension with manifest v3.
The extension has three contexts: a background service worker that handles API calls
and storage, a content script that extracts page text, and a popup with a single button
and a results display.
Generate the manifest.json, background.js, content.js, popup.html, and popup.js files.
The extension name is [your name] and it requires permissions: activeTab, storage.
Review the generated manifest.json immediately. Verify that:
manifest_versionis3(not2).- The
backgroundkey usesservice_worker(notscripts). - Only the permissions you actually need are declared.
- The
content_scriptsmatchesarray is correct for your target pages.
Step 3: Implement content script logic
Content scripts run in the context of web pages. They can read and modify the DOM but have limited capabilities: no cross-origin requests, no direct access to extension APIs beyond a subset.
A clear content script prompt:
In content.js, implement a function that extracts the main article text from the current page.
Try article tags first, then main, then the body element.
Clean the text by removing script tags, nav elements, and ads.
Send the extracted text to the background service worker using
chrome.runtime.sendMessage({type: 'PAGE_TEXT', text: cleanedText}).
Generated content script DOM manipulation is generally accurate. Test it against your specific target pages, as generated selectors may not match every site’s structure.
Step 4: Implement background service worker logic
The background service worker is where cross-origin API calls live. Claude Code generates clean service worker message handlers:
In background.js, listen for messages of type PAGE_TEXT.
When received, call the OpenAI API at https://api.openai.com/v1/chat/completions with the
page text as the user message and 'Summarize this in three sentences' as the system prompt.
Store the result in chrome.storage.local with key lastSummary.
Reply to the popup with the summary.
Service worker memory is not persistent between events. Claude Code knows this and generates patterns that use chrome.storage for any state that needs to persist, which is correct.
Step 5: Build the popup UI
The popup is a standard HTML page with a 400px width constraint. Keep popup UI simple: a button, a loading indicator, and a result display area.
Complex UI belongs in an extension options page, not the popup.
A popup prompt:
In popup.html and popup.js, create a popup with a 'Summarize Page' button.
When clicked, send a SUMMARIZE message to the content script via chrome.tabs.sendMessage.
Show a loading spinner.
When the background service worker responds with the summary, display it in a scrollable text area.
Handle the error case where no summary is available.
Common extension patterns
Page scraping and data extraction
Content scripts are the right context for page scraping. Specify the target sites and the DOM structure of the data you want to extract. Claude Code generates content scripts that handle common scraping patterns (product prices, article text, table data) accurately for well-structured pages.
AI integration
AI API calls (OpenAI, Anthropic, Gemini) always go in the background service worker, not the content script. This keeps your API key out of the content script context (which is more accessible to page JavaScript) and handles CORS correctly.
Storage sync
chrome.storage.syncpersists data across a user’s Chrome instances. Use when you want cross-device persistence. Note thatsynchas smaller storage quotas.chrome.storage.localis local to the current browser. Claude Code useslocalby default, specifysyncin your prompt if you need cross-device persistence.
Permissions and security table
| Permission | What it allows | Security consideration |
|---|---|---|
activeTab | Access current tab URL and DOM on user action | Lowest risk; prefer over tabs when possible |
tabs | Access all tab URLs and properties | Broad access; use only if required |
storage | Read and write extension storage | Use for preferences and cached data only |
alarms | Schedule background events | Low risk; use for periodic tasks |
scripting | Inject scripts programmatically | Use activeTab instead when possible |
host_permissions | Cross-origin requests to specific domains | Minimize to only the domains you actually call |
<all_urls> | Access all URLs | Avoid; use specific host patterns instead |
identity | OAuth flows for Google sign-in | Review OAuth scope carefully |
nativeMessaging | Communicate with native apps | High risk; requires explicit user install |
Chrome Web Store review rejects extensions with excessive permissions. Declare only the permissions your extension actually uses.
Claude Code will often declare minimal permissions by default. Review the generated manifest.json to ensure nothing unnecessary is included. For a broader treatment of security practices in Claude Code projects, the security best practices guide covers this in depth.
General development best practices are also relevant when structuring the extension codebase.
Frequently asked questions
Should I use manifest v2 or v3 for a new extension?
Manifest v3 for all new extensions. Google has deprecated v2 and is phasing out support.
Chrome Web Store no longer accepts new manifest v2 extensions. Claude Code generates manifest v3 by default.
How does Claude Code handle extensions that need to work on specific sites?
Specify the target sites in your prompt using their exact domains.
Claude Code will generate the correct content_scripts matches array in the manifest and can write content scripts optimized for those sites’ DOM structure if you provide the relevant HTML structure.
Can Claude Code generate an extension with a React or Vue popup?
Yes. Specify your framework in the scaffold prompt and include a build step (vite or webpack).
Claude Code generates a build configuration that outputs the correct files to the extension directory. The popup.html references the bundled output, and the manifest.json remains unchanged.
Review the build output paths to ensure they match the manifest’s file references.
How do I handle API keys securely in a Chrome extension?
Never hardcode API keys in content scripts or popup code. Store API keys in chrome.storage.local (set via an options page) or use a backend proxy that holds the key server-side and the extension calls your proxy.
Claude Code knows this pattern and will generate proxy-based API call patterns when you specify that the key must not be exposed client-side.
Ready to build your Chrome extension?
Chrome extensions are a high-leverage build for teams that need a browser-native workflow tool. The architecture has specific rules, but once the three-context model is understood and specified in your prompts, Claude Code generates structurally correct, manifest v3-compliant extensions quickly.
The extensions that work cleanly are the ones where the developer specified the context for every piece of functionality before prompting. Content script for DOM. Service worker for API calls and storage. Popup for UI. No exceptions, and no context blurring.
Path one: do it yourself. Write a three-line context spec for your extension: what the content script does, what the service worker does, and what the popup does. Use that as the starting point for your scaffold prompt. You will have a working structure within an hour.
Path two: work with Phos AI Labs. If you want an experienced team building your extension from architecture through Chrome Web Store submission, Phos AI Labs runs structured build engagements. Thirty minutes, no deck. Start here.