Headless Detection Techniques: How Sites Spot Automated Browsers

Websites detect headless browsers by stacking checks: simple browser properties such as navigator.webdriver, rendering and API inconsistencies, network-level fingerprints like TLS, behavioral signals, and the reputation of the IP address behind the request. No single check decides the outcome. Detectors combine them into a score, and a browser that passes the JavaScript tests can still fail on the network layer.
This guide walks through each layer in the order most detection systems apply them, explains what causes false positives, and shows how to test your own setup in an environment you are authorized to test. It is written for developers who build scrapers, QA and monitoring tools, and for engineers on the defending side who want to know what their own detectors can and cannot see.
TL;DR
- Detection works in layers: browser properties, rendering environment, network fingerprints (TLS and HTTP/2), behavior, and IP reputation. Each layer catches what the previous one misses.
- The cheap signals (
navigator.webdriver, a "HeadlessChrome" user agent, missingwindow.chrome) are easy to fix and easy to check, so they only filter out unconfigured tools. - The hard signals are contradictions: a fingerprint whose attributes disagree with each other, or a TLS handshake that does not match the browser it claims to be.
- Passing a public smoke-test page proves you removed obvious flags, not that your browser looks human.
- Network origin matters as much as browser configuration: the same clean browser can score very differently from a datacenter IP and from a real carrier IP.
Table of Contents
- What headless means, and why it is detectable
- The signal hierarchy: from cheap checks to hard ones
- Layer 1: the obvious browser flags
- Layer 2: API surface and environment inconsistencies
- Layer 3: fingerprint inconsistency
- Layer 4: the automation channel itself
- Layer 5: network fingerprints
- Layer 6: behavior
- Layer 7: IP and session reputation
- Why detection is never perfectly reliable
- How to test your own setup safely
- Where we stand
- Run your tests from a real carrier network
- FAQ
- Sources
What headless means, and why it is detectable
A headless browser runs without a visible window and is launched through code. Chrome now offers two implementations. According to Chrome for Developers, the modern Headless mode is unified with the headful browser, while the old Headless mode was a separate implementation that did not share Chrome browser code.
That history explains much of the detection folklore. The old mode behaved differently from a normal browser in many small ways, so detectors built long lists of tells. The unified mode removed many of those differences, which pushed detection toward signals that come from the automation itself: the control channel, the launch flags and the surrounding network traffic.
The second reason headless is detectable is structural. Automation has to be wired into the browser somehow, whether through WebDriver, the Chrome DevTools Protocol (CDP) or an injected script, and that wiring leaves traces.
The signal hierarchy: from cheap checks to hard ones
It helps to think of detection as a ladder. Lower rungs are cheap for the site and cheap for you to fix. Higher rungs cost more to run and are far harder to fake.
| Layer | Example signals | Cost to fix on the automation side |
|---|---|---|
| Browser flags | navigator.webdriver, "HeadlessChrome" in the user agent | Low |
| Runtime and API surface | Missing window.chrome, empty plugin list, odd screen geometry | Low to medium |
| Rendering | Software renderer in WebGL, canvas differences | Medium |
| Automation channel | CDP side effects, injected-script residue | Medium to high |
| Network transport | TLS ClientHello, HTTP/2 frame patterns | High |
| Behavior | Mouse paths, timing, navigation patterns | High |
| Reputation | IP type, ASN, request history | Depends on the network |
The cside overview of headless detection describes the same progression: simple API checks first, then analysis of the rendering environment, network transport fingerprints and behavioral analysis of how a visitor interacts with the page.
Layer 1: the obvious browser flags
navigator.webdriver
The W3C WebDriver specification defines navigator.webdriver as a standard way for a user agent to tell the page it is controlled by WebDriver, so alternate code paths can be triggered during automation. It reports true when the browser's webdriver-active flag is set. Selenium, Puppeteer and Playwright launches commonly trip it, which is why it is the first thing nearly every detector reads.
Chrome also still includes the --enable-automation switch and the "controlled by automated software" infobar, both of which are detectable, as the Measure The Web write-up on crawler detection notes.
A launch argument such as --disable-blink-features=AutomationControlled can suppress the property. Castle's analysis of Puppeteer-instrumented Chrome points out that this does not hide the underlying instrumentation through CDP, so hiding the flag only removes one signal.
The user agent string
Headless Chrome has historically announced itself with "HeadlessChrome" in the User-Agent header. DataDome describes this default as a simple identification marker on both the server and the client, unless someone explicitly modifies it. Overriding it is trivial, but a careless override creates a new problem: a user agent that claims one Chrome version while the other signals say another. We cover that trap in our guide to user agent rotation and fingerprints.
Layer 2: API surface and environment inconsistencies
Older detection guides list a familiar set of JavaScript tells. PiProgramming's 2021 write-up mentions empty plugin lists, an absent window.chrome object and missing permission handling for notifications. Many of these were characteristic of the old Headless mode and are less reliable against current Chrome, but they remain common in off-the-shelf detection scripts, and they still catch tools that patch the browser badly.
Other environment checks look at the window itself. Real desktop browsers have toolbars, scrollbars and screens with plausible dimensions. Headless setups often report a default viewport, an outer window the same size as the inner one, or a zero-sized window. If your automation sets a custom viewport, set the screen, outer window and device pixel ratio to match it.
Rendering is another giveaway. Headless Chrome without GPU passthrough can report a software renderer such as Google SwiftShader or ANGLE, and its output can differ from hardware-accelerated Chrome, according to cside. A WebGL vendor string that says software rendering on a machine claiming to be a consumer laptop is exactly the kind of mismatch detectors score.

