Reference · 9 min read

Chrome Extension manifest.json Example (Manifest V3)

A complete, copy-paste manifest.json for Manifest V3, with every field explained line by line.

Illustration for the ManifestGo article: Chrome Extension manifest.json Example (Manifest V3)

Every Chrome extension starts with manifest.json. It tells Chrome what your extension is called, what it is allowed to do, and which files run where. Get it wrong and Chrome refuses to load the folder at all.

A complete Manifest V3 example

{ "manifest_version": 3, "name": "Focus Timer", "version": "1.0.0", "description": "Blocks distracting sites and runs a Pomodoro timer.", "action": { "default_popup": "popup.html", "default_icon": { "16": "icons/icon16.png", "32": "icons/icon32.png", "48": "icons/icon48.png", "128": "icons/icon128.png" } }, "background": { "service_worker": "background.js" }, "permissions": ["storage", "alarms"], "host_permissions": ["https://*/*"], "content_scripts": [{ "matches": ["https://*/*"], "js": ["content.js"], "run_at": "document_idle" }], "icons": { "16": "icons/icon16.png", "48": "icons/icon48.png", "128": "icons/icon128.png" } }

Field by field

  • manifest_version: must be 3. Manifest V2 extensions are no longer accepted.
  • name, version, description: store metadata. version must be dot-separated integers.
  • action: the toolbar button — default_popup and default_icon live here.
  • background.service_worker: a single JS file, event-driven, no persistent page.
  • permissions vs host_permissions: API access vs site access, kept separate in V3.
  • content_scripts: files injected into matching pages, with run_at controlling timing.
  • icons: the install/Web Store icon set, separate from the toolbar icon.

Common mistakes

  • Referencing a file path that does not exist — Chrome fails the whole load.
  • Using remote scripts or inline handlers, which Manifest V3 CSP blocks.
  • Putting host patterns in permissions instead of host_permissions.
  • Shipping SVG icons — Chrome's toolbar requires PNGs.

The web_accessible_resources gotcha

Manifest V3 changed web_accessible_resources from a flat array of paths to a list of objects with resources and matches: [{ "resources": ["fonts/*.woff2"], "matches": ["https://*/*"] }]. Forgetting the matches array is the single most common reason an injected stylesheet or image 404s on the page even though the file exists in the packaged extension.

content_security_policy in V3

Instead of a single csp string, V3 uses "content_security_policy": { "extension_pages": "script-src 'self'; object-src 'self'" }. This CSP applies to popup.html, options.html and any extension page — not to content scripts, which are governed by the page's own CSP instead.

declarative_net_request instead of blocking webRequest

  • "declarative_net_request" with a "rule_resources" array replaces the blocking variant of webRequest for ad and tracker blockers.
  • Rules are static JSON evaluated by Chrome itself, so the service worker does not need to stay alive to filter requests.
  • The MAX_NUMBER_OF_DYNAMIC_AND_SESSION_RULES limit is 5000 for unpacked/enterprise policy installs and lower for Web Store extensions without justification.

optional_permissions and optional_host_permissions

List permissions you only sometimes need under optional_permissions instead of permissions. Request them at runtime with chrome.permissions.request(), which shows a Chrome-native consent dialog instead of scaring users at install time with a broad permission list.

Validating your manifest before you ship

  1. Run the file through a JSON linter — trailing commas and comments are the most common syntax failures.
  2. Load it unpacked at chrome://extensions and read any red error banner on the extension card.
  3. Check the Chrome Web Store Developer Dashboard's automated warnings after upload; it flags unused permissions.
  4. Confirm every file path referenced in the manifest actually exists in the zip you are uploading.

If you'd rather skip hand-writing any of this, ManifestGo generates a valid manifest.json plus the matching icons and background/content script files from a plain-English prompt, then packages the whole thing into a .zip ready to upload.

Frequently asked questions

Is manifest.json required for every Chrome extension?

Yes. It is the only mandatory file and must sit at the root of the extension folder.

What is the minimum valid manifest.json?

Three fields: manifest_version, name and version. Everything else is optional but almost every real extension adds action, background or content_scripts.

Do I need host_permissions if I only use activeTab?

No. activeTab grants temporary access to the current tab after a user gesture like a click, so you can skip host_permissions entirely for extensions that only ever act on the tab the user is looking at.

What does 'key' in manifest.json do?

The optional key field pins the extension's ID during local development so it matches the ID it will have once published, which is useful for OAuth redirect URIs and messaging setups that hardcode an extension ID.

Can manifest.json include comments?

No. manifest.json is strict JSON — // or /* */ comments will make Chrome reject the file with a parse error. Put explanations in a README instead.

Keep reading