Chrome Web Store Rejection Codes: Fix the Top 4 in a Day
Originally published on ExtensionLaunch. A Chrome Web Store rejection usually arrives as a policy name and a code like "Blue Argon" or "Purple Potassium", with little detail about what the reviewer saw. Every code maps
Originally published on ExtensionLaunch.
A Chrome Web Store rejection usually arrives as a policy name and a code like "Blue Argon" or "Purple Potassium", with little detail about what the reviewer saw. Every code maps to a specific policy, and the four that hit first-time publishers most often are usually a one-day fix. Here's how to read the code, fix the cause, and choose between resubmitting and appealing.
First, check which kind of action you got
Not every email from the store carries the same risk:
- Rejection: the new submission or update failed review. Your live version (if any) is untouched and users are not told. Fix it and resubmit.
- Warning: applies to an item that is already published. It stays live, but you typically get 7 to 30 days to fix it before it comes down.
- Takedown: the item is pulled from the store, and after several weeks Chrome disables it for existing users.
A warning is a deadline, so treat it as urgent.
The color is the category
The color tells you the policy family before you open the docs:
| Color | What it covers | Common IDs |
|---|---|---|
| Blue | Manifest V3 rules, prohibited products | Blue Argon (remote code) |
| Purple | Permissions and user data | Purple Potassium, Purple Lithium, Purple Nickel |
| Yellow | Broken features, thin functionality, metadata | Yellow Magnesium, Yellow Zinc, Yellow Argon, Yellow Potassium |
| Red | Deception and single purpose | Red Magnesium, Red Titanium, Red Zinc |
| Grey | Content | Adult, gambling, violence and similar |
The four codes most first submissions hit
Purple Potassium: excessive permissions
This is the most common one. Your manifest asks for permissions you don't use, or broader access than you need. Usual suspects:
-
tabsonly unlocksurl,pendingUrl,titleandfavIconUrlon Tab objects. Mostchrome.tabsmethods work without it. -
activeTabisn't required just to calltabs.query()ortabs.sendMessage(). -
cookiesis forchrome.cookies, notdocument.cookie. -
storageis forchrome.storage, notlocalStorageor IndexedDB.
Delete anything you can't point to in code, and move broad host access to runtime:
{
"permissions": ["activeTab"],
"optional_host_permissions": ["https://*.yourapp.com/*"]
}
Then make sure the justifications on the Privacy practices tab match what's left.
Blue Argon: remote code
Manifest V3 requires all executable code inside the package. A CDN <script> tag, eval() on a server string, or an interpreter running remote commands all trigger it. Fetching data is fine; fetching logic is not. Scan the folder you zip:
grep -rnE "<script[^>]*src=[\"']https?://|\beval\(|new Function\(" dist/
Also answer the remote-code question on the Privacy practices tab honestly, or you'll pick up a disclosure problem on top of this one.
Yellow Magnesium: functionality not working
The reviewer couldn't make it work. Usually it's packaging, not logic: a file in manifest.json missing from the ZIP, a case mismatch (Popup.html vs popup.html), a backend that was down, or a login the reviewer didn't have. A quick pre-upload check:
// verify-manifest.mjs usage: node verify-manifest.mjs dist
import { readFileSync, readdirSync } from 'node:fs';
import { join, dirname, basename } from 'node:path';
const dir = process.argv[2] || '.';
const m = JSON.parse(readFileSync(join(dir, 'manifest.json'), 'utf8'));
const list = (v) => (typeof v === 'string' ? [v] : Object.values(v || {}));
const refs = [
m.background?.service_worker,
m.action?.default_popup,
m.options_ui?.page ?? m.options_page,
m.side_panel?.default_path,
...list(m.icons),
...list(m.action?.default_icon),
...(m.content_scripts || []).flatMap((cs) => [...(cs.js || []), ...(cs.css || [])]),
].filter(Boolean);
// Compare exact file names so a case mismatch fails even on macOS
const exists = (p) => {
try { return readdirSync(dirname(p)).includes(basename(p)); } catch { return false; }
};
const missing = refs.filter((r) => !exists(join(dir, r)));
if (missing.length) {
console.error('Missing from package:', missing);
process.exit(1);
}
console.log(`OK: all ${refs.length} referenced files are present.`);
If anything needs an account, fill in the Test instructions section in the Developer Dashboard with credentials and steps.
Purple Lithium: privacy policy
Your privacy policy is missing, not in the Privacy tab's policy field, unreachable, or silent on how data is collected, used and shared. Put a working URL in that field, not just your description. Its sibling Purple Nickel means collecting data without in-product disclosure and consent: show what you collect and wait for a yes.
Codes you can't fix with an update
For Red Titanium (obfuscation) and Red Zinc (deceptive installation), Google says to publish a new extension rather than patch the old one. Minification is fine; Base64 or character-encoding tricks count as obfuscation, so disable string encoding in your build before submitting.
Resubmit or appeal?
- Resubmit when the reviewer was right. Bump the version, update the Privacy tab, and note non-obvious fixes in test instructions. To swap a package already queued, use Cancel review, upload the fix, and resubmit.
- Appeal only when you're sure you comply. Name the reference ID, quote the policy, point to the file and line that uses the flagged permission, and give reproduction steps. Replies can take up to three days.
Launch tip: uncheck automatic publishing when you submit. You get up to 30 days after approval to publish manually, so launch day lands on an approved version.
Key takeaways
- The code's color tells you the policy family.
- Purple Potassium, Blue Argon, Yellow Magnesium and Purple Lithium are the usual first-submission rejections, all fixable in a day.
- Test the exact ZIP you upload, not your dev build.
- Red Titanium and Red Zinc mean a new listing, so keep obfuscation out of your build.
- Resubmit when the reviewer is right; appeal only with evidence.
The full guide to Chrome Web Store rejection codes and how to fix each one maps every ID in the reference table and includes a pre-submission checklist. Once you're approved, you can launch your browser extension on ExtensionLaunch to get its first upvotes and reviews.
What was the reason for your most frustrating Chrome Web Store rejection, and what fixed it in the end?
Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.