We Run KataGo in the Browser — After Shipping It Broken
Description and use
By isolating the entire subdomain and ensuring COOP/COEP headers, KataGo runs at all difficulty levels in the browser, providing a superhuman AI while maintaining a safe fallback. The change required minimal cost once the isolation issue was understood.
Problem
KataGo, a superhuman Go engine compiled to WASM, could not run in the browser because it requires OS threads and thus SharedArrayBuffer, which in turn requires the document to be cross‑origin isolated. The initial integration failed silently, leaving the engine unused while the fallback engine continued to serve games.
Outcome
By isolating the entire subdomain and ensuring COOP/COEP headers, KataGo runs at all difficulty levels in the browser, providing a superhuman AI while maintaining a safe fallback. The change required minimal cost once the isolation issue was understood.
Workflow
- 1. Ship KataGo v1.18.2 compiled with Emscripten 3.1.64 to WASM, lazy‑loading 13.4 MB (b10) or 6.1 MB (b6) neural nets.
- 2. Attempt to run KataGo in a child iframe with COOP/COEP headers; the iframe reports crossOriginIsolated = false, so KataGo aborts silently.
- 3. Identify that crossOriginIsolated is a top‑level document property; isolation does not propagate to iframes.
- 4. Configure the entire covay subdomain with COOP: same‑origin, COEP: require‑corp, CORP: same‑origin headers via next.config.ts.
- 5. Audit cross‑origin loads; add crossOrigin="anonymous" to avatar images from Supabase to satisfy COEP.
- 6. Verify isolation with a probe suite: 37/37 checks pass, KataGo serves moves at all levels.
- 7. Implement runtime checks: if self.crossOriginIsolated is false or SharedArrayBuffer is undefined, skip KataGo and use legacy stack.
- 8. Calibrate device with a 40‑visit probe to set search depth per difficulty level.
- 9. Degrade gracefully: reduce visits, halve threads, switch to smaller net, then fallback if necessary.
- 10. Enforce legality checks and watchdogs to handle worker deaths and resignations.
- 11. Deploy and monitor; KataGo now powers all levels while legacy stack remains available for browsers that cannot isolate.
Evidence
KataGo had never played a single move. Every game, at every level, had been silently served by the old engine — which played well enough that nobody noticed.
KataGo cannot run without OS threads.
Emscripten pthreads in a browser means SharedArrayBuffer, and SharedArrayBuffer means the document must be cross-origin isolated: Cross-Origin-Opener-Policy: same-origin plus Cross-Origin-Embedder-Policy: require-corp.
crossOriginIsolated is a property of the top-level document. An iframe does not become cross-origin isolated because it was served with COOP/COEP headers if its parent page is not isolated.
After the flip, the production probe suite passed 37/37 checks: the document reports crossOriginIsolated === true, real KataGo serves moves and hints at all levels, and the fallback stack still works under isolation.
- Record date: 2026-11-01T05:13:48.170Z