Layer 3: fingerprint inconsistency
The modern trend is to stop asking whether a single value looks automated and start asking whether the values agree with each other. The Measure The Web article on crawler detection describes inconsistency detection as looking for attributes that contradict one another.
Academic work supports this. Researchers presenting at the 2025 ACM Internet Measurement Conference observed that many bots alter their fingerprints to evade detection, but the changes often produce mismatched attributes that can be used to identify them.
Typical contradictions include:
- A Windows user agent with a Linux platform string or Linux-only fonts.
- A mobile user agent with a desktop screen size and no touch support.
- A language header that disagrees with
navigator.languagesor the timezone. - A Chrome version in the user agent that does not match the feature set the browser actually exposes.
The practical lesson is that spoofing one attribute can make you more visible than leaving it alone. For more on how many dimensions are in play, see our list of browser fingerprint facts teams should know.
Layer 4: the automation channel itself
The Chrome DevTools Protocol is the instrumentation interface used by Puppeteer, Playwright and many Selenium setups. Using it can create side effects the page can observe. DataDome's research on new headless Chrome and the CDP signal explains that CDP detection targets the underlying technology of automation, not the quirks a specific framework adds. One commonly discussed example is a distinctive pattern in stack traces when the page serializes an error object while CDP is attached.
Other residue shows up in older Selenium setups: cdc_-prefixed globals and traces of injected setup scripts, as listed in Clearcote's layer-by-layer review.
This is the layer where "stealth" plugins struggle, because the thing being detected is the control channel, not a property that can be overwritten.
Layer 5: network fingerprints
Before any JavaScript runs, the server has already seen the TLS handshake and the HTTP/2 settings. Network-level detection analyzes the TLS ClientHello and HTTP/2 frame patterns, which can differ between headless Chromium builds and standard desktop browsers. Per cside, this makes them harder to spoof than JavaScript-based signals.
This is especially relevant for scrapers that mix tools. An HTTP library sending a Chrome user agent with a non-Chrome TLS fingerprint is a mismatch visible on the first request. If you are chasing that kind of problem, our article on stopping TLS fingerprint drift with JA3/JA4 goes into the details.
Layer 6: behavior
Behavioral analysis looks at what happens after the page loads: mouse movement, scrolling, typing rhythm, time between actions and navigation order. DataDome recommends combining browser fingerprinting, behavioral signals such as mouse movements and browsing patterns, and reputation signals such as IP and session reputation.
Signs that read as non-human include:
- Clicks at exact element centers with no pointer travel before them.
- Instant form filling.
- Perfectly regular intervals between requests.
- Visiting deep URLs without ever loading the pages a person would pass through first.
Behavior is also the layer where scale hurts. A pattern that looks fine for ten sessions looks synthetic across ten thousand.
Layer 7: IP and session reputation
The last layer sits outside the browser. Bot management services score network reputation alongside TLS fingerprints, browser runtime properties and behavior, as Measure The Web puts it. Datacenter ranges are widely known and often treated with suspicion by default. A request from a residential or mobile carrier address starts with a different baseline, and carrier networks put many real users behind shared addresses, which makes blanket blocking costly for the site.
Reputation is also about session consistency: an IP that changes between requests of one logged-in session, or a location that jumps from Dallas to Chicago in a minute, is a signal in its own right. This is why we support both sticky and rotating sessions. Use sticky when a flow needs one identity across several pages, and rotation when each request is independent. Our rundown of bot detection signals scrapers must handle shows how these signals combine in practice.
Why detection is never perfectly reliable
Detection systems work with probabilities, and both errors are possible.
False positives. Real people can look unusual: privacy extensions, remote desktop sessions, virtual machines without a GPU, corporate proxies, accessibility tools and outdated browsers all produce odd fingerprints. Vendors claim low error rates in their own tests (cside reports a human false-positive rate under 1% for its cursor model in controlled tests), but those figures come from the vendor's setup, not from your traffic. A site that blocks hard on one weak signal will lock out legitimate users.
False negatives. Client-side detection code is delivered to the client, so anyone can read it. Antoine Vastel notes that scripts are therefore often obfuscated, which feeds the cat-and-mouse dynamic between detectors and automation authors. Whatever one side learns, the other eventually adapts to.
If you run a site and are tuning a detector, treat single signals as score inputs, challenge rather than block at moderate scores, and keep a path for humans to recover.
How to test your own setup safely
Only test against pages and systems you own or have permission to test. Public test pages and your own staging site are the right targets.
- Start with a public detection page. The open-source detect-headless project from Infosimples runs a set of headless tests in your browser, including user agent, plugin and WebDriver checks.
- Treat a pass as a floor. One community write-up on a popular smoke-test site explains that passing only shows you avoid obvious, outdated signatures, not that your fingerprint is coherent or will look genuine to advanced systems.
- Check coherence, not just flags. Print the user agent, platform, languages, timezone, screen, WebGL renderer and fonts from the same session and read them as one story. Do they describe a single real machine?
- Compare headful and headless runs. Run the same script both ways and diff the results. Differences point to what a detector can see.
- Verify the network separately. Check your TLS and HTTP/2 fingerprint from the proxy path you will actually use, not from your laptop.
- Measure cost as you go. Headless pages can pull a lot of bytes, and on metered proxy plans that matters. Our guide to measuring headless browser bandwidth shows how to avoid paying twice for the same resources.
Where we stand
We build and run mobile proxy infrastructure, so we see detection from the network side every day. Here is our point of view, grounded in what we offer and what our users run into.
The browser layer gets most of the attention, but most failures we hear about from teams are inconsistencies between layers. A carefully patched Chromium behind a datacenter IP, a Chrome user agent with a library's TLS handshake, a New York timezone on a Texas exit: each pair tells a detector more than any single flag.

