In April I wrote about building a Chrome extension in Blazor WebAssembly, rewriting it in JavaScript, and going back to Blazor. I went back. Anaglyphohol 4.0.0 is done, it is the best version I have ever shipped, and Google will not let Chrome users have it.
This is what happened, with every email, line of code and commit linked. The full record is on GitHub: stupid-at-google.
What Anaglyphohol is
Anaglyphohol is a browser extension that turns the videos and images on web pages into 3D as you browse. Put on red/cyan glasses, open a video, and the picture gains depth. A depth estimation AI runs on your own graphics card through WebGPU. Nothing is uploaded, there is no account, no ads, no tracking. It is free on every site, and the source is public.
Version 4.0.0 is written in C# (.NET 10, Blazor WebAssembly) and runs the depth models and 3D kernels on the GPU with my own open source libraries, SpawnDev.ILGPU and SpawnDev.ILGPU.ML.
Rejection 1: "Keyword spam"
On October 7 the Chrome Web Store rejected 4.0.0 for "excessive and / or irrelevant keywords" in the description. The offending text:
"YouTube, Twitch, Pluto TV, Tubi, Bing, Google, Yahoo and more."
Those are the sites the extension is built for. It turns 3D on by default on exactly those sites. Google called a list of supported sites, one of which is Google, "irrelevant". Version 2.0.0 had a list just like it in its description and passed review.
I removed the list anyway and used the exact description Google had already approved for version 3.0.14. Resubmitted the same day.
Rejection 2: "Requesting but not using" storage and offscreen
On October 9 it was rejected again. This time the claim was that Anaglyphohol requests the storage and offscreen permissions and does not use them.
Both are used.
-
storagesaves every setting the user changes: 3D on or off, per-site switches, 3D mode, depth level, focus, toolbar state. Without it, no setting survives a page load. -
offscreenruns the "Shared 3D converter", an option that runs one depth and 3D converter for every tab instead of one per page.
Notice what this rejection is not. Google did not say Anaglyphohol is malware, a scam, or a privacy risk. It did not say the extension does anything harmful. It said the extension asks for two permissions and does not use them: in other words, that it does too little. Neither permission even shows users a warning at install time (Chrome's permission list gives history, tabs and others a "Warning displayed" line; storage and offscreen have none). And the claim is false: both are used. Google rejected a free extension for not using code that it does use.
Here is why a lazy scan misses them. Anaglyphohol is C# compiled to WebAssembly. Chrome supports WebAssembly in Manifest V3 extensions; wasm-unsafe-eval exists for exactly this. The compiled code reaches the extension APIs through an interop library, SpawnDev.SpawnJS.BrowserExtension, which reads properties off the global chrome object by name:
// Browser.cs
public Storage? Storage => JSRef!.Get<Storage?>("storage");
public Offscreen? Offscreen => JSRef!.Get<Offscreen?>("offscreen");
// Offscreen/Offscreen.cs
public Task CreateDocument(OffscreenCreateParameters parameters) => JSRef!.CallVoidAsync("createDocument", parameters);
public Task<bool> HasDocument() => JSRef!.CallAsync<bool>("hasDocument");
So chrome.storage and chrome.offscreen never appear as literal text in the package's .js files. If your review is a grep of the JavaScript, you will not find them. The strings are still in the package: storage, offscreen, createDocument and hasDocument sit in the compiled .wasm, stored as UTF-16 the way .NET stores strings.
The appeal
Google's appeal reply asked for "evidence(code snippet) of usage of above permission".
So I sent it. Every call site, file names, line numbers, the interop code that calls chrome.storage.sync.get/set and chrome.offscreen.createDocument/hasDocument/closeDocument, GitHub permalinks to the exact commits in the build, and the steps to watch the offscreen document run in chrome://extensions.
The answer, the next morning:
We are not able to see the provided code in the extension package. So, we request you to update by removing "storage" and "offscreen" permissions from the manifest file.
[...] Please reply to this email with evidence that the functionality is not working after removing the permissions.
They asked for code. They got code. They said they cannot see the code. Then they asked me to break my own extension and send proof that it is broken.
Checking whether a permission is used is the review. It takes about a minute: install the extension, change a setting, reload the page, see that it stuck. Handing that job back to the developer is lazy, and asking for a deliberately broken build as "evidence" is absurd.
Google already approved this exact pattern. Twice.
This is the part that makes it indefensible.
| Version | Built with | Permissions | Chrome Web Store |
|---|---|---|---|
| 1.0.x | .NET 8 Blazor WebAssembly |
storage, used from WebAssembly |
Approved |
| 2.0.0 | .NET 8 Blazor WebAssembly |
storage, used from WebAssembly |
Approved |
| 3.0.14 | JavaScript and HTML |
storage, offscreen
|
Approved, live today |
| 4.0.0 | .NET 10 Blazor WebAssembly |
storage, offscreen, used from WebAssembly |
Rejected: "not used" |
Versions 1 and 2 were Blazor WebAssembly apps that called storage from compiled code, invisible to a text search, exactly like version 4. Google approved both. Version 3.0.14, still being served to Chrome users today, requests the exact same two permissions as 4.0.0 and has the exact same description. Google approves the extension it is serving and rejects the update that asks for nothing more.
The Chrome Web Store is hostile to WebAssembly
Put it together. Chrome supports WebAssembly in extensions; wasm-unsafe-eval exists for it. The review treats a permission as unused unless the package's JavaScript names it. When I sent the code, the answer was that they could not see it, and the fix they demanded was removing the permissions, not reading the code. Google's own AI describes the review as a string-matching scanner and advises faking the JavaScript (more on that below).
In practice, that makes the Chrome Web Store hostile to WebAssembly. An extension written in C#, Rust, Go, C++ or anything else that compiles to WebAssembly can use exactly the APIs it declares and still be rejected, unless it ships JavaScript whose only job is to be seen by the scan. My versions 1 and 2 got through. Version 4 did not, and nothing in the rules tells you which outcome to expect.
Free work, turned away
Extensions are a large part of what makes Chrome worth using, and developers build them for free. Every free extension Google lists makes its browser more valuable at no cost to Google. Anaglyphohol asks Google for nothing but a listing.
Alphabet reported $403 billion in revenue for 2025. The check that would have settled this takes about a minute. Instead, the rejection flagged two permissions it could not find in the package's text, and a person handling the appeal asked for code, received it, and answered with the same finding, adding only that they could not see it.
If the final word belongs to whatever the first pass could or could not find, what is the person on the appeal being paid for? Google pays for a human review step, and the human handed the review back to me. That is lazy, and it turns away free work that Google itself benefits from.
What it costs to give something away on Google's store
To put a free extension on the Chrome Web Store, I paid Google a registration fee, and Google required my full name, home address and phone number. As a "trader", all three were published on the listing page. The dashboard later switched me to "non-trader" without asking me to confirm. Switching back meant uploading my driver's license again, so I left it. My name and home street address are still on the public page.
Then every update means a full release build (over an hour; it is AOT compiled), a submission, a wait, and a form letter. This one update cost days. The time should have gone into the extension and the open source libraries other developers use for free.
And it is not only Chrome. Google now requires Android developers to register and verify their identity with Google before their apps can be installed on certified Android devices, even apps that never touch the Play Store. Enforcement began September 30, 2026 in Brazil, Indonesia, Singapore and Thailand, with a worldwide rollout planned for 2027. Independent developers are being treated as the problem.
Not the first time
This is not my first write-up of Google treating the people who use and build on its platforms as a resource to be managed.
- Google Drive Isn't a Drive Anymore - It's a Trap
- I Got My Data Out of Google - Here's What They Did to It on the Way Out
- I Built a Chrome Extension in Blazor WASM, Rewrote It in JavaScript, and I'm Going Back to Blazor, where I noted in April that Google puts a solo developer's home address on a public page as the price of publishing a free tool.
In April I called that the cost of publishing on Google's platform. In October I paid it and still could not publish.
What I did not do
The obvious workaround is to ship a JavaScript file that names chrome.storage and chrome.offscreen literally, just so the scan finds them. It would change nothing about what the extension does. It would only confirm that a keyword search counts as a review. I did not do it.
That workaround came from Google itself. When I asked Gemini, Google's own AI, about the rejection, it described the review as a "naive static string-matching analyzer" and recommended what it called "The Canary String Trick (Easiest Bypass)":
// Add this dummy function somewhere in an unminified JS file included in your extension package
function __chrome_store_compliance_canary() {
// Explicit string literals for the static analyzer
if (false) {
console.log(chrome.storage, chrome.offscreen);
}
}
Dead code that can never run, there only so "the scanner will see them and clear the build" (Gemini's full reply). Claude, the AI I build with, pointed out that this would likely make things worse: code that exists only to pass a scan looks like an attempt to mislead the review if a reviewer ever notices it. Google's AI advises gaming Google's review. Google's review rejects honest code.
I'm pulling Anaglyphohol from the Chrome Web Store
I am done with Google's stores. Anaglyphohol stays free and open source.
- Download 4.0.0: GitHub release
- Install it without the Chrome Web Store (Edge, Chrome, Brave, Opera, Vivaldi, Firefox): INSTALL.md
- The full record, every email verbatim: stupid-at-google
If you want a browser run by people who can review an extension, use Microsoft Edge. It runs every Chrome extension, and Edge Add-ons lists Anaglyphohol.
If you build extensions in C#, Rust, Go or anything else that compiles to WebAssembly, expect the same wall. Chrome supports WebAssembly in extensions. Chrome's review process does not.
If I owned Alphabet stock, I would want to know that the Chrome Web Store turns away finished, free work because its review cannot read WebAssembly and will not look at the code it asks for.
Using Google is just not worth it.
Top comments (0)