Skip to content

Browser automation through WebDriver is the most common technique bots use to impersonate real users. Knowing exactly what signals expose a WebDriver-controlled browser — and how reliable those signals are — is the foundation of any serious bot detection strategy.

What WebDriver Signals Actually Reveal

When a browser is launched via WebDriver (Selenium, Playwright, Puppeteer, or similar), it leaves a set of observable artifacts that detection systems can interrogate. These are not bugs in the automation tools; they are structural side-effects of how the WebDriver protocol instruments the browser engine.

The most consistently detected signals include:

  1. navigator.webdriver property – Browsers controlled via the WebDriver protocol set this boolean to true by default. It is the single most cited signal in bot detection literature, though modern headless browsers increasingly attempt to patch it.
  2. CDP (Chrome DevTools Protocol) attachment markers – When Playwright or Puppeteer attaches to a browser over CDP, certain runtime objects and event listeners appear in the JavaScript heap that are absent in organic sessions.
  3. Plugin and MIME-type arrays – A headless Chrome instance typically exposes zero plugins. Real desktop Chrome on any major OS exposes at least several.
  4. Rendering timing inconsistencies – Hardware-accelerated rendering produces measurably different canvas and WebGL fingerprint outputs versus software-rendered headless environments.
  5. Event sequencing anomalies – Human mouse movement generates dozens of mousemove events between a mousedown and mouseup. Script-driven clicks often produce exactly one or none.
  6. Missing or malformed browser features – Properties like window.chrome, speech synthesis voices, or the Notification API are either absent or stub objects in many headless configurations.

None of these signals is individually decisive. Robust detection scores them in aggregate — something more sophisticated than a single if (navigator.webdriver) check.

layered signal funnel diagram showing multiple browser signals converging into a

How Evasion Attempts Change the Detection Landscape

Understanding evasion is essential for defenders: if you only test your protection against naive bots, you will be unprepared for the tooling that most real attackers use.

Tools like undetected-chromedriver, Playwright-stealth, and various CDP-level patches attempt to neutralize the obvious signals above. They patch navigator.webdriver, inject realistic plugin arrays, and spoof window.chrome. Against a detector that relies solely on those static property checks, these tools work.

This is why detection has shifted toward behavioral and consistency-based analysis:

Behavioral Signals

  • Mouse trajectory entropy (real paths curve; scripted paths are often linear or grid-snapped)
  • Scroll acceleration and deceleration curves
  • Inter-keystroke timing distribution
  • Focus/blur patterns during form completion

Consistency Signals

  • Does the reported GPU in the WebGL renderer match the reported OS and browser version?
  • Does the Accept-Language header match the JavaScript navigator.language?
  • Does the screen resolution, color depth, and device pixel ratio form a plausible combination for any real device?

Inconsistencies here are hard to spoof exhaustively because the attacker must maintain a coherent fiction across dozens of independent measurement channels simultaneously.

Comparing Detection Approaches Across Common Providers

Different CAPTCHA and bot-defense services weight these signals differently.

ProviderPrimary Signal TypeInvisible-FirstFirst-Party Data
Google reCAPTCHABehavioral + Google account historyYes (v3)No (cross-site profile)
hCaptchaVisual challenge + behavioralPartialNo
Cloudflare TurnstileBrowser integrity + TLS fingerprintYesPartially (tied to Cloudflare network)
CaptchaLaBehavioral + device fingerprintYesYes — no cross-site tracking

The first-party data distinction matters for compliance (GDPR, CCPA) and for avoiding false positives that arise when a user's Google or Cloudflare reputation is low for reasons unrelated to your site.

Implementing Server-Side Validation Correctly

Client-side detection is only half the job. A bot that passes a challenge can replay the resulting token; your server must validate it before trusting the action.

A minimal server-side validation call to CaptchaLa looks like this:

js
// Node.js example — run this on your server, never in the browser
const response = await fetch('https://apiv1.captcha.la/v1/validate', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-App-Key': process.env.CAPTCHALA_APP_KEY,       // keep secret
    'X-App-Secret': process.env.CAPTCHALA_APP_SECRET  // keep secret
  },
  body: JSON.stringify({
    pass_token: req.body.captchaToken,  // token from the client widget
    client_ip: req.ip                   // forwarded real IP, not proxy IP
  })
});

const result = await response.json();
// result.success === true means the challenge was genuinely solved
if (!result.success) {
  return res.status(403).json({ error: 'Bot check failed' });
}

Two things to get right here: always pass the real client_ip (not a load balancer IP), and always validate server-side even if you already checked on the client. Skipping server validation is the most common integration mistake.

Full integration details, including SDKs for PHP (captchala-php), Go (captchala-go), and mobile platforms (iOS via CocoaPods Captchala 1.0.2, Android via Maven la.captcha:captchala:1.0.2, Flutter via pub.dev captchala 1.3.2), are in the docs.

abstract flow diagram showing client widget token passing through server validat

Choosing the Right Detection Threshold

Bot detection always involves a tradeoff between false negatives (bots that pass) and false positives (real users blocked). Where you set that threshold should be driven by the value and risk of the protected action:

  • Low-stakes pages (newsletter subscription, search) — tolerate more false negatives; minimize friction for real users.
  • Medium-stakes actions (account creation, password reset) — challenge on behavioral anomalies; pass clean sessions silently.
  • High-stakes actions (checkout, API key generation, large transfers) — require explicit challenge completion regardless of behavioral score; log for audit.

A server-token flow (POST to https://apiv1.captcha.la/v1/server/challenge/issue) lets you trigger challenges server-side when your own application logic raises a risk flag, independent of what happened on the client. This is useful for step-up authentication scenarios.

Where to Go Next

If you want to test detection against your own registration or login flow, CaptchaLa has a free tier covering 1,000 validations per month — enough to evaluate real-world detection quality without committing a budget. When you're ready to scale, pricing starts at 50K validations per month on the Pro plan. The docs cover every SDK and the full API reference, including the loader script at https://cdn.captcha-cdn.net/captchala-loader.js for quick front-end integration.

Articles are CC BY 4.0 — feel free to quote with attribution