So our advice is to fix coherence before cleverness. Use a current, unmodified browser build where you can, keep the user agent honest, make the timezone and language match the exit location, and choose the session type to fit the task. Where location matters, we offer real carrier IPs in 46 US cities, so a geo-targeted check can run from the city you are actually studying. Pick sticky sessions for multi-step flows and rotation for independent requests. Our approach is built on genuine mobile IPs rather than datacenter ranges, which gives requests a more natural network origin. No proxy replaces a coherent browser, and no browser patch replaces a trustworthy network origin. You need both.
We would also rather you test than guess. Run your automation against your own staging site first, read what the page sees, and only then point it at production targets, within each site's terms and the law.
— Jon
Run your tests from a real carrier network
If your headless setup is coherent but your IP gives it away, the network layer is where to look next. Masklabs provides US mobile proxies on real carrier IPs, with city-level targeting, sticky and rotating sessions, HTTP, HTTPS and SOCKS5 support, and per-byte metering so you pay for the data you use. Plans start at $30 per month (Starter), with Basic at $100 per month, Advanced at $500 per month and Scale at $1000 per month, and there is a free trial with limited data. Setup is self-serve, with no sales call. For wiring it into your stack, see our proxy API for browser automation and Selenium proxy setup.
FAQ
Can websites detect headless mode?
Often, yes, but rarely from one signal. Sites combine browser properties, rendering clues, TLS and HTTP/2 fingerprints, behavior and IP reputation. The more of those layers that agree with a normal desktop browser, the harder detection becomes, and the more any contradiction stands out.
How do I detect a headless browser on my own site?
Start server-side with the user agent and TLS fingerprint, then add client-side checks for navigator.webdriver, renderer strings and window geometry. Score the signals together instead of blocking on one, and add behavioral data if you need more confidence. Challenge borderline cases rather than denying them.
Does the HeadlessChrome user agent still matter?
It matters for unconfigured tools, because it is a default marker that is trivial to read. It is also trivial to change, so serious detectors treat it as a starting point and check whether the rest of the fingerprint agrees with whatever user agent is sent.
Is passing a bot-test page enough?
No. Those pages check for well-known signatures, and passing shows you removed obvious flags. It does not show that your fingerprint is internally consistent, that your TLS handshake matches your claimed browser, or that your behavior and IP will look genuine to a commercial system.
Does using a proxy stop headless detection?
A proxy changes the network origin and location, not the browser. It helps with IP reputation and geo-targeting, but the browser, TLS and behavior layers still need to be consistent. Treat the proxy and the browser as one setup.
Sources
- Chrome Headless mode, Chrome for Developers
- WebDriver, W3C
- Headless Browser Detection: Signals, Methods, and What Works, cside
- Crawler detection, Measure The Web
- How to detect headless Chrome bots instrumented with Puppeteer, Castle
- Why server-side bot detection is not enough, DataDome
- How New Headless Chrome and the CDP Signal Are Impacting Bot Detection, DataDome
- How automation gets caught, layer by layer, Clearcote
- 6 Ways to detect a headless Browser with JavaScript, PiProgramming
- FP-Inconsistent: Measurement and Analysis of Fingerprint Inconsistencies, ACM IMC 2025
- Bot detection 101, Antoine Vastel
- Detect Headless, Infosimples
- sannysoft explained, invisible_playwright wiki