Why Anubis Rewrote Its Bot Check in WebAssembly

Anubis now runs its proof-of-work bot check in WebAssembly. It took a year — and the reason is a lesson for anyone shipping WASM.

Share

If you've ever hit a "making sure you're not a bot" page on a self-hosted code forge and watched a progress bar tick up — that was probably Anubis. The project just announced its proof-of-work challenge now ships as WebAssembly. The interesting number isn't in the feature list. It's in the title: it took a year.

One compile target, three browser engines, twelve months. That ratio is today's lesson, whether you ship anti-bot gates or anything else in WASM.

Why this matters

Scraping has gone from nuisance to line item. LLM crawlers will happily pull every page of your docs, wiki, or forum. Managed challenges from Cloudflare work until you want control, privacy, or zero cost — at which point Anubis is the default self-hosted answer. Its WASM rewrite is the biggest change to how it works since launch, and a preview of what "compile once, run everywhere" actually costs in 2026.

How it works

Anubis hands each visitor a small hash puzzle: find a nonce so that SHA-256 of the challenge plus that nonce has N leading zero bits. Solve it, get a cookie, get through. Difficulty scales with how sketchy the request looks.

The JavaScript version had two problems. Hashing in JS is interpreter-bound, so the same difficulty felt instant in Chrome and glacial in old Safari. And a bot could read the loop in DevTools, patch it, and skip the work entirely.

WASM fixes both. The hash loop compiles to near-native speed that's roughly identical across browsers, so difficulty finally means the same thing for everyone. Real users finish in milliseconds. Bots have to actually execute the module instead of editing a function they just read.

Where this helps

  • Public docs and wikis being vacuumed into training sets — proof-of-work multiplies the CPU cost of every fetched page.
  • Community forges and forums drowning in AI signups — drop Anubis in front of the reverse proxy, no accounts required.
  • Unauthenticated internal tools — status pages, dashboards — where a speed bump beats a login wall.

Watch out

WASM is a speed bump, not a wall. A determined scraper runs the module headlessly and pays the CPU bill. You're raising cost per page, not making scraping impossible — and every notch of difficulty also burns battery on real visitors' old phones.

That year-long timeline is the other warning. Browser WASM still has sharp edges: Safari quirks, CSP headers that forget wasm-unsafe-eval, compile time on cheap Androids. Budget QA time across all three engines, not just your daily driver.

Decide your fail behavior before launch. Users with JS off, and some accessibility tooling, cannot solve a challenge at all. Fail open for them or fail closed — but choose on purpose.

Try it yourself

docker run --rm -p 8923:8923 ghcr.io/techaro/anubis:latest
# open http://localhost:8923 and solve the gate
# peek at the challenge page it serves:
curl -s http://localhost:8923 | head -50

TL;DR

  • Anubis's proof-of-work bot gate now runs its challenge in WebAssembly — after a year of work for one compile target.
  • Uniform near-native speed across browsers means difficulty finally measures the same thing for everyone; bots pay real CPU per page.
  • Run the Docker image locally today, then pick your difficulty and fail-open policy before pointing it at prod.