Two ways to answer a challenge
A challenge widget is a program that runs in the browser, asks the browser questions and sends the answers to a server. An automated client can produce those answers in two ways. It can run the program in a real browser, such as a headless browser, which answers every question with its own engine. Or it can understand the program well enough to answer without running it: undo the obfuscation (see how deobfuscation works), decode the bytecode, then compute or replay each answer.
The second approach looks cheaper because there is no browser process. Its real cost is that it depends on the program's internals, and those are the part the challenge vendor changes most.
A public case: 49 hours
An open-source HTTP-only implementation for a widely deployed challenge widget was published on 25 October 2026: 43,314 lines of Rust, a deobfuscator with more than twenty passes, a symbolic interpreter for the widget's bytecode and one recorded iPhone whose answers it replays. Its documentation already marked "a new challenge build" as a non-retryable error.
The first new build arrived about 49 hours later. The fix changed 99 files, adding 8,976 lines and removing 5,602:
- Deobfuscation: six new passes and four removed, because the obfuscator switched its string-table scheme.
- Virtual machine: dispatcher rewritten, register handling added.
- New probes: a WebSocket echo that measures round-trip time (see latency-based proxy detection) and a worker that times fetches to the vendor's hosts.
- Recorded answers: the device profile re-recorded, about 2,500 lines, including a new header order for the WebSocket handshake.
Other public evidence points the same way: one browser project's bug tracker documented at least 31 distinct builds of another vendor's challenge script in October 2026, with a new probe appearing between two builds 23 minutes apart.
What each approach has to maintain
| Item | HTTP-only reimplementation | Real browser |
|---|---|---|
| Obfuscator transforms | A pass for each; new ones break the pipeline | Nothing; the engine runs the code |
| Per-session virtual machine | Recover handlers and opcodes every session | Nothing |
| Randomised field names, payload encoding | Map and re-encode per build | Nothing |
| New probes (latency, hash rate) | A recorded or modelled answer for each | Answered by the machine itself |
| Transport (TLS, HTTP/2, header order) | Impersonate per request kind | Native |
| Identity consistency | One replayed device in every session | Keep hardware, locale and network coherent |
Replay also has a ceiling no update fixes: one recorded device answers for every session from every IP, and each probe that measures something physical, such as latency or a proof-of-work hash rate, needs a fresh model of what that device would have measured.
Browsers cost memory and CPU and need fleet management, so the trade is real: pay for browser processes, or pay a code change every time the challenge ships a build. A managed web data API takes the browser side of that trade and runs the fleet, so the integration does not change when a challenge does.
