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. There are two ways to produce those answers automatically. One is to run the program in a real browser, which answers every question with its own engine. The other is to understand the program well enough to answer its questions without running it: deobfuscate the script, decode its bytecode, compute or replay each answer, and encode the payload yourself.
The second approach is attractive because it needs no browser process, which is cheaper in memory and CPU. Its cost is that it must understand the program, and the program changes.
A public case: 49 hours
An open-source browserless solver for a widely deployed challenge widget was published on 25 October 2026. It is a careful piece of work: 43,314 lines of Rust in its source tree, a deobfuscator with more than twenty transformation passes, a symbolic interpreter for the widget's bytecode, and one recorded iPhone whose answers it replays. Sixteen minutes after publishing, its author changed the README so that the error for "a new challenge build" is marked as not retryable.
The first new build arrived two days later. The commit titled "fix for new build" on 27 October changed 99 files, adding 8,976 lines and removing 5,602, about 49 hours after the first release, followed by a three-file bug fix 35 minutes later. What changed:
- Deobfuscation: six new passes (cached-string inlining, call helpers routed through
Function.prototype.call, merged functions behind a selector, register arrays, state machines, arrow-function blocks) and four removed, because the obfuscator had switched its string-table scheme. - The virtual machine: the dispatcher rewritten and register handling added.
- New probes: a WebSocket echo that measures round-trip time and a worker that times fetches to the vendor's hosts, both present only in some builds from that day on.
- Recorded answers: the device profile re-recorded, about 2,500 lines changed, including a new header order for the WebSocket handshake.
- Tests: the tests for the old deobfuscator and virtual machine deleted rather than migrated.
Other evidence points the same way. A Firefox-based browser's bug tracker documented archived copies of another vendor's challenge script in October 2026: a new probe appeared between two builds 23 minutes apart, and the archive held at least 31 distinct builds.
What a browserless solver has to track
- The obfuscator. Each transform the script uses needs a pass that undoes it, and new transforms break the pipeline.
- The virtual machine. The script defines a register machine whose handlers, opcodes and masks vary per session; the solver must recover them symbolically every time.
- Names. Field names and states are randomised per build, so a vocabulary maps each session's names to a reference build by aligning the strings that stay stable.
- The payload encoding. One algorithm, but a per-session base64 alphabet, RSA modulus and key secret, with deflate, XTEA and textbook RSA.
- The probes. Every probe needs either a recorded answer from a real device or a computation that reproduces what a browser would measure, including timing, clocks and network behaviour.
- The transport. Header order per request kind, TLS and HTTP/2 settings and request timing; see header order depends on the request.
Each item is a separate way to fall behind. A build that changes any of them stops the solver until someone updates it, and the update requires recordings from a real browser anyway.
What a browser avoids, and what it does not
A real browser needs no update when the widget changes. It runs the new script, opens the new WebSocket, answers the new probe from its engine and sends whatever the new code encodes. The maintenance burden moves from tracking the challenge to something more stable: making sure the browser's own identity is consistent, which is the subject of most of this hub, from anatomy of a browser fingerprint to cross-realm coherence.
Replay also has a ceiling that no update fixes. A solver that replays one recorded device presents that device's answers in every session, from every IP, and each new probe that measures something physical, such as latency or hash rate, needs a fresh model of what that device would have measured. A browser on a real machine produces those values by running.
The costs are real on both sides. A browser process needs memory and CPU, and a fleet of them needs management. The trade is between paying that cost and paying a code change every time the challenge ships a build, measured here at 14,578 changed lines in two days.
The through-line
Challenge code changes quickly and on purpose; engines change slowly and in public. Building on the engine and controlling identity where the engine produces it, the approach behind Clearcote and described in how a stealth browser is built and verified, puts the moving target on the other side. The probes the widget collects are listed in inside a challenge widget.
