From clocks to hardware signatures
Transcendental math and pixel hashes identify the software stack; timing identifies the hardware. A script runs a fixed GPU draw or a WASM SIMD kernel and measures wall-clock duration: a real discrete GPU finishes a shader far faster than Chrome’s SwiftShader software renderer, and a real CPU’s cache hierarchy produces a Prime+Probe latency curve that an emulated environment does not. Academic side-channel work (cache attacks, GPU timing) showed these measurements can even infer what other tabs or processes are doing — which is why browsers coarsened performance.now() and gated SharedArrayBuffer behind cross-origin isolation after Spectre.
Why headless browsers fail timing checks
Headless browsers on GPU-less servers fall back to software rendering. A draw that takes ~2 ms on a real GPU might take 50–200 ms in SwiftShader — a giant, obvious tell. Anti-bots that pair a canvas probe with a timing probe can catch a replayed canvas hash: the pixels look real but the render took software-renderer time. The same logic flags WASM workloads that run at emulated speed. There is no JavaScript fix; you need real (or GPU-accelerated) hardware to produce real timings.
Why timing is hard to fake — and what works
Timing side-channels are powerful precisely because they read the real hardware underneath the browser. Even with performance.now() resolution deliberately coarsened to defend against Spectre, the relative cost of operations — cache hits versus misses, JIT warm-up, GPU draw timing — reflects the actual CPU and memory you are running on. You cannot convincingly fake those ratios from JavaScript, because the code you add to fake them also takes measurable time.
So the practical answer is to run on hardware whose timing profile matches the identity you present, rather than to spoof clocks. A datacentre VM running headless Chrome behind a residential User-Agent has a timing signature that does not match a real consumer laptop. Residential and real-device infrastructure — the kind a managed web scraping API runs behind — produces genuine timing characteristics instead of trying to forge them.
