Contact
Stealth

Jak Platformy Wykrywają Automatyzację

Empirium Team10 min read

Every automation framework leaves traces. Puppeteer, Playwright, Selenium, and their derivatives modify the browser environment in ways that detection scripts can identify. The detection has gotten sophisticated enough that simply patching navigator.webdriver no longer works.

This guide covers the full detection stack — from trivial JavaScript checks to machine learning behavioral models — and the specific countermeasures that work in 2026.

The Detection Stack

Modern bot detection operates on three layers, each progressively harder to evade.

Layer 1: Client-Side JavaScript Checks

Detection scripts injected into the page check browser properties for automation artifacts. These are the easiest to detect and the easiest to evade — but they catch the majority of amateur bots.

Common checks:

  • navigator.webdriver — true when controlled by WebDriver/CDP
  • window.chrome.runtime — missing in headless Chrome
  • navigator.plugins — empty array in headless mode
  • navigator.languages — empty in some automation setups
  • CDP-specific objects in the global scope
  • Missing Notification, PermissionStatus, or MediaDevices APIs

Layer 2: Server-Side Behavioral Analysis

The server analyzes request patterns, session behavior, and interaction sequences. This layer doesn't depend on JavaScript execution — it works even if the client-side checks are perfectly spoofed.

Signals analyzed:

  • Request timing (too regular = bot, too fast = bot)
  • Navigation patterns (no organic browsing path, direct URL hits)
  • Mouse movement data (if collected via JS and sent to server)
  • Form interaction timing (instant fills = bot)
  • Absence of expected background requests (font loading, image prefetch, service worker registration)

Layer 3: Machine Learning Models

The most sophisticated platforms (Cloudflare Bot Management, PerimeterX, DataDome) train ML models on labeled datasets of human and bot traffic. These models combine signals from layers 1 and 2 with additional features:

  • TLS fingerprint consistency with claimed browser
  • HTTP/2 settings frame analysis
  • Request header order and values
  • Session-level behavior patterns across multiple pages
  • Statistical analysis of timing distributions

ML models catch bots that pass all individual checks by detecting statistical anomalies in the aggregate behavior.

Navigator and WebDriver Detection

The navigator.webdriver property is the most basic automation flag. When Chrome is launched by Puppeteer, Playwright, or Selenium, this property returns true. Detection is trivial:

if (navigator.webdriver) {
  reportBot();
}

But detection goes deeper. Here are the specific properties and their expected values:

Property Real Chrome Puppeteer Default Playwright Default
navigator.webdriver false / undefined true true
navigator.plugins.length 3-5 0 0
navigator.languages ["en-US", "en"] [""] or empty ["en-US"]
window.chrome Object with runtime Partial/missing Partial/missing
window.chrome.runtime Object undefined undefined
Notification.permission "default" "denied" "denied"
navigator.permissions Fully functional Partial Partial

CDP Detection

Chrome DevTools Protocol (CDP) is how Puppeteer and Playwright communicate with Chrome. Even after patching navigator properties, CDP artifacts remain:

// Detect CDP by checking for injected bindings
const hasCDP = window.__playwright !== undefined ||
               window.__puppeteer !== undefined ||
               window.cdc_adoQpoasnfa76pfcZLmcfl_Array !== undefined;

// Detect by checking for overridden functions
const originalToString = Function.prototype.toString;
const isPatched = originalToString.call(navigator.permissions.query)
  .includes('native code') === false;

Advanced detection also checks for the CDP websocket connection by examining window.performance.getEntries() for CDP-related resource loads, and by testing whether Runtime.evaluate is accessible.

Behavioral Analysis

Even if your automation passes every JavaScript check, behavioral analysis can still identify it. The challenge is that real humans are messy — their movements are imprecise, their timing varies, and their attention wanders. Bots are clean, precise, and consistent. That cleanliness is the signal.

Mouse Movements

Real mouse movements follow Fitts's Law — movement time is logarithmically related to distance and inversely related to target size. Human mouse paths include:

  • Micro-corrections near the target (overshoot, then adjust)
  • Bézier-curve-like trajectories (not straight lines)
  • Variable acceleration (fast in the middle, slow at start and end)
  • Occasional idle periods (human pauses to read or think)

Bot mouse movements are typically straight-line paths with constant velocity. Even when randomized, the distribution doesn't match human motor patterns. See behavioral biometrics for the full analysis.

Scroll Behavior

Humans scroll in irregular bursts — fast scrolls past uninteresting content, slow scrolls while reading, pauses at interesting sections. Bots typically scroll at constant speed or in fixed increments.

Typing Cadence

