A neutral, detection-side listicle of the 12 signals — TLS, canvas noise, fonts, UA-CH, and more — that separate a real browser from an anti-detect profile.
An anti-detect browser and a real browser can send the same user-agent string and still look nothing alike to a detection stack. The gap isn't any single header or API — it's coherence: a real device is one integrated system, and a spoofed profile is a patchwork of substituted values that rarely agree with each other end to end. This is a detection-side rundown, not an evasion guide: 12 concrete signals that detection systems check today, grouped by the layer they operate on, and what each one reveals when a claimed identity doesn't match the traffic behind it.
Key Takeaways
- Detection rarely relies on one signal — it scores whether dozens of independent values are coherent with each other, not just whether any single one looks fake.
- Network-layer signals (TLS handshake, HTTP/2 frames) are checked before a page even loads, and are invisible to JavaScript-level spoofing tools.
- Rendering signals (canvas, WebGL, fonts) come from real hardware and drivers, which makes them the hardest layer to fake convincingly.
- Identity signals (UA-CH, timezone, locale) are cheap to check and catch the most common, least careful spoofing attempts.
- No current anti-detect setup passes every layer at once — fixing one mismatch usually surfaces another.
The 12 Signals, at a Glance
| # | Signal | What a real browser shows |
|---|---|---|
| 1 | TLS ClientHello (JA3/JA4) | Matches the claimed browser's TLS library exactly |
| 2 | HTTP/2 frame & header order | Matches the claimed browser's stack, not a scripting library |
| 3 | Canvas noise test-retest | Identical hash across repeated draws in the same page load |
| 4 | WebGL renderer vs. parameters | GPU string agrees with extensions, precision, texture limits |
| 5 | Font list vs. GPU/OS | Font set matches the claimed operating system |
| 6 | Screen, touch, hardware concurrency | Device class (phone, laptop, desktop) is internally consistent |
| 7 | UA-CH vs. legacy User-Agent | navigator.userAgentData exists only on Chromium, and agrees with the UA string |
| 8 | Timezone vs. IP geolocation | Local timezone matches the region the IP resolves to |
| 9 | Locale / Accept-Language vs. IP | Browser language matches the visitor's apparent region |
| 10 | navigator.webdriver and automation residue | Absent, with no CDP or driver artifacts in the global scope |
| 11 | Property descriptor / prototype integrity | Native API .toString() output and prototype chain are untouched |
| 12 | Headless rendering anomalies | Consistent permissions states, full codec list, no software-only GPU |
Network-Layer Signals
1. TLS ClientHello — JA3/JA4
Before a page loads, your browser negotiates HTTPS with a ClientHello message that lists cipher suites, extensions, and elliptic curves in an order dictated by the TLS library, not by any setting you control. JA3 and JA4 hash that message into a stable fingerprint tied to the underlying library — BoringSSL for Chromium, NSS for Firefox. An anti-detect browser that spoofs its user-agent as "Firefox" but is a Chromium fork under the hood still hands over a Chromium TLS handshake, because changing the ClientHello requires swapping the TLS library itself, not the JavaScript layer. See TLS fingerprinting explained for how JA3 and JA4 are computed and why GREASE — reserved dummy values defined in RFC 8701 — complicates naive fingerprint matching.
2. HTTP/2 Frame and Header Fingerprint
One layer up, HTTP/2 connections carry their own tell: SETTINGS frame values, stream-priority behavior, and pseudo-header ordering (:method, :path, :authority) differ between browser engines and HTTP client libraries. A profile that gets its TLS handshake right but is driven by an automation library underneath can still leak a mismatched HTTP/2 fingerprint, because the two layers are implemented by different code paths and rarely patched together.
Rendering Signals
3. Canvas Noise Test-Retest Variance
Canvas fingerprinting reads subtle pixel differences that come from real GPU and driver behavior — and that output is deterministic for a given device: drawing the same shapes twice in one page load produces an identical hash. Anti-detect tools defend against canvas tracking by injecting random noise per render call, but that noise itself is detectable: draw the same canvas twice and compare. A real browser always matches; a per-call noise injector produces two different hashes with high probability. The EFF's Cover Your Tracks project documents how canvas uniqueness is measured in the wild.
4. WebGL Renderer String vs. Everything Downstream
The unmasked WEBGL_debug_renderer_info extension exposes the real GPU vendor and renderer string. Substituting a plausible-looking string is easy; making every parameter that depends on that GPU agree with it is not — supported extensions, maximum texture size, and shader precision are all tied to the actual hardware doing the rendering, not to the string a script claims. A mismatch between the claimed GPU and the rendered pixel output is one of the strongest tells available, because faking it requires simulating an entire GPU's behavior, not just overriding one property.
5. Font List vs. GPU/OS Coherence
Installed fonts are largely determined by the operating system: Windows ships Segoe UI and Calibri, macOS ships San Francisco and Helvetica Neue, and each Linux distribution has its own defaults. A profile claiming macOS with a Windows font list — or a GPU renderer string that only ships on Windows paired with an Apple-only font set — fails a coherence check without needing to know what the "correct" fingerprint should look like.
6. Screen, Touch, and Hardware Concurrency
A device's screen dimensions, touch-event support, and reported CPU core count should all describe the same class of hardware. A "mobile Safari" identity with no touch events and a desktop-class core count doesn't match any real iPhone. These are cheap checks, which is exactly why crude spoofing tools still get caught on them.
Identity Signals
7. UA-CH vs. Legacy User-Agent
Chromium browsers expose structured User-Agent Client Hints through navigator.userAgentData — a JavaScript-readable object that either exists (Chromium) or doesn't (Firefox, Safari), regardless of what the legacy user-agent string claims:
// Chromium: returns an object. Firefox/Safari: undefined — no matter the spoofed UA string.
console.log(navigator.userAgentData);
A "Safari" identity that exposes a populated userAgentData object is definitively running Chromium underneath. This is one of the fastest checks in the detect-user-agent-spoofing playbook — see how sites detect user-agent spoofing for the full set of header- and client-hint-level tells.
8. Timezone vs. IP Geolocation
Every browser exposes its local timezone via Intl.DateTimeFormat().resolvedOptions().timeZone. Detection systems compare that value against the timezone the visitor's IP address geolocates to. A profile claiming to browse from Tokyo while reporting America/New_York as its local timezone is an immediate red flag — and one that's cheap to correct, which is why sloppier anti-detect configurations still slip on it.
9. Locale and Accept-Language vs. IP Region
Similarly, the Accept-Language header and navigator.language should broadly agree with the region an IP resolves to. A residential IP in Vietnam paired with an Accept-Language: ru-RU header isn't impossible — real travelers and expats exist — but it raises the same kind of suspicion score as a timezone mismatch, especially stacked with other inconsistencies.
Automation and Tamper Signals
10. navigator.webdriver and Automation Residue
When a session is driven by the WebDriver protocol, the standardized navigator.webdriver property is set to true. Beyond that single flag, automation frameworks leave residue in the global scope — injected CDP artifacts, unusual window properties, and driver-specific variables that a naive spoofing layer forgets to clean up. See bot detection techniques for the fuller list of automation tells beyond this one property.
11. Property Descriptor and Prototype Integrity
Anti-detect browsers alter fingerprint values by intercepting APIs at the prototype level — reassigning HTMLCanvasElement.prototype.toDataURL or wrapping WebGLRenderingContext.prototype.getParameter. A native method's .toString() returns "function toDataURL() { [native code] }"; a naively patched one often doesn't, and Object.getOwnPropertyDescriptor() can reveal the substitution even when sophisticated tools try to synthesize a convincing native-code marker.
12. Headless Rendering Anomalies
Headless and virtualized browser environments render pages differently from ordinary desktop sessions: a permissions API that reports contradictory states, a truncated media codec list, or a WebGL renderer string that resolves to a software rasterizer like SwiftShader instead of real GPU hardware. None of these require comparing against a claimed identity — they're internally inconsistent on their own.
What Spoofing Can and Cannot Hide
Spoofing a single attribute — a user-agent string, a canvas hash, a timezone — is trivial. Making all twelve of these signals agree with each other, continuously, across browser and OS updates, is a different problem entirely. This is the same coherence principle behind browser fingerprinting itself, just read in reverse: instead of measuring how unique a fingerprint is, detection systems measure how internally consistent it is. The signals that are cheapest to fix — timezone, locale, the legacy UA string — get fixed first by any competent operator. The signals anchored in hardware and network stacks — TLS library, GPU-rendered output, JavaScript engine behavior — are the ones that remain a durable tell, because faking them means replacing the actual component that produces them, not just the value it reports.
Check Your Own Setup
BrowserInsight's fingerprint check surfaces your Canvas hash, WebGL renderer string, and font list side by side, and the bot detection tool shows the automation and headless signals a detection system would score. If you run a multi-profile or privacy-hardened setup, checking both is the fastest way to spot which of the twelve signals, if any, disagrees with the identity you're presenting.
Frequently Asked Questions
Is any single signal enough to prove a browser is spoofed?
Rarely on its own. Detection is probabilistic — each mismatch raises a suspicion score, and systems combine many signals rather than relying on one absolute check. A determined operator can fix any individual signal; fixing all twelve simultaneously, and keeping them fixed through updates, is the hard part.
Which of these 12 signals is hardest to fake?
The rendering and network signals — WebGL output, canvas test-retest consistency, and the TLS handshake — because they're produced by hardware, drivers, and TLS libraries rather than by values a script can simply overwrite. Faking them convincingly means replicating an entire component's real behavior, not editing one property.
Do VPNs or proxies affect any of these signals?
Indirectly, through timezone and locale mismatches if the exit location doesn't match the browser's configured locale — but an ordinary tunneling VPN doesn't touch TLS, canvas, WebGL, or UA-CH, since those are computed by the browser itself, not the network path. See how websites detect VPNs and proxies for the network-layer checks that run alongside these.
Is using an anti-detect browser illegal?
No. Anti-detect browsers have legitimate uses — managing multiple storefronts, running parallel ad accounts under platform terms that allow it, and privacy-conscious browsing. The tool is neutral; detection systems care about whether the signals it produces are internally coherent, not about the operator's intent.
Recommended Reading
- Browser Fingerprinting Explained: How to Protect Your Privacy
- TLS Fingerprinting Explained: How JA3/JA4 Identify Your Client
- Bot Detection Techniques: How to Identify Bots and Crawlers
- How to Detect User-Agent Spoofing (and Why It's Easy to Spot)
- How Sites Detect Anti-Detect Browsers and Fingerprint Spoofing


