ブログに戻る
検出防止

How Websites Detect Browser Automation and How to Prevent It

Automation frameworks like Playwright and Puppeteer leave detectable traces. Learn what signals websites check and how cloud browsers eliminate them.

Introduction

When you automate a browser with Playwright, Puppeteer, or Selenium, the browser exposes signals that identify it as programmatically controlled. The navigator.webdriver property is set to true. Framework-specific objects appear in the JavaScript environment. Console and debugging protocols leave traces. Headless mode behaves differently from headed mode in subtle ways.

These signals exist because automation frameworks need hooks into the browser to function. The problem is that these same hooks are visible to any JavaScript running on the page.

The Detection Signals

The W3C WebDriver specification introduced navigator.webdriver. When a browser is controlled via the WebDriver protocol, this property returns true. It was designed as a transparency mechanism, but it is now the most commonly checked automation signal.

In standard Chromium, this value is set at the C++ level during browser initialization when the --enable-automation flag is present, which Playwright and Puppeteer add by default.

Framework Injection Points

Each automation framework injects code at specific points:

  • Playwright injects binding functions (__playwright__binding__) and initialization scripts into every new page context
  • Puppeteer injects evaluation script helpers and CDP session management code
  • Selenium uses the WebDriver protocol which sets browser-level automation flags

CDP Artifacts

The Chrome DevTools Protocol enables external tools to control the browser. When a CDP session is active, several signals become observable:

  • Runtime.enable and Console.enable change the behavior of console.log and error stack traces
  • CDP session connections appear on specific WebSocket endpoints
  • Certain browser behaviors change when CDP domains are active

Headless Mode Differences

Standard Chromium's headless mode differs from headed mode in several ways. The navigator.plugins array may be empty. WebGL may fall back to software rendering. Window dimensions may have unusual values.

Why Stealth Plugins Fall Short

Stealth plugins attempt to clean up after the framework has already set automation values. They override navigator.webdriver with a JavaScript getter, delete framework objects from the global scope, and patch other telltale properties.

This approach has a fundamental weakness: the cleanup happens in JavaScript, after the page context is initialized. The original values exist briefly before being overwritten, and the cleanup code itself is detectable.

Detection systems can:

  • Check for property descriptor modifications on navigator.webdriver
  • Detect that Object.getOwnPropertyDescriptor returns a getter instead of a value
  • Observe timing differences between the initial state and the patched state
  • Look for the stealth plugin's own code patterns

How BotCloud Solves This

BotCloud eliminates automation signals at the engine level, before any page code executes:

  • navigator.webdriver returns false natively, not through a JavaScript override
  • No framework binding objects are present in page contexts
  • CDP session activity is invisible to page JavaScript
  • Headless and headed modes produce identical observable behavior

Because these changes happen in the browser engine itself, there is no JavaScript patch to detect, no timing gap to exploit, and no property descriptor anomaly to find.

Practical Implications

With BotCloud, you can use Playwright or Puppeteer's full API surface without any stealth plugins or configuration workarounds. Your automation scripts stay clean and focused on business logic rather than detection avoidance.

// No stealth plugin needed - just connect and automate
const browser = await puppeteer.connect({
  browserWSEndpoint: 'wss://bots.win/ws?apiKey=YOUR_API_KEY',
});

const page = await browser.newPage();
await page.goto('https://example.com');

// navigator.webdriver is false, no automation traces visible
#automation#detection#webdriver#puppeteer#playwright