Chrome Extension Manifest V3 Cheatsheet: Every Field Explained (2026)

AppBooster Team · · 9 min read
Chrome browser developer tools and code

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:

PropertyDescription
matchesURL patterns to match (required)
jsJavaScript files to inject
cssCSS files to inject
run_atdocument_idle (default), document_start, or document_end
match_about_blankWhether to inject into about:blank frames
all_framesInject 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:

PermissionAPI AccessUser Warning?
activeTabTemporary access to current tabNo
storagechrome.storageNo
contextMenusRight-click menu itemsNo
alarmschrome.alarms for schedulingNo
tabschrome.tabs (URL, title)Yes — “Read your browsing history”
notificationsDesktop notificationsYes
scriptingchrome.scripting.executeScriptNo (needs host permissions)
declarativeNetRequestNetwork request rulesYes — “Block content on any page”
cookieschrome.cookiesYes
downloadschrome.downloadsYes — “Manage your downloads”
bookmarkschrome.bookmarksYes — “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"
}
ValueBehavior
spanningSingle instance shared between normal and incognito (default)
splitSeparate instance for incognito
not_allowedDisabled 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.

FieldPurpose
file_browser_handlersHandle file types in ChromeOS file browser
file_handlersRegister file types the extension can open
file_system_provider_capabilitiesCreate virtual file systems
input_componentsRegister 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

  1. Using <all_urls> in host_permissions — triggers a scary warning and lowers install rates. Use activeTab or specific domains.
  2. Forgetting "type": "module" in background — ES imports won’t work without it.
  3. Storing state in service worker globals — they terminate when idle. Use chrome.storage instead.
  4. Missing web_accessible_resources match patterns — MV3 requires explicit domain lists, unlike MV2’s wildcard access.
  5. Requesting permissions you don’t use — Chrome Web Store reviewers flag unused permissions, and users distrust over-permissioned extensions.

Quick Reference Card

CategoryFields
Requiredmanifest_version, name, version, description, icons
Architecturebackground, content_scripts, action, side_panel
Permissionspermissions, host_permissions, optional_permissions, optional_host_permissions
UI Pagesoptions_ui, chrome_url_overrides, devtools_page
Securitycontent_security_policy, web_accessible_resources, sandbox
Networkingdeclarative_net_request, externally_connectable
Inputcommands, omnibox
Distributionhomepage_url, update_url, minimum_chrome_version, key
Localizationdefault_locale

Next Steps

Ready to build? Here are the resources that matter:

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