Where the flag comes from
The WebDriver standard requires a conforming automation session to set navigator.webdriver to true so that pages can tell they are being driven. Chrome sets it when launched with the --enable-automation switch or controlled via the DevTools Protocol; Firefox sets it under Marionette; every mainstream automation framework triggers it by default. On a normal human browser session it is false.
That makes it a perfect first-pass filter: one line, if (navigator.webdriver) flag(), catches every scraper that has not specifically dealt with it - which is a surprising number, because many tutorials never mention it.
Why naive hiding gets caught anyway
The obvious fix is to overwrite the property: Object.defineProperty(navigator, "webdriver", { get: () => false }). This makes the value read false, but it introduces new, detectable artifacts:
- The getter is now a JavaScript function.
Object.getOwnPropertyDescriptor(navigator, "webdriver").get.toString()returns the patch source instead of"[native code]"- caught by Function.toString() inspection. - On real Chrome,
webdriverlives onNavigator.prototype, not as an own-property of thenavigatorinstance. Defining it on the instance changes where it appears in the prototype chain - itself a tell. - If the patch runs after page scripts, there is a race where the real value is briefly observable.
So spoofing the value with JavaScript trades one obvious signal for a subtler one. The clean fix is to launch the browser so the flag is never set - excluding the enable-automation switch - or to patch at the engine level so the property reads false natively.
Necessary but not sufficient
The most important thing to understand about navigator.webdriver is its place in the detection stack: it is the floor, not the ceiling. Passing it means you are not in the bottom tier of trivially-detectable bots. It tells a vendor nothing reassuring - real users pass it too - so failing it is fatal but passing it earns you nothing. Serious anti-bot systems (Kasada, DataDome, Akamai) treat it as a checkbox and move on to TLS fingerprints, canvas/WebGL/audio coherence, behaviour, and the harder probes.
This is why tooling that only hides navigator.webdriver (some minimal stealth scripts) still gets blocked everywhere that matters. The flag is the first gate; the real contest is the coherent fingerprint behind it. Engine-level browsers launch with the flag genuinely absent and harden the rest.
