Guide for developing modern Chrome extensions using Manifest V3. Use when creating, modifying, or troubleshooting Chrome extensions. Covers setting up projects with manifest.json, implementing service workers, content scripts, and popups, managing permissions and security, building with action API and declarativeNetRequest, and Chrome Web Store publication. Includes 2025 best practices and MV3 migration patterns.
Resources
3Install
npx skillscat add within-7/minto-plugin-tools/chrome-extension-dev Install via the SkillsCat registry.
Chrome Extension Development
Build modern Chrome extensions using Manifest V3, the current 2025 standard for secure, performant browser extensions.
Quick Start
Create a minimal extension:
- Create
manifest.jsonwith MV3 format - Add service worker for background logic
- Create UI (popup, side panel, or content script)
- Load unpacked in
chrome://extensions
See asset templates for complete project structure.
Core Concepts
Manifest V3 Architecture
Service Workers replace background pages:
- Event-driven, terminate when idle
- No DOM access
- Use chrome.storage and chrome.runtime for data
Content Scripts:
- Run in web page context
- Can read/modify DOM
- Communicate via messaging API
Action API:
- Toolbar icon interactions
- Popup windows
- Badge text/icons
Development Workflow
- Initialize project structure
- Configure manifest.json (see MANIFEST.md)
- Implement components (service worker, content scripts, popups)
- Load and test locally in developer mode
- Debug using Chrome DevTools
- Package for Chrome Web Store
Common Extension Patterns
Popup Extension
Structure:
extension/
├── manifest.json
├── popup.html
├── popup.js
└── icons/
├── icon16.png
├── icon48.png
└── icon128.pngmanifest.json:
{
"manifest_version": 3,
"name": "My Extension",
"version": "1.0",
"action": {
"default_popup": "popup.html"
}
}Content Script Extension
manifest.json:
{
"manifest_version": 3,
"name": "Page Modifier",
"version": "1.0",
"content_scripts": [{
"matches": ["https://example.com/*"],
"js": ["content.js"],
"run_at": "document_idle"
}]
}Message passing to service worker:
// content.js
chrome.runtime.sendMessage({action: "getData"}, (response) => {
console.log(response.data);
});
// background.js
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request.action === "getData") {
sendResponse({data: "example"});
}
});Background Service Worker
manifest.json:
{
"manifest_version": 3,
"name": "Background Task",
"version": "1.0",
"background": {
"service_worker": "background.js"
},
"permissions": ["storage", "alarms"]
}background.js:
chrome.alarms.create("refresh", {periodInMinutes: 60});
chrome.alarms.onAlarm.addListener((alarm) => {
if (alarm.name === "refresh") {
// Perform periodic task
}
});Declarative Net Request
manifest.json:
{
"manifest_version": 3,
"name": "Request Blocker",
"version": "1.0",
"permissions": ["declarativeNetRequest"],
"declarative_net_request": {
"rule_resources": [{
"id": "ruleset",
"enabled": true,
"path": "rules.json"
}]
}
}rules.json:
[{
"id": 1,
"priority": 1,
"action": {"type": "block"},
"condition": {
"domains": ["example.com"],
"urlFilter": "||tracker.com/*"
}
}]Permissions Best Practices
Use minimum required permissions:
- Active permissions: Declare in manifest.json
- Optional permissions: Request at runtime with
chrome.permissions.request()
Common permissions:
storage- chrome.storage APIactiveTab- current tab access (user gesture required)scripting- dynamic script injectionalarms- scheduled taskstabs- tab management
Key APIs
Storage API
// Save data
chrome.storage.local.set({key: "value"});
// Retrieve data
chrome.storage.local.get(["key"], (result) => {
console.log(result.key);
});Tabs API
// Query tabs
chrome.tabs.query({active: true, currentWindow: true}, (tabs) => {
const currentTab = tabs[0];
});
// Send message to content script
chrome.tabs.sendMessage(tabId, {action: "execute"});Scripting API
// Inject content script dynamically
chrome.scripting.executeScript({
target: {tabId: tabId},
files: ["content.js"]
});Security Guidelines
Critical MV3 requirements:
- ✅ All code bundled with extension
- ❌ No remotely hosted JavaScript
- ❌ No eval() or inline scripts
- ✅ Content Security Policy required
CSP example:
{
"content_security_policy": {
"extension_pages": "script-src 'self'; object-src 'self'"
}
}Testing & Debugging
Load unpacked extension:
- Navigate to
chrome://extensions - Enable "Developer mode"
- Click "Load unpacked"
- Select extension directory
Debug service worker:
- Go to
chrome://extensions - Find extension, click "service worker" link
- Opens DevTools for background script
Debug content script:
- Open web page where script runs
- Open DevTools (F12)
- Content script appears in Sources panel
Debug popup:
- Right-click extension icon
- Select "Inspect popup"
Migration from V2 to V3
Key changes:
- Background pages → Service workers
chrome.webRequest→declarativeNetRequestchrome.extension.getBackgroundPage()→ Use messaging- Persistent state → chrome.storage
See MV3 Migration Guide for detailed steps.
Chrome Web Store Publication
Requirements:
- Single, clearly defined purpose
- Detailed store listing (screenshots, description)
- Privacy policy if collecting data
- Comply with Developer Program Policies
Package extension:
- Zip all extension files (not the folder itself)
- Upload to Chrome Web Store Developer Dashboard
- Complete store listing
- Submit for review
Resources
Detailed Documentation
- Manifest Configuration - Complete manifest.json reference
- MV3 Migration Guide - V2 to V3 migration patterns
- API Reference - All Chrome extension APIs
Asset Templates
- Basic extension - Minimal popup extension
- Content script - Page modification example
- Service worker - Background processing example
- Declarative rules - Network filtering example
Tools
- Chrome Extensions Developer Hub - Official documentation
- Extension Playground - Tutorials and examples