A Threaded Web Build Needs Two Headers. Google's Own Ad Tag Doesn't Support Them.
A multithreaded HTML5 game needs two isolation headers to run, and Google's ad tag does not support them. One licensed title can mute your whole ad stack. The requirement is not in the game's file list or its load-time report โ it is a property of how the build was compiled, it applies to the document that serves the game rather than to the game itself, and by the time anyone notices, the catalogue is already live and the revenue line is already wrong.
This is the least-audited line item in HTML5 game due diligence. Buyers check aspect ratios, bundle size, mobile input and licence scope. Almost nobody asks whether a build uses WebAssembly threads, because it sounds like an engine detail. It is not. It is a hosting requirement that propagates outward from the game into every ad call, analytics beacon, consent script and font on the page.
๐งต What "Thread Support" Actually Switches On
A WebAssembly build that uses threads needs SharedArrayBuffer โ a block of memory that more than one worker can see at once. Because that same primitive can be used to build a high-resolution timer, browsers restricted it after Spectre. Google's Publisher Tag documentation states the reasoning plainly: "Because SharedArrayBuffer can be used to create a high resolution timer, it can make Spectre-style attacks more efficient."
The restriction took the form of a gate. A document only gets SharedArrayBuffer if it is cross-origin isolated, and per MDN's COEP reference, getting there means setting the Cross-Origin-Embedder-Policy header to require-corp or credentialless and the Cross-Origin-Opener-Policy header to same-origin. Chrome enforced this from Chrome 92 on desktop and Chrome 88 on Android; Firefox shipped the isolated form from Firefox 79.
Two response headers. That is the entire cost, and it looks trivial on a slide. The cost is in what the first of them does to everything else on the page.
๐ซ require-corp Blocks Everything You Did Not Vet
Cross-Origin-Embedder-Policy: require-corp flips the default for third-party content from permitted to blocked. MDN's description of the rule: a document under it "can only load resources requested in no-cors mode from the same origin, or resources that have explicitly set the Cross-Origin-Resource-Policy header to a value that allows it to be embedded."
Read that as an operator rather than a developer. Every script, image, iframe and font that your page pulls from somebody else's domain now has to send a Cross-Origin-Resource-Policy header saying it is willing to be embedded by you. You do not control that header. The vendor does. If a vendor has not shipped it, the browser drops the resource โ and in Chrome DevTools it drops with a status string, blocked:NotSameOriginAfterDefaultedToSameOriginByCoep, that nobody on a commercial team is watching for.
So the failure mode is not a crash. It is a page that renders, a game that plays, and a set of third-party scripts that silently did not load. Sessions look fine. Revenue does not.
๐ธ Google Says Its Own Ad Tag Doesn't Work Here
This is the part worth quoting to whoever is signing the catalogue deal. Google's Publisher Tag documentation on COEP says it outright: "Google Publisher Tag (GPT) currently doesn't support pages using Cross-Origin-Embedder-Policy (COEP) due to restrictions on cross-origin embedding."
The reason is structural, not a backlog item. Ad delivery is a chain of cross-origin fetches โ creatives, trackers, verification vendors, header-bidding partners โ and every link in it would need to opt into embedding. Google's stated plan is to wait for a browser-level solution rather than push CORP headers through the entire ad supply chain: "Chrome plans to continue supporting this opt-out until support for embedding unmodified third-party content is released. At that point we intend to ensure GPT supports COEP pages."
The opt-out Google points at is a Chrome deprecation trial that let sites keep SharedArrayBuffer without isolating. Chrome's own January 2024 announcement extended it "until Chrome 124" โ a release that reached stable in 2024. If you are reading Google's COEP guidance today and it tells you to register for the trial, that escape hatch has closed. On current desktop Chrome, you isolate or you do not get threads.
๐ช You Cannot Quarantine It Inside an iframe
The obvious architectural instinct is to contain the blast radius: put the threaded game on its own origin, iframe it into a normal page, let the game have its strict headers and let the portal keep its ad tag. Under COOP and COEP, that does not work the way people assume.
COEP is not scoped to the document that sets it. MDN: "The policy applies to loaded resources, and resources in iframes and nested frames." Isolation is a property of a frame tree, not of a single box inside one. That is precisely the design flaw Chrome went on to acknowledge when it shipped a replacement โ the Document Isolation Policy announcement sells the new mechanism on the grounds that it "applies per frame and makes no requirements of subframes." The contrast only means something because COEP does make requirements of subframes.
Practically: if a licensed game's wrapper page is isolated, the frame it lives in inherits obligations upward and downward. You end up choosing at the level of the whole page, which is the level where your monetization lives.
๐ credentialless Is a Chromium Answer to a Cross-Browser Problem
There is a softer variant. COEP: credentialless lets a page load cross-origin resources without a CORP header by stripping their credentials โ MDN describes it as loading them "without an explicit permission via the Cross-Origin-Resource-Policy header," with "cookies omitted in the request, and ignored in the response."
Two problems for a games portal. First, credential-stripping is not free for ad tech: an ad request without cookies is a different, usually cheaper request, and frequency capping and attribution degrade with it. Second, coverage. Google's web.dev guide to cross-origin isolation records credentialless as "available from Chrome 96 and in Edge, but is not yet supported by other browsers." Firefox has since implemented it. Safari has not shipped it at all.
Safari is not a rounding error in casual games. StatCounter's mid-2026 mobile numbers put it around a quarter of worldwide mobile browsing, with the secondary summaries citing figures between roughly 23% and 25.4% depending on the month sampled โ and materially higher than that in North America. A "fix" that leaves out iOS is not a fix for a catalogue whose traffic is mostly phones.
๐ ๏ธ The Real Repair Ships in One Browser, on Desktop
Document Isolation Policy is the fix, and it is genuinely a good one: per-frame isolation with no demands on subframes, which is exactly the shape a games portal needs. It "unlocks access to powerful web functionalities like SharedArrayBuffers or WebAssembly threads" without the COEP contagion, and Google reports that Gmail, Google Meet and Zoom trialled it and now see deploying cross-origin isolation as possible.
Then read the availability line: "Document Isolation Policy is shipping in Chrome 137 for desktop only. The intention is to launch on Android later this year." Desktop Chromium. Not Safari, not iOS, and โ at announcement โ not Android.
Plan on the header behaviour you have, not the one that is coming. A catalogue decision you make this quarter has to serve iPhones this quarter.
๐ฎ The Engine Vendors Already Made This Call for You
The most useful signal here is that the engines conceded the argument. Godot 4 originally built its web export around threads. Then it reversed. The official Godot export documentation now describes single-threaded web export, added in 4.3, as "the preferred and now default way to export your games on the Web" โ while being blunt that it "cannot use threads, and is not as performant as the multi-threaded export."
They traded measurable performance for distribution reach, and the docs name the reason: compatibility with platforms including itch.io and Poki. Poki alone documents 90 million monthly players. When the engine's own maintainers decide the threaded build is worth less than the ability to be hosted anywhere, a licensee buying finished games should weight it the same way.
Unity's position is quieter but points the same direction. Threading in Unity's web builds only reaches native C/C++ and Burst-compiled code; managed C# threads are not supported, because WebAssembly lacks multithreaded garbage collection. So a Unity title that demands isolation is often paying the full hosting cost for a partial win.
๐ Five Questions Before You Sign for a Catalogue
- Does any title in this catalogue require
SharedArrayBuffer? Ask for a yes/no per title, in writing. It is a build flag; the licensor knows. - What headers does your hosted version send? If the games run on the licensor's domain, their header choice becomes your constraint. Fetch a game URL and read the response headers yourself.
- If we self-host, what breaks? A build that assumed isolation and does not get it may fail loudly, fail quietly, or fall back. "Fall back to what" is the real question.
- Is there a single-threaded export of the same title? For Godot-built games since 4.3 the answer is usually yes, and it costs you a request rather than a renegotiation.
- Who pays if a title has to be pulled? If one game forces headers that cost you your ad tag, you will remove it. Make sure the licence lets you, without paying for a title you cannot serve.
๐ซ Four Ways Operators Get This Wrong
- Testing the game, not the page. A threaded build tested in isolation on a bare page passes. The same build on your live portal, next to your ad tag and consent script, is where the conflict happens. Test the composite.
- Treating blocked resources as a bug report. Nothing errors visibly. Diff your ad requests before and after adding a title, or you will attribute the drop to seasonality.
- Setting the headers site-wide to "unblock" one game. This is the single most expensive move available. One title's requirement becomes every page's policy, including pages with no game on them.
- Assuming a portal-hosted iframe insulates you. It does not, under COOP/COEP. Confirm what your embed actually inherits before you design around it.
๐ฏ Where a Licensed Catalogue Fits
This is a reason to be specific about build requirements when you license, not a reason to avoid engine-built games. Forestry Games has licensed HTML5 games since 2017, and questions like "does this title need cross-origin isolation" and "is there a single-threaded export" are answerable per title rather than guessed at after launch. If you are assembling a catalogue for a portal that has to monetize through ads, ask them before signature โ and if you are buying source code rather than a hosted licence, the build flags are yours to set, which is a genuine advantage. Operators sizing ad revenue against these constraints can work it through with our monetization team.
๐งญ What to Do This Week
Open your live portal, load a game, and read the response headers on the document that serves it. If you see Cross-Origin-Embedder-Policy, open the network panel and count how many third-party requests are being blocked โ then compare that count against the same page with the game removed. That single measurement tells you whether you are already paying for this and calling it something else.
If the headers are absent, you are fine today, and the job is to keep it that way: add "requires SharedArrayBuffer, yes or no" to your intake checklist for every title you license from here on. It is one field. It is cheaper to collect at signature than to discover in a quarterly revenue review, and unlike most due-diligence questions, this one has a definite answer that the licensor can look up in thirty seconds.


