In short: a site checks many small signals: what JavaScript reports, how the page renders, how the browser was started, how the user moves, and what the network connection looks like. One odd signal can be explained; signals that disagree with each other give a browser away. seleniumbase-rs answers each signal at the layer where it is read, and keeps the answers consistent.
The signals, layer by layer#
| Layer | What a site reads | Example of a giveaway |
|---|---|---|
| Network | IP address and its reputation, TLS ClientHello, HTTP/2 settings, header order | A datacenter IP; a JA3/JA4A fingerprint of the TLS handshake: versions, ciphers, extensions hash no real Chrome sends |
| Launch | Flags and the browser binary | Automation flags; chromedriver’s cdc_ markers in the page |
| JavaScript | navigator, Client Hints, permissions, plugins, the toString of functions | navigator.webdriver is true; HeadlessChrome in the user agent |
| Rendering | Canvas, WebGL vendor and renderer, audio, fonts, screen size | A software renderer; a screen size no monitor has |
| Behaviour | Mouse paths, typing rhythm, timing | Instant straight-line moves; perfectly even keystrokes |
| Coherence | Whether all of the above agree | A Berlin IP with a New York time zone and an English-only locale |
What detection code looks like#
A detection script runs in the page like any other script. It asks the browser questions and sends the answers home. These are simplified versions of real checks.
seleniumbase-rs hides navigator.webdriver, replaces HeadlessChrome in the
user agent (UC mode), fills plugins and window.chrome, and binary patching
removes the cdc_ markers.
With native spoofing on, replaced functions keep a native-looking toString,
so the replacement itself does not show.
A Fingerprint draws random values together (operating system, region,
locale), so they agree; keep the proxy’s country in line with them.
How a fingerprint is generated#
A fingerprint is not stored in your browser: the site computes it each visit from how your device renders and reports things, then hashes the results into one identifier that survives clearing cookies.
Canvas
WebGL
Audio
Fonts and screen
Hash it together
What seleniumbase-rs changes: canvas and audio noise (set in StealthPolicy)
make the canvas and audio results differ per identity; the WebGL vendor and
renderer, screen size, pixel ratio, hardware values, fonts, time zone and locale
come from the Fingerprint. With .seed(..) the same identity gives the same
results every run, so a site sees one consistent returning visitor instead of a
new one each time.
Where seleniumbase-rs answers#
Each layer has its own way to change what the site sees
Launch flags and binary patching
The browser is started with flags that leave out automation markers, and the
Chrome and chromedriver binaries can be patched so their tell-tale strings are
gone. UC mode sets up the session to avoid common bot checks, and replaces
HeadlessChrome in the user agent when running headless. See
Binary patching and UC mode.
DevTools overrides
Through the DevTools Protocol the crate sets the user agent, Client Hints, time zone, locale and geolocation for a page, so what JavaScript asks for comes from the browser itself, not from a patched function. See The DevTools Protocol.
Page script
Evasion providers inject script that runs before the page’s own scripts, for
values with no DevTools override (WebGL vendor, canvas and audio noise, plugins,
permissions). With native spoofing on, patched functions keep a native-looking
toString, so the patch itself is not a signal.
Behaviour
Humanized input moves the mouse along curved paths and types with uneven timing, instead of jumping and typing instantly.
Network
A proxy changes the IP the site sees, and the WebRTC policy keeps the real IP from leaking through WebRTC. A real Chrome already sends a Chrome TLS fingerprint; for plain HTTP requests made outside the browser, the stealth crates reproduce the same TLS and HTTP/2 fingerprint (see the codec API).
Keeping the answers consistent#
One Fingerprint describes the whole identity, and each setting is one Spoof:
Natural (the browser’s own value), Random, Value(..) or Off. A Random
value is drawn together with the rest (the same operating system, region and
locale), so a random locale agrees with a time zone you set. How the claims are
delivered (canvas and audio noise, native spoofing, WebRTC policy, granted
permissions) is a separate StealthPolicy. See
Fingerprints and
Design: fingerprint API v2.
No layer makes a browser undetectable. Each closes known signals; a site can look for new ones. The stealth scraping layer is experimental; see its limits.