Chrome Extensions

Common Manifest V3 Mistakes That Get Extensions Rejected

The Chrome Web Store review process rejects a lot of Manifest V3 extensions, and the rejection emails are often vague. Most of the time it’s one of a handful of recurring mistakes, and knowing them up front saves a rejected submission and a week of waiting.

Illustration of a Chrome extension popup open in the browser, Common Manifest V3 Mistakes That Get Extensions Rejected
The Manifest V3 mistakes behind most Chrome Web Store rejections: broad permissions, remote code, V2 leftovers and vague listings, plus a…

Too many permissions

Asking for broad host permissions, access to all sites, when your extension only needs one is the fastest way to get flagged. Request the narrowest permissions that make the feature work, and use activeTab instead of blanket host access where you can.

A quick audit: open your manifest and, for every entry in permissions and host_permissions, write one sentence on which feature uses it. If you cannot write the sentence, remove it. The developer dashboard asks you to justify each permission anyway, so this work is not wasted. Permissions only a few users need can move to optional_permissions and be requested at the moment the feature is used.

The same applies to content scripts. If the matches list in your manifest covers every site but the feature only works on two, list those two. Reviewers read the manifest, and so do users when Chrome shows the install warning. A short, specific permission prompt is also easier for people to say yes to.

Remote code and CSP violations

Manifest V3 forbids inline scripts, eval, and remotely hosted code. Pulling a script from a CDN at runtime, or a bundle that injects inline code, will fail review. All code must be packaged inside the extension: test the packed build, not just the dev version.

The line is between code and data. Fetching a JSON settings file from your server is fine. Fetching JavaScript and running it, or building code from strings with new Function, is not. Watch your dependencies too: an analytics or chat library that loads its own scripts from a CDN breaks the rule even if your own code is clean.

Obfuscated code is a separate reason for rejection. Minifying your bundle is allowed. Deliberately scrambling it so reviewers cannot read it is not, so check that your build tool is not running an obfuscation step.

Leftover Manifest V2 patterns

Leftover V2 patterns are another trap: background pages became service workers, so code that keeps state in memory or uses APIs that no longer exist breaks. Make the background logic event-driven and able to survive the worker shutting down.

The usual suspects when porting an older extension:

  • Host access inside permissions. In Manifest V3, site patterns belong in their own host_permissions key.
  • Blocking web requests. Extensions that modified or blocked network requests now use the declarativeNetRequest API instead.
  • DOM work in the background. A service worker has no window or document. If you need them, use an offscreen document.
  • Timers and globals. Long setTimeout calls and global variables disappear when the worker stops. Use chrome.alarms and chrome.storage.

Google’s Manifest V3 migration guide lists every change, and it is worth reading once from top to bottom before porting anything.

Infographic summarising “Common Manifest V3 Mistakes That Get Extensions Rejected”: Too many permissions; Remote code and CSP violations; Leftover Manifest V2 patterns; Single purpose and an honest privacy policy; A pre-submission checklist for Manifest V3 mistakes; Building it right the first time
The article at a glance.

Single purpose and an honest privacy policy

Finally, the store wants a single, obvious purpose and an accurate privacy policy if you collect data. A "utility" that quietly does five unrelated things gets rejected. Narrow permissions, no remote or inline code, proper service worker patterns, and an honest privacy policy clear most rejections.

The listing itself is reviewed too. The description, screenshots and icon must match what the extension actually does, and the privacy section of the dashboard must declare the data you handle. The full rules are in the Chrome Web Store program policies.

Many extensions I am asked to build are companions to a business system, such as a button that saves a lead from a web page into the CRM, or a tool that prepares content for the company website. That is a good single purpose. If the system behind it is still undecided, settle that first: I compare the options in custom CRM vs HubSpot and WordPress vs Webflow.

A pre-submission checklist for Manifest V3 mistakes

  1. Load the packed build with “Load unpacked” and test every feature in it.
  2. Search the built files for eval, new Function and any https:// script URLs.
  3. Justify every permission in one sentence, and drop the ones you cannot.
  4. Stop and restart the service worker from chrome://extensions, then check nothing is lost.
  5. Read the listing as a stranger would: does it describe exactly one job?
  6. Check the privacy policy matches the data the extension really collects.

If you do get rejected, the email includes a violation reference. Look it up on the Chrome Web Store troubleshooting page, fix that specific issue, and say what you changed when you resubmit. Sending the same build again unchanged, hoping for a different reviewer, usually just costs another round of waiting.

Building it right the first time

Most of these problems are cheaper to avoid than to fix after a rejection. If you are building the interface in React, the CSP and service worker points come up again in building a Chrome extension with React. If you would rather hand the whole build and submission to someone who has been through review before, that is part of my web application development work.

Questions people ask

Why was my Chrome extension rejected?

Most rejections come from a few recurring problems: broader permissions than the features need, remotely hosted or inline code, obfuscated code, a listing that does not match what the extension does, or a missing or inaccurate privacy policy. The rejection email includes a violation reference you can look up.

Can a Manifest V3 extension load code from a CDN?

No. All JavaScript must be packaged inside the extension. Fetching data such as a JSON settings file from your server is fine, but downloading scripts and running them, or using eval or new Function, breaks the Manifest V3 rules and fails review.

Should I use activeTab or host permissions?

Use activeTab whenever the extension only needs a page after the user clicks it. It grants temporary access to the current tab without asking for access to every site. Broad host permissions should be reserved for features that genuinely need to run on many sites automatically.

Does my Chrome extension need a privacy policy?

If it collects or handles user data, yes. The privacy policy must be accurate, and the data you declare in the developer dashboard must match what the extension actually collects. Extensions that collect nothing still need to fill in the privacy section honestly.

Comments

Leave a comment

0 / 3000
Comments are moderated. Links are not clickable and your email is never published. See the privacy policy.
keep reading

Related articles

Usually replies within a day
let’s talk

Tell me what you want to build

A website, an app, some automation, or something you’re still figuring out. Tell me the problem and I’ll give you a straight answer on what it takes. No pressure, no sales team.