chrome-extension
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
By samber · 2,061 installs
npx skills add samber/cc-skills --skill chrome-extension
Source repository · Upstream listing
Chrome Extension Development (Manifest V3)
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
references/content scripts.md Injecting code into pages, isolated/main world, dynamic injection, SPA handling, orphaning
references/messaging rpc.md Communication between any contexts, typed protocols, RPC layer, async handler patterns
references/ui surfaces.md Popup, options page, side panel, context menus, commands, notifications, omnibox, devtools panel
references/storage.md chrome.storage (local/sync/session), quotas, reactive patterns, framework hooks
references/network csp.md HTTP requests from content scripts, CSP bypass relay, declarativeNetRequest, offscreen docs, CORS
references/permissions.md Required/optional permissions, host permissions, activeTab, runtime request flow
references/web accessible resources.md Exposing extension files to web pages, security implications
references/typescript build.md TypeScript setup, project structure, build tools comparison, bundling
references/publishing.md 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:
Communication flows (labeled channels)
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
1. 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
2. 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
3. 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
4. Permissions determine CWS review speed. Broad host permissions trigger manual review (weeks). activeTab + optional permissions = fast automated review. → Read references/permissions.md
5. 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"
→ Three layer bridge: page (window.postMessage) → content script → service worker → Read references/messaging rpc.md
"I need to understand what each context can and cannot do"
→ Read references/execution contexts.md — per context cards listing chrome.\ access, DOM, network, storage, lifetime, hard limits, and practical workarounds.
"I need periodic background tasks"
→ chrome.alarms (minimum 30s interval). NOT setTimeout. → Read references/service worker.md
"I need DOM APIs in the background" (DOMParser, Canvas, Audio)
→ Offscreen document. One per extension, only chrome.runtime available. → Read references/network csp.md
"I need to authenticate with OAuth"
→ chrome.identity.launchWebAuthFlow() or chrome.identity.getAuthToken() (Google only) → Read references/service worker.md (identity section)
Workflow: new extension from scratch
1. Define the manifest with minimum permissions. Start with activeTab + scripting . → Read references/manifest v3.md
2. Set up TypeScript and build tooling (or use CRXJS for Vite based dev). → Read references/typescript build.md
3. Implement the service worker with all event listeners at the top level. → Read references/service worker.md
4. Add content scripts if you need page interaction. → Read references/content scripts.md
5. Build UI surfaces (popup, options, side panel) as needed. → Read references/ui surfaces.md
6. Wire up messaging between all contexts. → Read references/messaging rpc.md
7. Test with DevTools , specifically test service worker termination. → Read references/debugging mistakes.md
8. Publish to Chrome Web Store. → Read references/publishing.md
Workflow: adding a feature to an existing extension
1. Identify which context the feature belongs to (see decision tree above).
2. Read the relevant reference file(s) for that context.
3. Check if new permissions are needed. Prefer optional permissions for new capabilities. → Read references/permissions.md
4. Update the manifest if adding new content scripts, UI surfaces, or permissions.
5. Handle extension updates gracefully (content script orphaning). → Read references/content scripts.md (orphaning section)
Minimal manifest.json template
→ For the full manifest reference with all fields: references/manifest v3.md
Code patterns quick reference
Async message handler (the safe pattern)
CSP bypass relay (content script → service worker → API)
Persist state across SW restarts
Orphaned content script detection
What NOT to do
Do NOT use eval() , new Function() , or load remote scripts. MV3 forbids it.
Do NOT use setTimeout / setInterval for anything 5s in service workers.
Do NOT register event listeners inside callbacks or async functions.
Do NOT use <all urls host permission unless absolutely necessary.
Do NOT rely on DevTools keeping the service worker alive during testing.
Do NOT forget return true in async message listeners.
Do NOT use localStorage or sessionStorage in service workers (they don't exist there).
Do NOT assume content scripts survive extension updates.
Do NOT use webRequest blocking (removed in MV3). Use declarativeNetRequest .
Do NOT use chrome.extension.getBackgroundPage() (removed in MV3).