Contact
Stealth

Headless-браузеры в 2026: обнаружение и защита

Empirium Team10 min read

Headless Chrome was supposed to be invisible — a browser without a visible window, perfect for automation. In practice, it's one of the most detectable automation methods available. Detection systems have spent years cataloguing the differences between headless and headed Chrome, and those differences are extensive.

The new headless mode introduced in Chrome 112 narrowed the gap significantly. But "narrowed" doesn't mean "eliminated." This guide covers what's still detectable, why it matters, and the defense strategies that actually work.

The Headless Detection Landscape in 2026

Detection has evolved through three phases:

Phase 1 (2017-2019): Navigator property checks. navigator.webdriver = true was the simplest detection. Headless Chrome set this flag by default, and detection scripts checked it. Patching this single property was enough to evade most detection.

Phase 2 (2019-2022): Deep property analysis. Detection expanded to dozens of browser properties: navigator.plugins (empty in headless), window.chrome.runtime (missing), Notification.permission (always "denied"), and missing APIs like MediaDevices and PermissionStatus. Each difference between headed and headless Chrome became a detection signal.

Phase 3 (2022-present): Behavioral and rendering analysis. Modern detection doesn't just check properties — it analyzes how the browser renders content, processes events, and handles edge cases. CDP protocol detection, rendering artifact analysis, and behavioral biometrics make headless detection multi-layered.

Chrome Headless vs Headful: The Measurable Differences

Even with Chrome's new headless mode, measurable differences remain. Here are the specific vectors:

Missing Browser Features

Feature Headed Chrome Old Headless New Headless
navigator.plugins PluginArray (3-5 items) Empty PluginArray PluginArray (matches headed)
navigator.mimeTypes MimeTypeArray (4+ items) Empty MimeTypeArray MimeTypeArray (matches headed)
window.chrome Full object Missing Present (matches headed)
window.chrome.runtime Object Missing Object (matches headed)
PDF viewer Available Not available Available
Notification.permission "default" "denied" "default"
Media codecs Full set Reduced set Most available
WebGL extensions Full set Reduced set Mostly matches headed

The new headless mode fixed the most obvious differences. But it didn't fix everything.

Rendering Differences

Font rendering. Headless mode renders fonts without sub-pixel anti-aliasing on some platforms. This changes the canvas fingerprint — a headed and headless browser on the same machine produce different canvas hashes.

Window dimensions. Headless Chrome defaults to 800×600 viewport with no outer window dimensions. screen.availWidth and screen.availHeight may return values inconsistent with the claimed display. In headed mode, these values come from the actual display; in headless mode, they're synthetic.

Color depth. Some headless configurations report screen.colorDepth of 24 instead of the standard 32 on modern displays. This subtle difference is checked by advanced detection.

CDP Protocol Artifacts

Chrome DevTools Protocol artifacts are the hardest to eliminate because they're fundamental to how automation frameworks communicate with the browser:

// Detection: check for CDP websocket artifacts
const cdpDetected = 
  performance.getEntriesByType('resource').some(r => 
    r.name.includes('devtools')
  ) ||
  window.__cdp_binding !== undefined ||
  document.querySelector('[data-selenium]') !== null;

CDP-injected scripts (via Page.addScriptToEvaluateOnNewDocument) execute before any page JavaScript but leave timing artifacts — the page's JavaScript execution starts slightly later than in a non-automated browser.

Permission API Behavior

Headed Chrome prompts for permissions (camera, microphone, notifications). Headless Chrome auto-denies them. Detection scripts query the Permission API and check whether the browser would show a prompt:

navigator.permissions.query({ name: 'notifications' }).then(result => {
  // Headed: "prompt" (user hasn't decided yet)
  // Headless: "denied" (auto-denied, never prompted)
  if (result.state === 'denied') {
    // Suspicious — might be headless
  }
});

New Headless Mode (Chrome 112+)

Chrome 112 introduced --headless=new, which shares the same browser implementation as headed mode. The key changes:

Same rendering pipeline. New headless uses the same compositing and rendering path as headed mode. This means canvas fingerprints, WebGL output, and font rendering should match headed Chrome on the same system.

Same feature support. PDF viewer, media codecs, extensions — all available in new headless mode. This eliminates the most common feature-presence detection vectors.

Same JavaScript environment. navigator.plugins, window.chrome, permission APIs — all behave identically to headed mode.

What Still Leaks

No window management. Functions that interact with the OS window (moving, resizing, minimizing) behave differently. window.screenX, window.screenY, and window.outerWidth / window.outerHeight may return default values rather than real window positions.

Event timing. The event loop behaves slightly differently without a real display. Rendering-triggered events (requestAnimationFrame timing, IntersectionObserver callbacks) may fire with different timing characteristics.

