chrome-extension
samber/cc-skills
Guía completa para crear extensiones de Chrome con Manifest V3. Utiliza esta habilidad siempre que el usuario mencione «extensión de Chrome», «extensión de navegador», «manifest.json», «script de contenido», «service worker» (en el contexto de las extensiones), «ventana emergente», «panel lateral», «chrome.runtime», «chrome.tabs», «chrome.storage», «chrome.scripting», «script en segundo plano», «MV3», «Manifest V3» o cualquier API de extensiones de Chrome. También se debe activar cuando el usuario quiera inyectar scripts en páginas web, establecer comunicación entre la página y el fondo o eludir la CSP desde un contenido.
...Expandir todoAcerca de chrome-extension
Una guía completa para crear, depurar y publicar extensiones de Chrome con Manifest V3, estructurada como un documento de enrutamiento. Primero se lee el archivo principal para comprender la arquitectura y los puntos de decisión; a continuación, solo se carga el archivo de referencia pertinente e independiente para conocer los detalles de implementación. Los archivos de referencia abarcan la configuración y el control de versiones de manifest.json, el ciclo de vida de los service workers y la persistencia del estado, los scripts de contenido y la inyección en el entorno aislado frente a la inyección en el entorno principal, las capas de mensajería y RPC, las interfaces de usuario (ventanas emergentes, página de opciones, panel lateral, menús contextuales, comandos, notificaciones, omnibox, panel de herramientas de desarrollo), el uso y las cuotas de `chrome.storage`, la gestión de la red y la CSP, los permisos, los recursos accesibles desde la web, la configuración de la compilación de TypeScript, la publicación en la Chrome Web Store, los diagramas de flujo del contexto de ejecución y los errores comunes de depuración. Está dirigido a agentes de programación de IA y requiere Git y Node.js; las herramientas indicadas abarcan la edición de archivos y los comandos de Git, GitHub y npm.
La descripción general de la arquitectura explica que una extensión tiene hasta cinco contextos de ejecución que se comunican mediante el intercambio de mensajes: el service worker (en segundo plano, sin DOM, efímero, con acceso a todas las API chrome.* ), la ventana emergente, la página de opciones y el panel lateral (todos con DOM completo y API), y, en la propia página web, el script de contenido en un entorno aislado y un script principal en el contexto de la página. Los diagramas muestran que el script de contenido comparte el DOM, pero tiene su propio ámbito de JS y acceso a chrome.runtime y chrome.storage, al tiempo que está sujeto a la CSP solo para la red, mientras que el script del entorno principal tiene acceso completo a la página, pero no a las API chrome.*, y está totalmente sujeto a la CSP. Ambos se comunican mediante window.postMessage a través del DOM compartido.
Los patrones de comunicación se resumen en las siguientes tablas: chrome.runtime.sendMessage para solicitudes y respuestas puntuales desde cualquier contexto de extensión al service worker (el caso más habitual), chrome.tabs.sendMessage para enviar datos desde el service worker a una pestaña específica mediante el tabId, los puertos de chrome.runtime.connect para la transmisión bidireccional y el progreso (incluido el servicio worker a una ventana emergente), y window.postMessage para conectar entornos en la misma página. Dado que el service worker es efímero y no puede enviar datos directamente a las páginas de las extensiones, la guía orienta a los lectores hacia los puertos o hacia chrome.storage.onChanged, que se activa simultáneamente en todos los contextos, y remite a la referencia de contextos de ejecución para consultar diagramas de flujo más detallados y desgloses de capacidades y límites por contexto. La habilidad indica explícitamente que no debe utilizarse para preguntas específicas de marcos de trabajo.
Preguntas frecuentes
¿Qué versión del manifiesto de extensiones de Chrome abarca esta guía?
Manifiesto V3 (MV3). Abarca la configuración y modificación de `manifest.json`, la configuración de iconos y el control de versiones, junto con la arquitectura general de MV3, la gestión de mensajes y el proceso de publicación.
¿Cómo está organizada la skill?
Como un documento de enrutamiento. Primero se lee el archivo principal SKILL.md para conocer la arquitectura y los puntos de decisión; a continuación, se carga únicamente el archivo de referencia relevante e independiente (por ejemplo, service-worker.md, content-scripts.md o messaging-rpc.md) para conocer los detalles de implementación.
¿Qué contextos de ejecución tiene una extensión de Chrome según esta guía?
Hasta cinco contextos que se comunican mediante el intercambio de mensajes: el service worker (en segundo plano), la ventana emergente, la página de opciones y el panel lateral dentro del proceso de la extensión, además del script de contenido (entorno aislado) y el script principal de la página web.
¿Qué método de mensajería debo utilizar para una solicitud/respuesta típica?
chrome.runtime.sendMessage desde cualquier contexto de la extensión al service worker, que, según señala la guía, cubre aproximadamente el noventa por ciento de los casos. Para enviar mensajes a una pestaña específica, utiliza chrome.tabs.sendMessage, y para la transmisión bidireccional, utiliza los puertos de chrome.runtime.connect.
¿Cuáles son los requisitos previos para utilizar esta habilidad?
Está diseñada para Claude Code o agentes de programación de IA similares y requiere Git y Node (los metadatos incluyen Git, Node y npm). No está pensada para preguntas específicas sobre marcos de trabajo.
Todos los archivos
14archivosreferences/content-scripts.md12,5KBVerreferences/execution-contexts.md18,3KBVerreferences/messaging-rpc.md19,4KBVerreferences/permissions.md8,0KBVerreferences/service-worker.md 10,9KB Ver referencias/typescript-build.md 7,9KB Ver referencias/debugging-mistakes.md 9,2KB Ver referencias/manifest-v3.md 7,2KB Ver referencias/network-csp.md 9,9KB Ver referencias/publishing.md6,4KBVer referencias/storage.md9,0KBVer referencias/ui-surfaces.md9,7KBVer referencias/web-accessible-resources.md3,1KBVer SKILL.md16,0 KBVerThis 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:
┌──────────────────────────────────────────────────────────┐│ 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.mdContent 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.mdMessaging is the backbone. Every cross-context interaction uses chrome.runtime messaging. The #1 bug: forgetting to
return truefrom async message listeners. → Readreferences/messaging-rpc.mdPermissions determine CWS review speed. Broad host_permissions trigger manual review (weeks). activeTab + optional permissions = fast automated review. → Read
references/permissions.mdPopup 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
Define the manifest with minimum permissions. Start with
activeTab+scripting. → Readreferences/manifest-v3.mdSet up TypeScript and build tooling (or use CRXJS for Vite-based dev). → Read
references/typescript-build.mdImplement the service worker with all event listeners at the top level. → Read
references/service-worker.mdAdd content scripts if you need page interaction. → Read
references/content-scripts.mdBuild UI surfaces (popup, options, side panel) as needed. → Read
references/ui-surfaces.mdWire up messaging between all contexts. → Read
references/messaging-rpc.mdTest with DevTools, specifically test service worker termination. → Read
references/debugging-mistakes.mdPublish to Chrome Web Store. → Read
references/publishing.md
Workflow: adding a feature to an existing extension
- Identify which context the feature belongs to (see decision tree above).
- Read the relevant reference file(s) for that context.
- Check if new permissions are needed. Prefer optional_permissions for new capabilities. → Read
references/permissions.md - Update the manifest if adding new content scripts, UI surfaces, or permissions.
- Handle extension updates gracefully (content script orphaning). → Read
references/content-scripts.md(orphaning section)
Minimal manifest.json template
{ "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
Code patterns quick reference
Async message handler (the safe pattern)
// Wrap async handlers to avoid the return-true trapfunction asyncHandler( fn: (msg: any, sender: chrome.runtime.MessageSender) => Promise<any>,) { return ( message: any, sender: chrome.runtime.MessageSender, sendResponse: (r: any) => void, ) => { fn(message, sender) .then(sendResponse) .catch((e) => sendResponse({ __error: true, message: e.message })); return true; // literal true, not Promise<true> };}chrome.runtime.onMessage.addListener( asyncHandler(async (msg, sender) => { if (msg.type === "FETCH") { const res = await fetch(msg.url); return { ok: res.ok, data: await res.text() }; } }),);
CSP bypass relay (content script → service worker → API)
// content-script.tsasync function apiCall(endpoint: string, options?: RequestInit) { return chrome.runtime.sendMessage({ type: "API_RELAY", endpoint, options });}// background.tsconst ALLOWED_ENDPOINTS = ["https://api.example.com"];chrome.runtime.onMessage.addListener( asyncHandler(async (msg) => { if (msg.type !== "API_RELAY") return; if (!ALLOWED_ENDPOINTS.some((e) => msg.endpoint.startsWith(e))) { throw new Error("Blocked endpoint"); } const res = await fetch(msg.endpoint, msg.options); return { ok: res.ok, status: res.status, data: await res.text() }; }),);
Persist state across SW restarts
// Use chrome.storage.session for ephemeral statechrome.storage.session.setAccessLevel({ accessLevel: "TRUSTED_AND_UNTRUSTED_CONTEXTS",});async function getState<T>(key: string, fallback: T): Promise<T> { const result = await chrome.storage.session.get(key); return result[key] ?? fallback;}async function setState<T>(key: string, value: T): Promise<void> { await chrome.storage.session.set({ [key]: value });}
Orphaned content script detection
function isExtensionContextValid(): boolean { try { return !!chrome.runtime?.id; } catch { return false; }}// Before any chrome.runtime callif (!isExtensionContextValid()) { showRefreshBanner(); return;}
What NOT to do
- Do NOT use
eval(),new Function(), or load remote scripts. MV3 forbids it. - Do NOT use
setTimeout/setIntervalfor 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 truein async message listeners. - Do NOT use
localStorageorsessionStoragein service workers (they don't exist there). - Do NOT assume content scripts survive extension updates.
- Do NOT use
webRequestblocking (removed in MV3). UsedeclarativeNetRequest. - Do NOT use
chrome.extension.getBackgroundPage()(removed in MV3).
Todos los archivos
14 archivosInstalar chrome-extension
Descarga y descomprime los archivos de habilidades en tu directorio .claude/skills/.
Descargar ZIPClona el repositorio y copia los archivos de la habilidad a tu proyecto.
git clone https://github.com/samber/cc-skills/blob/main/skills/chrome-extension/SKILL.md # Copy SKILL.md to your .claude/skills/ directory
Copiar





Hogar
