Browser Anti-Detection (Part 2): GPU Pipelines, Keystroke Entropy, and Client Hints

Input event entropy, GPU rendering pipeline differences, Client Hints headers, CDP Runtime detection — sites still checking navigator.webdriver in 2026 are years behind.

16Yun Engineering TeamApr 6, 20264 min read

Do Classic Detection Signals Still Work in 2026?

Direct answer: Individual signals are mostly dead. Combined signals are what matter.

navigator.webdriver — defeated in 2018 by puppeteer-extra-plugin-stealth. window.chrome missing — patched by stealth plugins in 2020. Plugin array empty — patched in 2019. WebGL VENDOR/RENDERER — stealth plugins override getParameter return values. User-Agent — replaced by the Client Hints system.

Every static property check has a stealth plugin counter. Detection in 2026 has moved to signals that cannot be bypassed by simple property overrides.

Signal 1: Input Event Entropy

This is the most reliable single signal. Real human input — even very fast input — produces event streams with predictable physical characteristics.

Mouse movement: Human mouse movement isn't straight. Each movement has microscopic jitter, acceleration curves follow Fitts' law. CDP-driven mouse movement, even with stealth plugins, produces synthesized events:

  • CDP synthesized: integer-pixel coordinates, perfectly straight or curved trajectories, identical inter-event timing
  • Real human: sub-pixel coordinates, trajectory jitter, velocity varying by distance

Keyboard input: Real typing has key dwell times varying between 30-120ms. Different keys have different dwell times (space is usually shorter than letters). CDP's keyDown/keyUp events either have perfectly uniform timing or are too random — lacking the natural distribution of human typing.

The specific detection rule: a session performing meaningful actions (login, checkout, payment) without preceding mouse movement is 99% bot.

Detection logic (pseudocode):
if session has meaningful_action (login/checkout/submit):
    if mouseMoveCount == 0:
        return "bot - no mouse movement before action"
    if mouseMoveEntropy < threshold:
        return "bot - insufficient movement entropy"
    if keyDwellStdDev < threshold:
        return "bot - keystroke timing too uniform"

Signal 2: GPU Rendering Pipeline

Headless Chrome's GPU pipeline differs from headful Chrome's, even with --use-gl=swiftshader or hardware acceleration emulation.

Specific differences:

Canvas subpixel text positioning. The same text rendered headless vs. headful produces systematically different subpixel positions. Stable and predictable. Detection systems maintain a hash table of "known Canvas rendering values → CDP-driven Chrome."

Bezier curve aliasing patterns. Canvas path rendering produces characteristic aliasing differences between headless and headful modes.

WebGL readPixels output. Reading pixels from a controlled scene produces different byte-level output between modes.

Stealth plugins don't touch the GPU pipeline because modifying GPU output requires swapping the renderer — which itself produces detectable inconsistencies.

Signal 3: Client Hints

Chrome's User-Agent Reduction project has fundamentally changed how browsers identify themselves. The old UA string Mozilla/5.0 (Windows NT 10.0; ...) has lost most of its information value. Chrome now sends minimal default Client Hints headers:

Sec-CH-UA: "Google Chrome";v="124", "Chromium";v="124"
Sec-CH-UA-Mobile: ?0
Sec-CH-UA-Platform: "Windows"

If the server wants more, it sends Accept-CH in its response. Chrome decides whether to comply:

Accept-CH: Sec-CH-UA-Arch, Sec-CH-UA-Full-Version-List, Sec-CH-UA-Model

For detection systems:

  • Old UA spoofing is insufficient — Client Hints must match the claimed browser version
  • If Sec-CH-UA claims Chrome 124 but browser behavior matches Chrome 130, inconsistency is detected
  • High-entropy values (platform, architecture, device model) must align with other fingerprint signals

Signal 4: CDP Runtime Detection

Even with all stealth patches applied, Chrome DevTools Protocol leaves a small but measurable runtime signature.

The technique: call console.debug with a %c-formatted argument inside a getter that's accessed during DevTools attachment. This produces a ~0.3ms measurable timing delta when DevTools is attached — which CDP fundamentally is.

This signal needs re-validation every few months — Chromium's CDP team patches known detection techniques. As of mid-2026, multiple variants still work.

Scoring, Not Blocking, Is The Key

Individual signals all have false positives:

  • Touch device users have zero mouse events
  • Some GPUs behave abnormally in headless mode
  • VPN users may trigger suspicious patterns

The correct approach is score-based gating:

score = calculate_automation_score(input_entropy, gpu_pipeline, client_hints, cdp_signal)
 
if score < 0.3:
    action = "allow"
elif score < 0.6:
    action = "step_up"  # CAPTCHA or email confirmation
elif score < 0.9:
    action = "hard_challenge"  # honeypot or 2FA
else:
    action = "block"

What This Means for Automation

If you maintain browser automation pipelines, the 2026 reality is:

Transport layer fingerprints (Part 1) and application-layer behavioral signals (this article) combine to create a detection surface that's harder to bypass than ever. Stealth plugins alone aren't enough. C++ engine-level anti-detection alone isn't enough. What's needed is consistency across transport, application, and behavioral layers.

The next article analyzes why consistency matters most: why long-lived stable environments survive longer than aggressive rotation.

Need an enterprise proxy plan?

We can tailor architecture to your target domains, concurrency, and reliability goals.