Clipboard and drag-and-drop. These APIs require OS-level integration that headless mode doesn't fully support. Detection scripts that attempt clipboard operations and check for failures can distinguish headless mode.

Screen capture and media. getDisplayMedia() and screen-sharing APIs fail in headless mode because there's no display to capture.

Defense Strategies

Strategy 1: Headed Mode with Virtual Display

The most reliable approach: run a full headed Chrome instance on a virtual display. On Linux, Xvfb (X Virtual Framebuffer) provides a display server without physical hardware:

Xvfb :99 -screen 0 1920x1080x24 &
export DISPLAY=:99
chromium --window-size=1920,1080

This eliminates every headless detection vector because the browser is genuinely running in headed mode. It just happens to be rendering to a virtual display instead of a physical monitor.

Tradeoffs: Higher resource consumption (20-30% more RAM and CPU than headless), requires Linux or virtual Linux environment, and virtual display configuration adds operational complexity.

For Docker deployments:

FROM node:20-slim
RUN apt-get update && apt-get install -y xvfb chromium
ENV DISPLAY=:99
CMD Xvfb :99 -screen 0 1920x1080x24 & node app.js

Strategy 2: Patched Chromium Builds

Compile Chromium from source with patches that eliminate headless detection vectors. This is the approach taken by some anti-detect browsers — they maintain their own Chromium fork with modifications.

Key patches:

  • Remove --headless flag detection from JavaScript
  • Match window dimension reporting between headless and headed
  • Normalize rendering pipeline for consistent fingerprints
  • Remove CDP artifacts from the page context

Tradeoffs: Requires Chromium build expertise, takes 2-4 hours per build, must be maintained across Chrome versions, and the patches themselves may be fingerprinted by detection systems that specifically look for known anti-detect Chromium modifications.

Strategy 3: Cloud Browser Services

Services like Browserless, BrowserBase, and Kameleo Cloud provide headed browser instances in the cloud. You connect via CDP or a proprietary API and interact with a real browser running on remote hardware.

Advantages: No local detection vectors, real hardware fingerprints, managed infrastructure. Tradeoffs: Higher cost per session, provider controls the infrastructure (and could be compromised), and the shared infrastructure may carry reputation from other users' activities.

Strategy 4: New Headless Mode + Careful Configuration

For lower-scrutiny targets, the new headless mode with proper configuration handles most detection:

const browser = await puppeteer.launch({
  headless: 'new',
  args: [
    '--window-size=1920,1080',
    '--disable-blink-features=AutomationControlled',
    '--lang=en-US',
  ]
});

const page = await browser.newPage();
await page.setViewport({ width: 1920, height: 1080 });

// Override screen properties
await page.evaluateOnNewDocument(() => {
  Object.defineProperty(screen, 'availWidth', { get: () => 1920 });
  Object.defineProperty(screen, 'availHeight', { get: () => 1040 });
  Object.defineProperty(screen, 'colorDepth', { get: () => 32 });
});

This addresses the most common detection vectors but won't survive sophisticated analysis.

FAQ

Is Firefox headless more or less detectable than Chrome? Firefox headless has fewer well-documented detection vectors because less research has focused on it. However, Firefox headless mode has its own artifacts: different navigator.platform behavior, missing notification support, and distinct rendering characteristics. The smaller user base of Firefox headless means detection databases have fewer signatures — but it also means your traffic stands out more if the target primarily sees Chrome traffic.

Does Playwright or Puppeteer have lower detection rates? Comparable. Both use CDP to control Chrome and leave similar artifacts. Playwright's context isolation is slightly cleaner (each context is more isolated), but the fundamental detection vectors are the same. The choice between them should be based on API preference and feature needs, not detection avoidance.

How much more resource-intensive is headed mode with Xvfb? Approximately 30% more RAM (Chromium allocates GPU buffers for the virtual display) and 10-20% more CPU (rendering pipeline is active). For a single instance: 250MB headless vs 350MB headed with Xvfb. At 100 instances, that's 10GB additional RAM — significant but manageable on modern servers.

What about using real browser instances on real machines? The ultimate defense — remote desktop into real machines with real browsers. Services like BrowserStack, LambdaTest, or your own fleet of machines running real Chrome. Zero detection vectors because there's nothing to detect. The cost and management overhead is high, but for operations where detection has severe consequences, it's the most reliable option.

Written by Empirium Team

Explore More

Deep-dive into related topics across our five pillars.

Pillar Guide

Фингерпринтинг браузеров в 2026: что нужно знать

Технический разбор: 12 векторов и защита.

View all Stealth articles

Related Resources

Need help with this?

Talk to Empirium