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.

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 ownhost_permissionskey. - Blocking web requests. Extensions that modified or blocked network requests now use the
declarativeNetRequestAPI instead. - DOM work in the background. A service worker has no
windowordocument. If you need them, use an offscreen document. - Timers and globals. Long
setTimeoutcalls and global variables disappear when the worker stops. Usechrome.alarmsandchrome.storage.
Google’s Manifest V3 migration guide lists every change, and it is worth reading once from top to bottom before porting anything.

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
- Load the packed build with “Load unpacked” and test every feature in it.
- Search the built files for
eval,new Functionand anyhttps://script URLs. - Justify every permission in one sentence, and drop the ones you cannot.
- Stop and restart the service worker from
chrome://extensions, then check nothing is lost. - Read the listing as a stranger would: does it describe exactly one job?
- 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.




