Build Chrome extensions with Manifest V3. Use this skill whenever the user mentions Chrome extension, browser extension, manifest.json, content script, service worker (in extension context), popup, side panel, chrome.runtime, chrome.tabs, chrome.storage, chrome.scripting, or any Chrome extension API. Also trigger when the user wants to inject scripts into web pages, communicate between page and background, bypass CSP from a content script, build an RPC layer over chrome messaging, or publish to the Chrome Web Store. Covers both new extension projects and adding features to existing ones. Do NOT use for CRXJS/Vite-based builds with HMR — use samber/cc-skills@crxjs instead.
Instalar com Codex ou Claude Copie este prompt, cole no Codex, Claude ou outro assistente e deixe que ele revise a página da skill e instale para você.
Um comando direto ignora o prompt de revisão. Verifique a origem antes de executá-lo.
Instruções da origem · Visualização somente leitura
name
chrome-extension
description
Build Chrome extensions with Manifest V3. Use this skill whenever the user mentions Chrome extension, browser extension, manifest.json, content script, service worker (in extension context), popup, side panel, chrome.runtime, chrome.tabs, chrome.storage, chrome.scripting, or any Chrome extension API. Also trigger when the user wants to inject scripts into web pages, communicate between page and background, bypass CSP from a content script, build an RPC layer over chrome messaging, or publish to the Chrome Web Store. Covers both new extension projects and adding features to existing ones. Do NOT use for CRXJS/Vite-based builds with HMR — use samber/cc-skills@crxjs instead.
user-invocable
true
license
MIT
compatibility
Designed for Claude Code, Codex or similar harness. Requires git, node.
This skill covers everything needed to build, debug, and publish Chrome extensions with MV3. It is organized as a routing document: read this file first to understand the architecture and decision points, then load the relevant reference file for implementation details.
Reference files
Read only the reference files relevant to the current task. Each file is self-contained.
File
When to read
references/manifest-v3.md
Setting up or modifying manifest.json, configuring icons, versioning
references/service-worker.md
Background logic, lifecycle, state persistence, alarms, events
Chrome Web Store submission, review process, rejection reasons, updates, privacy policy
references/execution-contexts.md
Communication flow diagrams, per-context capabilities/limits, choosing the right messaging method
references/debugging-mistakes.md
DevTools for extensions, testing SW termination, common gotchas, error patterns
Architecture overview
A Chrome extension has up to 5 execution contexts that communicate via message passing:
┌──────────────────────────────────────────────────────────┐
│ Extension Process │
│ ┌─────────────────┐ ┌───────┐ ┌─────────┐ ┌──────┐ │
│ │ Service Worker │ │ Popup │ │ Options │ │ Side │ │
│ │ (background) │ │ │ │ Page │ │Panel │ │
│ │ - No DOM │ │ Full │ │ Full │ │ Full │ │
│ │ - Ephemeral │ │ DOM │ │ DOM │ │ DOM │ │
│ │ - All chrome.* │ │ All │ │ All │ │ All │ │
│ │ APIs │ │ APIs │ │ APIs │ │ APIs │ │
│ └────────┬─────────┘ └───┬───┘ └────┬────┘ └──┬───┘ │
│ │ chrome.runtime.sendMessage / connect │ │
└───────────┼────────────────┼───────────┼──────────┼──────┘
│ │ │ │
chrome.tabs.sendMessage │ │ │
│ │ │ │
┌───────────┼────────────────┼───────────┼──────────┼──────┐
│ Web Page ▼ │
│ ┌──────────────────┐ ┌──────────────────┐ │
│ │ Content Script │ │ Main World Script │ │
│ │ (isolated world) │◄──►│ (page context) │ │
│ │ - Shared DOM │ │ - Shared DOM │ │
│ │ - Own JS scope │ │ - Page JS scope │ │
│ │ - chrome.runtime │ │ - No chrome.* API │ │
│ │ - chrome.storage │ │ - Full page access│ │
│ │ - Subject to CSP │ │ - Subject to CSP │ │
│ │ (network only) │ │ (fully) │ │
│ └──────────────────┘ └──────────────────┘ │
│ ▲ window.postMessage │
│ │ (through shared DOM) │
└──────────────────────────────────────────────────────────┘
Communication flows (labeled channels)
┌───────────────────────────────────────────────────────────────────────────┐
│ Extension Process │
│ │
│ ┌─────────────────┐ chrome.runtime ┌───────┐ ┌─────────┐ ┌──────┐ │
│ │ Service Worker │◄─.sendMessage()──│ Popup │ │ Options │ │ Side │ │
│ │ (background) │◄─.connect()──────│ │ │ Page │ │Panel │ │
│ │ │ └───────┘ └─────────┘ └──────┘ │
│ │ - No DOM │ ┌────────────────────────────────────────────┐ │
│ │ - Ephemeral 30s │ │ SW cannot push to these pages. │ │
│ │ - All chrome.* │ │ Use: ports (.connect) or storage.onChanged │ │
│ └────────┬─────────┘ └────────────────────────────────────────────┘ │
│ │ │
│ chrome.storage.onChanged ◄── fires across ALL contexts simultaneously │
│ │
└───────────┼──────────────────────────────────────────────────────────────┘
│ chrome.tabs.sendMessage(tabId, ...) [SW must know tabId]
│
┌───────────┼──────────────────────────────────────────────────────────────┐
│ Web Page ▼ │
│ ┌──────────────────┐ window.postMessage ┌──────────────────┐ │
│ │ Content Script │◄───────────────────►│ Main World Script │ │
│ │ (isolated world) │ Custom DOM events │ (page context) │ │
│ │ │ │ │ │
│ │ chrome.runtime ───┼── to/from SW │ No chrome.* APIs │ │
│ │ chrome.storage │ │ Full page JS │ │
│ │ Shared DOM │ │ Shared DOM │ │
│ │ Page CSP (network)│ │ Page CSP (full) │ │
│ └──────────────────┘ └──────────────────┘ │
└──────────────────────────────────────────────────────────────────────────┘
For detailed flow diagrams (three-layer bridge, cross-extension, storage broadcast) and a per-context breakdown of permissions, limits, and workarounds: → Read references/execution-contexts.md
Communication methods at a glance
Method
Direction
Best for
chrome.runtime.sendMessage
Any ext context → SW
One-shot request/response (90% of cases)
chrome.tabs.sendMessage
SW → content script (by tabId)
Pushing data to a specific tab
chrome.runtime.connect (Port)
Bidirectional
Streaming, progress, SW ↔ popup
window.postMessage
Between worlds on same page
Page JS ↔ content script bridge
chrome.storage.onChanged
Broadcast to all contexts
Settings sync, no messaging needed
→ Full matrix with limits and edge cases: references/execution-contexts.md → Implementation patterns, typed protocols, RPC layer: references/messaging-rpc.md
Key architectural rules
Service worker is ephemeral. It terminates after 30s of inactivity. All state must be persisted to chrome.storage. All event listeners must be registered synchronously at the top level. Never use setTimeout/setInterval for anything beyond a few seconds. → Read references/service-worker.md
Content scripts run in the page's origin. Network requests from content scripts are subject to the page's CSP and CORS. To bypass, relay through the service worker. → Read references/network-csp.md
Messaging is the backbone. Every cross-context interaction uses chrome.runtime messaging. The #1 bug: forgetting to return true from async message listeners. → Read references/messaging-rpc.md
Popup is destroyed on blur. Side panel persists. Choose based on interaction duration. → Read references/ui-surfaces.md
Decision tree: which context handles what?
"I need to run code when the user visits a page"
→ Content script. Static (manifest) for known URL patterns, dynamic (chrome.scripting) for user-triggered injection. Default to isolated world unless you need page JS access. → Read references/content-scripts.md
"I need to make an HTTP request to my API"
From popup/options/side panel: direct fetch() works (extension origin, no CSP issues)
From content script on a page with restrictive CSP: relay through service worker
From service worker: direct fetch() works (requires host_permissions for the target domain) → Read references/network-csp.md
"I need to store user settings"
Settings that sync across devices: chrome.storage.sync (100KB limit)
Large data or caches: chrome.storage.local (10MB, or unlimited with permission)
Ephemeral state surviving SW restarts: chrome.storage.session → Read references/storage.md
"I need to modify HTTP headers or block requests"
→ declarativeNetRequest (NOT webRequest, which lost blocking in MV3) → Read references/network-csp.md
"I need the page's JavaScript to talk to my extension"
{"manifest_version":3,"name":"My Extension","version":"1.0.0","description":"What it does in one sentence","permissions":["storage","activeTab","scripting"],"action":{"default_popup":"popup.html","default_icon":{"16":"icons/icon16.png","48":"icons/icon48.png","128":"icons/icon128.png"}},"background":{"service_worker":"background.js","type":"module"},"icons":{"16":"icons/icon16.png","48":"icons/icon48.png","128":"icons/icon128.png"}}
→ For the full manifest reference with all fields: references/manifest-v3.md