Manifest V3 requires that the executable code making up the extension ships inside the package. Developers who get this rejection usually believe they comply — and often the offending line is a single hosted analytics tag someone added months ago.
The distinction that matters
The question is not whether your extension talks to the network. It is whether what comes back can change what your extension executes.
Data is fine. Instructions are not.
Things that get flagged
- A CDN script tag in an extension page — jQuery, Bootstrap, a chart library, Google Analytics, Tag Manager. Very common in options pages copied from a website.
- Remote JavaScript pulled in by a font or stylesheet helper. Remote fonts and CSS are not themselves remote code, but a loader script fetched from a CDN is. CSS and fonts can still raise separate CSP and privacy questions.
eval()ornew Function()on anything that came from the network.- Injecting a remote script into a page via
document.createElement("script")with a remotesrc. - A server response that supplies logic — new expressions, rules, scripts or commands that the extension then interprets or executes. Selecting between code paths that already ship in the package is a normal feature flag and is a different thing.
- An iframe used to supply extension logic — if the extension depends on code running inside a remote page to provide its functionality, that is the problem. Simply displaying remote web content is not automatically a violation, though CSP, permissions and other policies still apply.
Things that are usually not the problem
- Calling your API and rendering the response.
- Loading images or media from a remote host.
- A WebSocket that carries data.
- Feature flags whose values select among behaviours already present in the bundled code.
How to fix it
1. Bundle the dependency
Download the library, put it in your extension folder, and reference it locally.
<!-- before --> <script src="https://cdn.example.com/chart.min.js"></script> <!-- after --> <script src="lib/chart.min.js"></script>
This also makes your extension work offline, which is usually an improvement anyway.
2. Drop the hosted analytics tag
Hosted analytics snippets load remote script and are a frequent cause of this rejection. If you need usage numbers, send your own events to your own endpoint from bundled code, and disclose that collection in your privacy policy and permission justifications.
3. Replace dynamic evaluation
If something evaluates a string, restructure it so the branches exist in your shipped code and the server response only selects between them.
4. Check the whole package, not just what was flagged
Assume the full package may be reviewed again on resubmission. Grepping your source for http://, https://, eval( and new Function( is a useful first pass — it also matches ordinary API and image URLs, and it will miss dynamically built URLs, so read the results rather than trusting the count. Include any library folder you vendored.
What to write in the appeal or notes
Name the specific thing you changed. A general statement of compliance without naming the change tends to invite follow-up questions.
Not sure what your manifest declares? The free manifest checker lists your permissions and flags the parts reviewers question most. Your manifest is read in your browser and is not uploaded; the page itself keeps an anonymous view count.
The Chrome Web Store Submission Kit (paid, opens in a new tab) covers the full submission — permissions, privacy policy, listing, and the resubmission checklist.