How websites detect bots and automated browsers
Bots fill in sign-up forms, abuse promo codes, scrape prices and try stolen passwords. Most of them run real browser engines controlled by scripts, so a simple User-Agent check no longer catches them. Here is how modern detection works, layer by layer.
Check your browser right now
Checking your browser…
Layer 1: automation flags
Browsers under automation, for example through Selenium, Puppeteer or Playwright with default settings, usually report navigator.webdriver = true; the WebDriver standard requires it. Older headless Chrome also called itself HeadlessChrome in the User-Agent. These are the cheapest checks and catch careless bots, but any serious bot hides them.
Layer 2: environment traces
Headless and virtualized browsers differ from a desktop browser in small ways: a software graphics renderer such as SwiftShader or llvmpipe instead of a real GPU, a window with zero outer size, missing objects that a real desktop Chrome always has, no speech voices or media devices, unusual screen sizes. Each trace has innocent explanations, so good detectors weigh them instead of blocking on one.
Layer 3: consistency and tampering
Bots that try to look human change values: a common User-Agent, a popular screen size, a plausible GPU name. Changing values consistently everywhere is hard, so detection compares the same fact from different sources:
- The User-Agent in the HTTP header and navigator.userAgent in JavaScript.
- Client Hints headers and navigator.userAgentData.
- The main page and a Web Worker or an iframe, which often keep the original values.
- The operating system in the User-Agent and the GPU and fonts that are actually available.
- Whether built-in functions are still native code or were replaced by a script.
A contradiction between two sources is far stronger evidence than any single odd value.
Layer 4: network
The IP address says a lot: does it belong to a home or mobile provider or to a data center, is it a known VPN, proxy or Tor exit, does it appear in spam blacklists, does the browser time zone fit the IP country? Advanced systems also fingerprint the TLS handshake (JA3, JA4) and HTTP/2 settings, which reveal the real client library behind a forged User-Agent.
Layer 5: behavior
Finally, systems watch how the visitor acts: mouse movement, typing rhythm, scrolling, how fast forms are filled, how many accounts come from one device. Behavior catches bots that pass every technical check, but it needs time and data, so it works best together with the earlier layers.
What this means for a website owner
No single signal is reliable, and blocking on one causes false positives for real people with VPNs, privacy browsers or unusual hardware. A practical setup scores several signals, adds friction (an email confirmation, a captcha, a manual review) only when the score is high, and protects the actions that matter: sign-up, login, checkout and promo codes.
SpoofLens is preparing an API and a WordPress / WooCommerce plugin that return such a score with the reasons behind it. The check on this page shows what the browser part finds today.
Frequently asked questions
- Is a captcha enough?
- Not on its own. Captcha-solving services and modern AI solve many captchas cheaply. A captcha works best as extra friction for visitors who already look suspicious, not as the only gate.
- Will bot detection block my real users?
- It can, if it blocks on single signals such as a VPN or a privacy browser. Weighing several signals and asking for extra proof instead of blocking keeps false positives low.
- Does SpoofLens block bots on my site?
- Not yet. Today the check shows the signals of one browser. A website API and plugins are in preparation, and you can join the waitlist on the home page.
Read next
- Browser fingerprinting: what it is and how it works
- Canvas, WebGL and audio fingerprints: how they work
- WebRTC leak: what it is and how to check your browser
- Time zone vs IP: why websites notice your VPN
- How websites recognise antidetect browsers
- User-Agent Client Hints: what replaced the User-Agent string