← Back to Skills Marketplace
samber

Chrome Extension

by Samuel Berthe · GitHub ↗ · v1.0.2 · MIT-0
cross-platform ✓ Security Clean
252
Downloads
0
Stars
1
Active Installs
2
Versions
Install in OpenClaw
/install chrome-extension
Description
Comprehensive guide for building Chrome extensions with Manifest V3. Use this skill whenever the user mentions Chrome extension, browser extension, manifest....
README (SKILL.md)

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:

┌──────────────────────────────────────────────────────────┐
│ 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

  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

{
  "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 trap
function asyncHandler(
  fn: (msg: any, sender: chrome.runtime.MessageSender) => Promise\x3Cany>,
) {
  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\x3Ctrue>
  };
}

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.ts
async function apiCall(endpoint: string, options?: RequestInit) {
  return chrome.runtime.sendMessage({ type: "API_RELAY", endpoint, options });
}

// background.ts
const 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 state
chrome.storage.session.setAccessLevel({
  accessLevel: "TRUSTED_AND_UNTRUSTED_CONTEXTS",
});

async function getState\x3CT>(key: string, fallback: T): Promise\x3CT> {
  const result = await chrome.storage.session.get(key);
  return result[key] ?? fallback;
}
async function setState\x3CT>(key: string, value: T): Promise\x3Cvoid> {
  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 call
if (!isExtensionContextValid()) {
  showRefreshBanner();
  return;
}

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 \x3Call_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).
Usage Guidance
This is a thorough, internally consistent MV3 extension developer guide — suitable if you want help building or debugging extensions. Before using examples verbatim, be aware the references describe powerful, potentially dangerous techniques (CSP-relay patterns, removing/modifying CSP via declarativeNetRequest, dynamic rules, relaying Authorization headers, persistent dynamic content script registration). Those are legitimate for some extension use-cases but increase attack surface and may violate Chrome Web Store policies if misused. Recommendations: (1) review and restrict any allowlists (ALLOWED_ORIGINS) before enabling relays; (2) avoid removing CSP headers broadly — scope any declarativeNetRequest modifications narrowly and document intent; (3) use optional_host_permissions and least-privilege host patterns; (4) treat the code samples as starting points to be audited, tested, and hardened; (5) don't copy secrets into content scripts or page-injected code. If you need higher assurance, request a review of any produced manifest or service-worker code before publishing.
Capability Analysis
Type: OpenClaw Skill Name: chrome-extension Version: 1.0.2 The `chrome-extension` skill bundle is a comprehensive educational resource for building Chrome extensions using Manifest V3. It provides detailed reference files (`references/*.md`) and architectural guidance in `SKILL.md`. The code snippets demonstrate standard patterns for messaging, storage, and UI development. No malicious intent, data exfiltration, or harmful prompt injections were identified; the bundle is purely technical documentation designed to assist developers.
Capability Tags
cryptorequires-oauth-token
Capability Assessment
Purpose & Capability
Name/description (Chrome extension MV3 guide) align with the contents: many detailed reference files about manifest, service worker, content scripts, messaging, CSP/relays, publishing, etc. Declared required binaries (git, node, npm) make sense for a coding agent creating or building extensions.
Instruction Scope
SKILL.md is a routing/guide document and the referenced files contain step-by-step patterns. Several references explicitly cover techniques with strong security implications: relay patterns to bypass page CSP (service-worker relay), use of declarativeNetRequest to remove/modify response headers (including CSP), dynamic registration of persistent content scripts, and examples passing Authorization headers via relay. Those techniques are legitimate for extension development but are powerful and must be used with strict allowlists and review; the skill documents them directly rather than restricting or warning strongly.
Install Mechanism
Instruction-only (no install spec, no downloads, no code files that execute on the host). Low-risk from installation perspective — nothing is written or fetched at install time.
Credentials
No environment variables, no credentials, no config paths requested. Allowed tools (git, npm) are reasonable for developing/building extensions. There are no unrelated credentials or secrets requested.
Persistence & Privilege
always:false and user-invocable:true (normal). The skill does not request to modify other skills or system-wide settings. It documents extension behaviors that affect browser-wide state (declarativeNetRequest rules, host_permissions) — which is expected for extension development — but it does not itself request persistent platform privileges.
How to Use
  1. Make sure OpenClaw is installed (local or Docker)
  2. Run the install command in chat: /install chrome-extension
  3. After installation, invoke the skill by name or use /chrome-extension
  4. Provide required inputs per the skill's parameter spec and get structured output
Version History
v1.0.2
Version 1.0.2 - Updated metadata version to 1.0.2. - Added AskUserQuestion to allowed tools. - Minor formatting fixes in the reference table and documentation. - No functional or structural changes to the skill’s content or routing logic.
v1.0.0
- Initial release of the "chrome-extension" skill. - Provides a comprehensive guide for building Chrome extensions with Manifest V3. - Includes coverage of all Chrome extension APIs, injection, messaging, CSP bypass, and publishing. - Organized reference files for quick access to implementation details per feature (manifest, service worker, UI surfaces, messaging, storage, permissions, etc.). - Contains architectural overviews and communication flow diagrams for extension contexts. - Designed for both new and existing extension projects, with compatibility for Claude Code or similar coding agents.
Metadata
Slug chrome-extension
Version 1.0.2
License MIT-0
All-time Installs 1
Active Installs 1
Total Versions 2
Frequently Asked Questions

What is Chrome Extension?

Comprehensive guide for building Chrome extensions with Manifest V3. Use this skill whenever the user mentions Chrome extension, browser extension, manifest.... It is an AI Agent Skill for Claude Code / OpenClaw, with 252 downloads so far.

How do I install Chrome Extension?

Run "/install chrome-extension" in the OpenClaw or Claude Code chat to install it in one step — no extra setup required.

Is Chrome Extension free?

Yes, Chrome Extension is completely free, licensed under MIT-0. You can download, install and use it at no cost.

Which platforms does Chrome Extension support?

Chrome Extension is cross-platform and runs anywhere OpenClaw / Claude Code is available (cross-platform).

Who created Chrome Extension?

It is built and maintained by Samuel Berthe (@samber); the current version is v1.0.2.

💬 Comments