Human typing has characteristic inter-keystroke intervals that vary by letter pair (digraph latency). "th" is typed faster than "qz" because of keyboard proximity and learned motor patterns. Bots that type at constant speed or use element.value = text bypass keystroke events entirely.

Page Interaction Patterns

Real users interact with pages in predictable but variable ways:

  • They move the mouse before clicking (bots click without mouse movement)
  • They hover over elements before clicking (bots jump directly)
  • They scroll before interacting with below-fold content
  • They occasionally interact with non-target elements (reading text, looking at images)

Stealth Patching Techniques

Puppeteer with puppeteer-extra-stealth

The most common stealth approach for Puppeteer:

const puppeteer = require('puppeteer-extra');
const StealthPlugin = require('puppeteer-extra-plugin-stealth');
puppeteer.use(StealthPlugin());

const browser = await puppeteer.launch({
  headless: false,
  args: [
    '--disable-blink-features=AutomationControlled',
    '--no-sandbox',
    '--disable-infobars',
    '--disable-dev-shm-usage'
  ]
});

The stealth plugin patches:

  • navigator.webdriverundefined
  • chrome.runtime → populated object
  • navigator.plugins → realistic plugin array
  • navigator.permissions → proper behavior
  • iframe.contentWindow → consistent properties
  • WebGL vendor/renderer → realistic values
  • window.chrome → full object

Limitations: The stealth plugin addresses ~80% of detection vectors. It doesn't handle TLS fingerprinting, HTTP/2 settings, or behavioral analysis. Against sophisticated detection (Cloudflare, DataDome), it's insufficient alone.

Playwright Stealth

Playwright doesn't have an official stealth plugin, but equivalent patching is available:

const { chromium } = require('playwright');

const browser = await chromium.launch({
  headless: false,
  args: ['--disable-blink-features=AutomationControlled']
});

const context = await browser.newContext({
  userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) ...',
  viewport: { width: 1920, height: 1080 },
  locale: 'en-US',
  timezoneId: 'America/New_York'
});

// Patch navigator.webdriver
await context.addInitScript(() => {
  Object.defineProperty(navigator, 'webdriver', { get: () => undefined });
  Object.defineProperty(navigator, 'plugins', {
    get: () => [1, 2, 3, 4, 5]
  });
});

Human-Like Interaction Libraries

Several libraries generate realistic human behavior for automation:

  • ghost-cursor — Bézier curve mouse movements with human-like acceleration profiles
  • human-typing — variable inter-keystroke delays based on digraph statistics
  • scroll-behavior — irregular scroll patterns with reading pauses

These address behavioral detection but add significant complexity and slow down automation. Use them only when behavioral detection is a confirmed issue on your target.

FAQ

How does reCAPTCHA v3 scoring work? reCAPTCHA v3 assigns a score from 0.0 (likely bot) to 1.0 (likely human) based on behavioral analysis. It doesn't present a challenge — it runs silently. Scores below 0.5 typically trigger additional verification. Improving your score requires realistic mouse movements, natural browsing patterns, and a clean browser fingerprint. reCAPTCHA v3 is heavily influenced by Google account login status — logged-in Chrome users score higher.

Is headless mode detectable in 2026? Chrome's new headless mode (headless=new, Chrome 112+) is significantly harder to detect than the old headless mode. However, differences remain in: navigator.plugins behavior, PDF viewer availability, media codec support, and window management APIs. For maximum stealth, use headed mode with a virtual display (Xvfb). See headless detection.

Can Cloudflare's bot detection be bypassed? Cloudflare's free tier can be bypassed with proper stealth patching and TLS fingerprint matching. Cloudflare Bot Management (paid) is significantly harder — it combines JA3/JA4 fingerprinting, behavioral analysis, and ML models. Bypassing it requires: matched TLS fingerprint (curl-impersonate or real browser), realistic behavioral patterns, and clean IP reputation. It's not impossible, but it requires effort proportional to the target's protection level.

What's the future of bot detection? The trend is toward ML-based behavioral analysis that's resistant to individual vector patching. The detection industry is moving from "check 50 properties" to "model the statistical distribution of human behavior and flag outliers." Countering this requires bots that don't just pass individual checks but statistically resemble human users across all dimensions. The barrier to entry is rising.

Written by Empirium Team

Explore More

Deep-dive into related topics across our five pillars.

Pillar Guide

Browser Fingerprinting w 2026: Co Musisz Wiedzieć

Techniczny przegląd fingerprintingu — 12 wektorów i obrona.

View all Stealth articles

Related Resources

Need help with this?

Talk to Empirium