Expand description
Chromium anti-detection (stealth) overrides.
Headless Chromium is trivially identifiable from JavaScript:
navigator.webdriver === true, no plugins, English-only languages,
Notification.permission === 'denied', WebGL vendor reports
“Google Inc. (NVIDIA)”, and so on. Modern WAFs (Cloudflare, Akamai,
PerimeterX/HUMAN, DataDome) check these signals and immediately
tag the visitor as a bot — no amount of “realistic mouse movement”
will recover from a navigator.webdriver === true answer.
apply_stealth(page) injects a CDP Page.addScriptToEvaluateOnNewDocument
that overrides each of the well-known fingerprint surfaces BEFORE
any page-side script can read them. It must be called once per
chromiumoxide::Page before the first goto() — not after.
What this fixes:
navigator.webdriverreturnsundefinedinstead oftruenavigator.pluginsreports a plausible PDF plugin listnavigator.languagesreturns["en-US", "en"]instead of[]Notification.permissiondoesn’t lie about being deniedwindow.chromeis faked to look like a real Chrome browser- WebGL vendor/renderer report a normal “Intel Inc. / Intel Iris OpenGL Engine” instead of leaking the headless GPU surface
screen.width/heightset to plausible desktop values when running with--window-size=...
What this does NOT fix:
- User-Agent string. Your
chromiumoxide::Browserconfig controls that — set it to a real Chrome UA, NOTHeadlessChrome/.... - TLS fingerprint (JA3/JA4). That requires a different chromium build or a network-layer proxy. Out of scope here.
- IP reputation. Use residential proxies if your traffic gets blocked by ASN.
- Realistic mouse trajectories. That’s
crate::behavior’s job; stealth and behavioural simulation are complementary, not alternatives — Cloudflare scores BOTH.
Production deployments should call apply_stealth(page).await?
immediately after Browser::new_page("about:blank").await? and
before navigating to the protected resource. See PRODUCTION.md.
Functions§
- apply_
stealth - Inject the stealth overrides into every new document on
page. Call ONCE perPage, BEFORE anypage.goto(...).