Chrome Extension Manifest V3 Cheatsheet: Every Field Explained (2026)
Building a Chrome extension? The manifest.json file is the single most important file in your project. Get it wrong, and Chrome won’t even load your extension. Get it right, and you unlock the full power of the Extensions API.
This cheatsheet covers every manifest.json field in Manifest V3 — the only supported format as of 2026. Bookmark it. You’ll come back to it often.
Required Fields
These fields are mandatory. Your extension will not load without them.
manifest_version
{
"manifest_version": 3
}Must be 3. Manifest V2 is no longer supported in Chrome.
name
{
"name": "My Extension Name"
}Max 75 characters. Displayed in the Chrome Web Store, install dialog, and chrome://extensions. Supports localization via __MSG_appName__.
version
{
"version": "1.2.3"
}Follows major.minor.patch format (up to 4 dot-separated integers). Chrome uses this for auto-update comparisons.
description
{
"description": "A short, compelling summary of what your extension does"
}Max 132 characters. Required by the Chrome Web Store. This appears in search results — treat it like a meta description for SEO.
icons
{
"icons": {
"16": "icons/icon16.png",
"32": "icons/icon32.png",
"48": "icons/icon48.png",
"128": "icons/icon128.png"
}
}Required for Web Store submission. Provide all four sizes. Use PNG format for best compatibility.
Core Extension Fields
These define your extension’s architecture and behavior.
action (Toolbar Button)
{
"action": {
"default_icon": {
"16": "icons/icon16.png",
"32": "icons/icon32.png"
},
"default_title": "Click me",
"default_popup": "popup.html"
}
}Controls the toolbar icon appearance and behavior. Replaces the old browser_action and page_action from MV2.
background (Service Worker)
{
"background": {
"service_worker": "background.js",
"type": "module"
}
}Registers your service worker — the event-driven backbone of your extension. Use "type": "module" to enable ES module imports. Service workers terminate when idle, so don’t store state in global variables.
content_scripts
{
"content_scripts": [
{
"matches": ["https://*.example.com/*"],
"js": ["content.js"],
"css": ["content.css"],
"run_at": "document_idle"
}
]
}Injects scripts and styles into web pages matching the URL patterns. Key properties:
| Property | Description |
|---|---|
matches | URL patterns to match (required) |
js | JavaScript files to inject |
css | CSS files to inject |
run_at | document_idle (default), document_start, or document_end |
match_about_blank | Whether to inject into about:blank frames |
all_frames | Inject into all frames, not just top-level |
side_panel
{
"side_panel": {
"default_path": "sidepanel.html"
}
}Displays an HTML page in Chrome’s side panel. Requires "sidePanel" permission.
Permissions
The most critical section for security and user trust. Chrome shows permission warnings during installation based on what you declare here.
permissions (Required at Install)
{
"permissions": [
"storage",
"activeTab",
"contextMenus",
"alarms",
"notifications"
]
}Common permissions and what they unlock:
| Permission | API Access | User Warning? |
|---|---|---|
activeTab | Temporary access to current tab | No |
storage | chrome.storage | No |
contextMenus | Right-click menu items | No |
alarms | chrome.alarms for scheduling | No |
tabs | chrome.tabs (URL, title) | Yes — “Read your browsing history” |
notifications | Desktop notifications | Yes |
scripting | chrome.scripting.executeScript | No (needs host permissions) |
declarativeNetRequest | Network request rules | Yes — “Block content on any page” |
cookies | chrome.cookies | Yes |
downloads | chrome.downloads | Yes — “Manage your downloads” |
bookmarks | chrome.bookmarks | Yes — “Read and change your bookmarks” |
host_permissions
{
"host_permissions": [
"https://*.example.com/*",
"https://api.myservice.com/*"
]
}Grants access to specific domains. Users see a warning for each domain. Best practice: use activeTab instead of <all_urls> whenever possible.
optional_permissions & optional_host_permissions
{
"optional_permissions": ["downloads", "bookmarks"],
"optional_host_permissions": ["https://*.newsite.com/*"]
}Request these at runtime via chrome.permissions.request(). Reduces install friction by only asking when the user actually needs the feature.
UI and Pages
options_ui (Embedded Options)
{
"options_ui": {
"page": "options.html",
"open_in_tab": false
}
}Settings page embedded in chrome://extensions. Set open_in_tab: true to open as a full tab instead.
chrome_url_overrides
{
"chrome_url_overrides": {
"newtab": "newtab.html"
}
}Override Chrome’s default New Tab, History, or Bookmarks page. Only one override per extension.
devtools_page
{
"devtools_page": "devtools.html"
}Adds custom panels to Chrome DevTools. The HTML file creates the panel via chrome.devtools.panels.create().
Networking and Security
content_security_policy
{
"content_security_policy": {
"extension_pages": "script-src 'self'; object-src 'self'",
"sandbox": "sandbox allow-scripts; script-src 'self' https://example.com"
}
}MV3 enforces strict CSP — no remote code execution. All JavaScript must be bundled within your extension package.
declarative_net_request
{
"declarative_net_request": {
"rule_resources": [
{
"id": "ruleset_1",
"enabled": true,
"path": "rules.json"
}
]
}
}Replaces webRequest blocking. Define network modification rules declaratively in a JSON file.
web_accessible_resources
{
"web_accessible_resources": [
{
"resources": ["images/*", "styles/*"],
"matches": ["https://*.example.com/*"]
}
]
}Exposes extension files to web pages. In MV3, you must specify which sites can access each resource — no more blanket access.
externally_connectable
{
"externally_connectable": {
"matches": ["https://*.mywebsite.com/*"]
}
}Allows your website or other extensions to send messages to your extension via chrome.runtime.sendMessage().
Keyboard and Commands
commands
{
"commands": {
"_execute_action": {
"suggested_key": {
"default": "Ctrl+Shift+Y",
"mac": "Command+Shift+Y"
},
"description": "Open the popup"
},
"toggle-feature": {
"suggested_key": {
"default": "Alt+Shift+T"
},
"description": "Toggle the feature"
}
}
}_execute_action is a special command that triggers the toolbar button click. Custom commands fire events on chrome.commands.onCommand.
omnibox
{
"omnibox": {
"keyword": "ext"
}
}Users type your keyword in the address bar, then press Tab to enter your extension’s search mode.
Metadata and Distribution
short_name
{
"short_name": "MyExt"
}Max 12 characters. Used when space is limited. Falls back to a truncated name.
version_name
{
"version_name": "1.0 Beta"
}Human-readable version label displayed instead of version on the extensions page.
minimum_chrome_version
{
"minimum_chrome_version": "116"
}Users on older versions see “Not compatible” in the Web Store. Blocks auto-updates to older browsers.
homepage_url
{
"homepage_url": "https://myextension.com"
}Links to your extension’s website from the extensions management page.
update_url
{
"update_url": "https://myserver.com/updates.xml"
}For self-hosted extensions only. Chrome Web Store extensions get auto-updates automatically.
key
{
"key": "MIIBIjANBgkqhkiG9w..."
}Locks your extension ID during development. Useful for OAuth redirects and consistent testing.
Localization
default_locale
{
"default_locale": "en"
}Required if your extension uses _locales/ folder. Must not be present in non-localized extensions.
Use the __MSG_keyname__ pattern in manifest fields to reference translated strings from _locales/{lang}/messages.json.
Advanced and Specialized
incognito
{
"incognito": "spanning"
}| Value | Behavior |
|---|---|
spanning | Single instance shared between normal and incognito (default) |
split | Separate instance for incognito |
not_allowed | Disabled in incognito |
sandbox
{
"sandbox": {
"pages": ["sandbox.html"]
}
}Sandboxed pages run with relaxed CSP but have no access to extension APIs or non-sandboxed pages.
oauth2
{
"oauth2": {
"client_id": "YOUR_CLIENT_ID.apps.googleusercontent.com",
"scopes": ["https://www.googleapis.com/auth/userinfo.email"]
}
}For Google OAuth integration. Generate your client ID in the Google Cloud Console.
storage (Managed)
{
"storage": {
"managed_schema": "schema.json"
}
}Defines a JSON schema for enterprise-managed storage. IT admins configure values via Chrome policies.
requirements
{
"requirements": {
"3D": {
"features": ["webgl"]
}
}
}Prevents installation on systems that don’t support required technologies.
tts_engine
{
"tts_engine": {
"voices": [
{
"voice_name": "Alice",
"lang": "en-US"
}
]
}
}Registers your extension as a text-to-speech engine.
ChromeOS-Only Fields
These only apply to extensions running on ChromeOS.
| Field | Purpose |
|---|---|
file_browser_handlers | Handle file types in ChromeOS file browser |
file_handlers | Register file types the extension can open |
file_system_provider_capabilities | Create virtual file systems |
input_components | Register as an input method (IME) |
Minimal Starter Template
Copy-paste this to get started immediately:
{
"manifest_version": 3,
"name": "My Extension",
"version": "1.0.0",
"description": "A brief description of what it does",
"icons": {
"16": "icons/icon16.png",
"48": "icons/icon48.png",
"128": "icons/icon128.png"
},
"action": {
"default_popup": "popup.html",
"default_icon": {
"16": "icons/icon16.png",
"32": "icons/icon32.png"
}
},
"permissions": ["storage", "activeTab"],
"background": {
"service_worker": "background.js"
}
}Common Mistakes to Avoid
- Using
<all_urls>inhost_permissions— triggers a scary warning and lowers install rates. UseactiveTabor specific domains. - Forgetting
"type": "module"in background — ES imports won’t work without it. - Storing state in service worker globals — they terminate when idle. Use
chrome.storageinstead. - Missing
web_accessible_resourcesmatch patterns — MV3 requires explicit domain lists, unlike MV2’s wildcard access. - Requesting permissions you don’t use — Chrome Web Store reviewers flag unused permissions, and users distrust over-permissioned extensions.
Quick Reference Card
| Category | Fields |
|---|---|
| Required | manifest_version, name, version, description, icons |
| Architecture | background, content_scripts, action, side_panel |
| Permissions | permissions, host_permissions, optional_permissions, optional_host_permissions |
| UI Pages | options_ui, chrome_url_overrides, devtools_page |
| Security | content_security_policy, web_accessible_resources, sandbox |
| Networking | declarative_net_request, externally_connectable |
| Input | commands, omnibox |
| Distribution | homepage_url, update_url, minimum_chrome_version, key |
| Localization | default_locale |
Next Steps
Ready to build? Here are the resources that matter:
- Official Manifest Reference — the source of truth for every field
- Permissions List — complete list of available permissions and their warnings
- Migrate from MV2 to MV3 — step-by-step migration guide
- ExtensionBooster Developer Tools — free tools to analyze, optimize, and grow your Chrome extension
Save this cheatsheet and share it with your team. The manifest is the foundation — nail it, and everything else gets easier.
Share this article
Build better extensions with free tools
Icon generator, MV3 converter, review exporter, and more — no signup needed.
Related Articles
Building Accessible Chrome Extensions: Keyboard, Screen Reader, and WCAG Compliance
26% of US adults have disabilities. Make your Chrome extension accessible with focus traps, ARIA, keyboard nav, and WCAG 2.1 AA compliance.
I Built the Same Chrome Extension With 5 Different Frameworks. Here's What Actually Happened.
WXT vs Plasmo vs CRXJS vs Extension.js vs Bedframe. Real benchmarks, honest opinions, and the framework with 12K stars that's quietly dying.
5 Best Email Marketing Services to Grow Your Chrome Extension (2026)
Compare the top email marketing platforms for SaaS and Chrome extension developers. MailerLite, Mailchimp, Brevo, ActiveCampaign, and Drip reviewed.