AntiDetect
Возможности Технология Цены Для кого
Документация Блог FAQ
Язык
EnglishItalianoDeutschEspañolРусский
Скачать

Headless Chrome — тупиковый путь

Новый headless закрыл брешь, открытую старым. Ту, что под ней, он не закрыл. Если вы всё ещё выбираете между headless и headful, вы оптимизируете не ту переменную — а есть третий вариант, который почти ничего не стоит.

Два режима headless, одна репутация

До Chrome 112 --headless означал старый headless: отдельная ветка бинарника, которая не была настоящим Chrome. У неё был свой user agent со строкой HeadlessChrome, не было поддержки расширений, не было chrome.runtime, не было списка плагинов, а путь отрисовки пропускал большие куски настоящего конвейера. Обнаружение укладывалось в одну строку.

В Chrome 112 появился новый headless (--headless=new, а с Chrome 132 — просто --headless). Это настоящий браузер, только окно не рисуется. Расширения работают, список плагинов заполнен, chrome.runtime существует, и user agent себя больше не выдаёт. Он закрыл почти все сигналы, которые протекали в старом режиме.

Репутация всё равно осталась — и во многом заслуженно. Новый headless убрал лёгкие следы. Чего он не убрал, так это слой под ними.

Что по-прежнему его выдаёт

SwiftShader, который завершает сессию

Самый надёжный сигнал и тот, на котором спотыкается большинство. Без видеокарты — а это обычное состояние сервера — Chrome переходит на программную растеризацию, и WebGL сообщает:

UNMASKED_VENDOR_WEBGL   → "Google Inc. (Google)"
UNMASKED_RENDERER_WEBGL → "ANGLE (Google, Vulkan 1.3.0 (SwiftShader Device ...))"

Такой пары нет ни на одном потребительском устройстве. Не «редко» — ноль. Никто не сидит в Instagram на программном рендеринге. Это не вероятностный сигнал, повышающий балл; это категорический сигнал, завершающий сессию.

По той же причине --disable-gpu — крайне плохой совет для этого сценария. Флаг массово копируют из веток по устранению проблем в Docker, где он лечит падение, и он принудительно включает ровно тот самый откат.

Окно, которого нет

Headless всё равно вынужден выдумать окно, и выдумка видна. outerWidth и outerHeight часто совпадают с innerWidth и innerHeight, потому что нет интерфейса, который нужно учесть: у настоящего десктопного Chrome разница около 16 пикселей по горизонтали и 85-90 по вертикали. screenX и screenY равны нулю. screen.availHeight совпадает с screen.height, а значит, на этой машине нигде нет ни панели задач, ни дока.

Ничто никогда не двигается

Ни движения мыши, ни инерции прокрутки, ни focus и blur при переключении окон, ни visibilitychange, когда вкладка уходит в фон. Cloudflare Turnstile и его аналоги следят за этим непрерывно, а не одной проверкой. Сессия с чистым отпечатком и нулём событий ввода — это сессия, прошедшая все статические тесты и провалившая единственный динамический.

Стек снизу

Headless не меняет отпечатки TLS и HTTP/2 — и это по-настоящему хорошая новость, ведь настоящая сборка Chromium даёт настоящие рукопожатия Chrome в любом случае. Не меняет он и поверхность CDP, где автоматизацию как раз и ловят. Смена режима не сдвигает ни то, ни другое.

Четыре слоя. Headless чинит один и ломает другой; два нижних он не трогает.

Почему стелс-плагины перестали работать

puppeteer-extra-plugin-stealth и его наследники накладывают набор JavaScript-заплаток на старте документа: прячут webdriver, наполняют navigator.plugins, подделывают chrome.runtime и так далее. В 2019 году этого часто хватало.

Сейчас — нет, и причина структурная, а не в качестве сопровождения. Каждая заплатка — это подмена в JavaScript, а у таких подмен есть форма. Нативные геттеры приводятся к строке как [native code]; заменители — нет. Свойства прототипа не выглядят как собственные свойства; заменители выглядят. И ни один скрипт уровня страницы не дотягивается до контекста Web Worker, поэтому любое значение, поправленное в главном потоке, расходится с копией внутри worker.

Опубликованные в 2026 году бенчмарки обнаружения сообщают о почти полной идентификации сессий со стелс-плагинами: один поставщик приводит для чистого Playwright 98,2 %, а для коммерческих browserless-сессий в стелс-режиме — 100 %, при доле ложных срабатываний ниже 1 %. Эти цифры от компании, которая продаёт обнаружение, и читать их надо с поправкой на это, но направление сомнений не вызывает.

Плагины написаны неплохо. Они просто работают на слое, который не способен выразить ответ.

Вариант, которого нет в меню

Противопоставление «headless или headful» скрывает вариант, который действительно работает: headful Chrome на виртуальном дисплее.

В Linux запустите Xvfb — настоящий X-сервер, который рисует в память вместо монитора. Chrome стартует вообще без флага --headless. Это полноценный браузер, рисующий полноценное окно, с настоящим GPU-рендерингом, если у хоста есть видеокарта. Обнаруживать headless-режим нечего, потому что его нет.

Xvfb :99 -screen 0 1920x1080x24 &
DISPLAY=:99 google-chrome --window-size=1920,1080

Что это чинит: сигнал SwiftShader (при наличии GPU), сигналы геометрии окна, отсутствующий интерфейс, availHeight и весь класс признаков «здесь нет дисплея». Чего не чинит: утечки CDP и поведение. Над ними нужно работать отдельно.

Цена вопроса — несколько десятков мегабайт ОЗУ на экземпляр и одна строка в скрипте развёртывания. По сравнению с поддержкой набора стелс-заплаток против движущейся мишени это почти даром.

Когда headless всё ещё уместен

Ничто из сказанного не делает headless бесполезным. Оно делает его неподходящим инструментом для одной конкретной задачи.

Headless хорош для: внутренних тестов, генерации скриншотов и PDF, обхода собственных сайтов, скрапинга ресурсов без антибот-защиты, CI-конвейеров, проверки ссылок, мониторинга доступности. Везде, где вас никто не пытается опознать, headless быстрее и легче — им и пользуйтесь.

Headless — неподходящий инструмент для: всего, что стоит за Cloudflare, Akamai, DataDome или PerimeterX; всего, где задействован аккаунт с активным входом на площадке, которой это небезразлично; всего, где попадание в категорию «автоматизация» чего-то стоит.

Разница не в технической изощрённости. Разница в том, есть ли противник.

Короткая диагностика

Если хотите понять, где сейчас ваша сборка, — четыре проверки в порядке информативности:

  1. Рендерер WebGL. Прочитайте UNMASKED_RENDERER_WEBGL. Если там упоминается SwiftShader, остановитесь и почините это в первую очередь; остальное не имеет значения.
  2. Геометрия окна. outerHeight - innerHeight в десктопном Chrome должен быть примерно 85-90, а screen.availHeight — меньше, чем screen.height.
  3. CreepJS. Загрузите его и прочитайте разделы про headless и про выявление подмен. Он прямолинеен в выводах.
  4. Настоящая цель. Загрузите сайт, который вам действительно важен, и посмотрите, выпадет ли проверка. Любой синтетический тест — лишь заменитель этого.

Прогоните те же четыре проверки в браузере, которым управляете руками на той же машине. Различия между двумя списками — это ваш список задач.

Headful, всегда

Профили P8 работают как настоящие окна с настоящим GPU-рендерингом. Автоматизация управляет ими так же, как это делал бы человек, и никакого headless-режима скрывать не приходится.

Начать бесплатно
Все статьи Далее: WebRTC нет дела до вашего прокси