What Is a Selenium Browser Fingerprint?
A Selenium browser fingerprint is the set of tell-tale signals — the navigator.webdriver flag, missing browser plugins, CDP traces, and inhumanly consistent timing — that anti-bot systems read to tell a Selenium WebDriver session apart from a real person clicking around in Chrome or Firefox. Out of the box, an unpatched Selenium instance broadcasts several of these signals at once, which is why so many scraping, testing, and automation scripts get blocked within the first few page loads.
Selenium was built for browser testing, not for staying invisible. Every action it takes — launching the driver, injecting JavaScript, controlling clicks — leaves traces in the DOM, the navigator object, and the browser’s own internals. Detection vendors like DataDome, PerimeterX, Cloudflare Bot Management, and Google’s reCAPTCHA all maintain lists of these traces and check for them automatically. Understanding what they look for is the first step toward either patching Selenium enough to pass casual checks, or recognizing when it’s time to switch to a tool that doesn’t need patching at all.
How Websites Detect Selenium Automation
Detection happens in layers. A site might start with a single JavaScript check and escalate to full behavioral analysis if the first pass looks suspicious. Here are the eight most common vectors.
1. The navigator.webdriver Property
This is the single most reliable Selenium indicator, and it requires no special library to check.
navigator.webdriverreturnstruein a default Selenium session- Real browsers return
undefinedorfalse - A single line of JavaScript detects it instantly
if (navigator.webdriver === true) {
console.log('Automation detected');
// Block, challenge, or silently serve fake data
}
2. Chrome and ChromeDriver Artifacts
Selenium’s ChromeDriver leaves its own markers behind:
window.chromeexists in real Chrome but is often missing or incomplete under Seleniumwindow.chrome.runtimeis absent in automated sessions- ChromeDriver injects specific global variables that scripts can enumerate
- The Chrome DevTools Protocol (CDP) endpoint that Selenium talks to leaves its own footprint (more on this below)
3. Plugin, Extension, and MimeType Gaps
Selenium sessions almost always look under-furnished compared to a browser a real person has used for months:
navigator.plugins.length === 0is a strong red flag — real desktop Chrome ships with a built-in PDF viewer plugin- Most real users have accumulated a handful of extensions; a completely clean profile is unusual
navigator.mimeTypesshows the same emptiness pattern
4. Language and Locale Mismatches
navigator.languagesis sometimes empty or inconsistent withnavigator.language- The Accept-Language HTTP header can disagree with the JavaScript-reported locale
- Timezone and Intl API values can clash with the claimed geography
5. Permissions API Inconsistencies
- Querying the Permissions API for notifications or geolocation behaves differently in Selenium than in a real Chrome profile
- A default Selenium profile has no permission history, so every prompt behaves like a fresh install, every time
6. User-Agent and Platform Mismatches
- A User-Agent string that claims Windows while
navigator.platformreports Linux, which is common on cloud scraping servers - Headless Chrome has its own User-Agent tell, though this is less common now that Selenium usually runs headed or with modern headless mode
- Screen resolution and available color depth that don’t match any real device
7. Behavioral Signals
Even a perfectly patched fingerprint gets caught by behavior:
- Mouse movement: Selenium’s native click() jumps straight to the element with no path at all, while real cursors arc, overshoot, and correct
- Typing speed: send_keys() can type faster and more evenly than any human
- Scroll patterns: programmatic scrollTo() calls land on exact pixel values; humans scroll in uneven bursts
- Timing consistency: identical delays between actions across sessions is itself a signature
8. Canvas, WebGL, and Audio Fingerprint Peculiarities
- Canvas rendering in headless or virtualized environments often produces a hash that matches known automation signatures
- WebGL renderer strings can reveal a software rasterizer or a cloud GPU instead of consumer hardware
- AudioContext fingerprints generated inside virtual machines cluster together in ways detection vendors have already catalogued
These same signals matter well beyond Selenium. They’re exactly what a solid browser fingerprinting protection strategy needs to account for, and canvas fingerprinting in particular is one of the hardest signals to fake convincingly with software patches alone.
Advanced Detection Techniques Anti-Bot Vendors Use
Basic checks catch careless scripts. Enterprise anti-bot vendors go further, layering in protocol-level and timing-based checks that are much harder to patch around.
CDP (Chrome DevTools Protocol) Detection
Selenium 4 controls Chrome through CDP by default, and that protocol channel leaves detectable traces:
- CDP’s runtime domain injects properties that a determined script can enumerate
- Specific CDP commands, such as Page.addScriptToEvaluateOnNewDocument, create observable side effects in the execution context
- Some anti-bot vendors fingerprint the CDP binding itself rather than any single property it sets
iframe Content Window Testing
- Selenium and real browsers handle iframe execution contexts slightly differently
- contentWindow properties on cross-origin iframes can reveal automation
- Switching between frame contexts programmatically is detectable through timing
Performance and Navigation Timing
- performance.timing and the Navigation Timing API can show implausibly fast page construction
- Real page loads have variable network and render delays; automated loads are often too clean
- Missing intermediate timing events, the small gaps a human’s slower device would introduce, stand out statistically across thousands of sessions
How to Make Selenium Harder to Detect
None of this makes Selenium useless. It just means you need to actively work against its defaults instead of relying on them. These are the standard mitigations, roughly in order of effort.
Basic Stealth Techniques
Remove the WebDriver property and automation flags:
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
options = Options()
options.add_argument('--disable-blink-features=AutomationControlled')
options.add_experimental_option('excludeSwitches', ['enable-automation'])
options.add_experimental_option('useAutomationExtension', False)
driver = webdriver.Chrome(options=options)
driver.execute_cdp_cmd('Page.addScriptToEvaluateOnNewDocument', {
'source': 'Object.defineProperty(navigator, "webdriver", {get: () => undefined})'
})
Spoof a realistic User-Agent:
options.add_argument('user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36')
Use a maintained stealth library instead of patching individual properties by hand:
pip install selenium-stealth
from selenium_stealth import stealth
stealth(driver,
languages=['en-US', 'en'],
vendor='Google Inc.',
platform='Win32',
webgl_vendor='Intel Inc.',
renderer='Intel Iris OpenGL Engine',
fix_hairline=True,
)
Advanced Anti-Detection Measures
Match a common real-world window size:
driver.set_window_size(1920, 1080)
Add human-like delays between actions:
import random
import time
def human_delay():
time.sleep(random.uniform(0.5, 2.0))
element.click()
human_delay()
Simulate mouse movement instead of jumping straight to the target:
from selenium.webdriver.common.action_chains import ActionChains
actions = ActionChains(driver)
actions.move_to_element(element)
actions.pause(random.uniform(0.1, 0.5))
actions.click()
actions.perform()
Carry over cookies and storage from a real browsing session so the profile doesn’t look freshly minted:
cookies = json.load(open('cookies.json'))
for cookie in cookies:
driver.add_cookie(cookie)
Why Selenium Stealth Techniques Eventually Fail
Patched Selenium can pass casual checks. It rarely survives sustained scrutiny from a dedicated anti-bot vendor.
Persistent Detection Vectors
- Version lag: ChromeDriver releases trail real Chrome releases, so version mismatches are a recurring tell
- CDP traces: as long as Selenium controls the browser through CDP, some signature of that control channel exists
- Behavioral drift: scripted delays and movement patterns still cluster statistically, even when individually randomized
- Fingerprint entropy: a synthetic Canvas, WebGL, or Audio fingerprint rarely matches the entropy distribution of millions of real devices
Sites With the Strongest Anti-Bot Defenses
- Google (reCAPTCHA v3): continuous behavioral scoring rather than a one-time check
- Cloudflare Bot Management: combines TLS fingerprinting, JS challenges, and network reputation
- PerimeterX and DataDome: enterprise-grade services purpose-built to catch WebDriver traffic
- Major social platforms: Facebook, LinkedIn, and X all run aggressive, constantly-updated Selenium detection
For a broader look at how these defenses work across categories beyond just Selenium, see our guide on how to bypass anti-bot systems without tripping the same behavioral and fingerprint checks covered above.
Selenium Alternatives With Better Built-In Stealth
If stealth-patching Selenium feels like a losing arms race, three alternatives are worth comparing before you invest more engineering time into patches that age out with every Chrome release.
Playwright
Microsoft’s modern automation framework ships with fewer default automation markers than Selenium and executes noticeably faster:
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch(headless=False)
page = browser.new_page()
page.goto('https://example.com')
Advantages over Selenium include a cleaner default fingerprint, built-in network interception, and a more modern multi-context architecture. Playwright still ultimately drives a browser through a control protocol, though, so it isn’t immune to the same category of detection described above.
Puppeteer With a Stealth Plugin
const puppeteer = require('puppeteer-extra')
const StealthPlugin = require('puppeteer-extra-plugin-stealth')
puppeteer.use(StealthPlugin())
const browser = await puppeteer.launch()
const page = await browser.newPage()
await page.goto('https://example.com')
The stealth plugin patches many of the same properties covered earlier automatically, which saves setup time but still doesn’t eliminate CDP-level traces.
Real Browser Automation: Send.win’s Approach
Send.win takes a different angle entirely. Instead of trying to make an automated browser look real, it runs your automation against a browser profile that already is real. Send.win offers two ways to work: the Sendwin Browser, a native desktop app for Windows, macOS, and Linux that keeps profiles local-first with encrypted cloud sync, and cloud browser sessions that run entirely on Send.win’s own infrastructure with zero local install, billed by cloud browsing time.
Each profile, whether local or cloud, carries its own consistent Canvas, WebGL, audio, and font fingerprint plus its own cookie jar and proxy assignment, the same kind of fingerprint isolation covered in our antidetect browser comparison. Starting on the Pro plan, Send.win’s Automation API lets you point your existing Selenium, Puppeteer, or Playwright scripts at a Sendwin Browser profile running locally, so the automation inherits that profile’s real fingerprint, session cookies, and proxy instead of a synthetic one you have to keep patching by hand.
Send.win vs Selenium: Which Wins for Undetectable Automation?
| Aspect | Selenium (Stealth-Patched) | Send.win (Automation API) |
|---|---|---|
| Detection risk | Medium to high, and rises over time as patches age | Low, since automation runs against a real profile fingerprint |
| Setup effort | High: stealth libraries, CDP tricks, ongoing maintenance | Moderate: point your existing script at a profile |
| Fingerprint origin | Synthetic, hand-patched property by property | Genuine device fingerprint per profile |
| Where it runs | Your local machine or your own server | Sendwin Browser desktop app or cloud sessions |
| Maintenance | Constant, since every Chrome release can break stealth patches | Handled by Send.win’s profile engine |
| Access | Free, open source | Pro plan ($9.99/mo, or $6.99/mo billed annually) or higher |
| Best for | QA testing on your own site, low-stakes scraping | Multi-account management plus automation against sites with strong anti-bot defenses |
🏆 Send.win Verdict
A Selenium browser fingerprint isn’t a bug you can fully patch away. navigator.webdriver, CDP traces, and behavioral tells are baked into how WebDriver controls a browser. Stealth libraries buy time against basic checks but rarely hold up against Cloudflare, DataDome, or reCAPTCHA v3 for long. If your automation needs to survive real anti-bot scrutiny, Send.win’s Automation API lets your existing Selenium, Puppeteer, or Playwright code run against a genuinely fingerprinted profile in the Sendwin Browser instead of a synthetic one, available from the Pro plan up.
Try Send.win free today — start your 30-day free trial, no credit card required.
Frequently Asked Questions
Can a Selenium browser fingerprint ever be made truly undetectable?
Not reliably. Selenium’s architecture depends on WebDriver and, since version 4, on the Chrome DevTools Protocol, both of which leave traces that sophisticated anti-bot vendors can detect. Stealth libraries reduce detection against basic and mid-tier checks but don’t eliminate the risk against enterprise-grade systems like Cloudflare Bot Management or DataDome.
Is patching a Selenium browser fingerprint legal?
Using automation tools, including stealth patches, is legal on its own. What can create legal exposure is using that automation to violate a site’s Terms of Service, scrape copyrighted content at scale, or bypass security controls for fraudulent purposes. Always check the target site’s terms before automating against it.
What’s the most reliable Selenium stealth library right now?
For Python, selenium-stealth and undetected-chromedriver are the most actively maintained options. For Node.js, puppeteer-extra-plugin-stealth covers the same category of fixes for teams moving from Selenium to Puppeteer.
Why do websites bother blocking Selenium at all?
Mainly to stop automated account creation, large-scale content scraping, ticket and product sniping bots, credential-stuffing attacks, and fraudulent form submissions. Even sites without an obvious monetization reason to block bots often do it just to keep analytics and inventory data clean.
Does the navigator.webdriver flag alone get Selenium blocked?
On many sites, yes. A single JavaScript check for navigator.webdriver === true is enough to trigger a block or a CAPTCHA challenge. It’s the cheapest check a site can run, which is exactly why so many sites run it first.
Can I use Selenium for social media account automation?
Technically yes, but platforms like Facebook, Instagram, LinkedIn, and X actively detect and ban Selenium sessions, and stealth patches degrade quickly against them. For reliable multi-account social media workflows, most teams eventually move that automation to a tool built around real browser fingerprints, such as Send.win, rather than continuously re-patching Selenium.
How is Send.win’s Automation API different from just running Selenium normally?
Instead of asking Selenium to impersonate a real browser, Send.win’s Automation API, available from the Pro plan, lets your Selenium, Puppeteer, or Playwright script drive a Sendwin Browser profile that already has a genuine, consistent fingerprint plus its own cookies and proxy, so the automation inherits real signals instead of synthetic ones you have to maintain by hand.
Does switching away from raw Selenium mean giving up my existing automation scripts?
No. Send.win’s Automation API is designed to work with the same Selenium, Puppeteer, or Playwright code you already have. You’re pointing it at a different, more realistic browser profile rather than rewriting your automation logic from scratch.