- BrainTools - https://www.braintools.ru -

Кто открывает ваш сайт, когда растёт посещаемость?

График посещаемости ползёт вверх уже третью неделю, маркетинг радуется охватам. Заказы стоят на месте. Продакт смотрит на конверсию, которая падает, и разбирает воронку по шагам, пытаясь найти, где она сломалась.

Часть новых «посетителей» в таком графике оказывается браузерами, за которыми не сидит ни один человек. 30 сентября 2026 Cloudflare написал, что впервые больше половины трафика в интернете сделали не люди. Запросы AI‑агентов [1] за год выросли больше чем на 1700%.

Краулеры, а их среди ботов большинство, JavaScript не исполняют. Без JavaScript счётчик молчит.

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

Счётчик слышит только тех, кто исполнил JavaScript

Счётчик аналитики живёт скриптом на странице. Пока браузер не исполнил JavaScript, хита нет.

Чтобы посмотреть, кто из автоматических гостей до хита доходит, я повесил на тестовую страницу свой мини‑счётчик и по очереди открывал её всем, что обычно ходит по сайтам само: curl, Python, Chromium через Playwright в разных режимах, с маскировкой и без.

Снимает он примерно то же, что теги Метрики и GA4. При загрузке собирает данные о браузере и отправляет их на сервер, через 3 секунды шлёт пинг «посетитель ещё здесь», при закрытии вкладки отправляет последний хит. И ставит собственную, first‑party куку, как ym_uid или _ga:

// send() — fetch/sendBeacon на /collect, webglRenderer() — UNMASKED_RENDERER_WEBGL
var m = document.cookie.match(/(?:^|; )lab_uid=([^;]+)/);
var returning = !!m;
var uid = m ? m[1] : (Date.now() + '.' + Math.floor(Math.random() * 1e9));
document.cookie = 'lab_uid=' + uid + '; path=/; max-age=31536000; SameSite=Lax';

send('hit', {
  ua: navigator.userAgent, webdriver: navigator.webdriver,
  brands: navigator.userAgentData?.brands, platform: navigator.platform,
  tz: Intl.DateTimeFormat().resolvedOptions().timeZone,
  screen: [screen.width, screen.height],
  inner: [innerWidth, innerHeight], outer: [outerWidth, outerHeight],
  webgl: webglRenderer(), returning: returning,
});

Рядом nginx пишет в свой лог заголовки User-Agent, Sec-CH-UA, Accept-Language и Referer. Если положить лог и хиты счётчика рядом, видно, кто где оставил след:

клиент                                  access log   хит счётчика
curl                                         да           нет
python requests                              да           нет
curl с User-Agent GPTBot                     да           нет
Playwright headless по умолчанию             да           да
Playwright, новый headless                   да           да
Chrome headful под виртуальным экраном       да           да
chrome --headless --dump-dom без Playwright  да           да

Всё, что не исполняет JavaScript, остаётся только в логе сервера и в отчёты не попадает. Так ведут себя крупные AI‑краулеры.

При этом те же краулеры OpenAI и Anthropic JS‑файлы скачивают, но не запускают. Из крупных JavaScript исполняют Gemini, который ходит через инфраструктуру Googlebot, и AppleBot. Свежих независимых замеров на эту тему я не нашёл.

Если трафик на сервере вырос, а в Метрике нет, скорее всего, это они или мониторинги со скрейперами, и для аналитики они безвредны.

А любой Chromium, который открыл страницу, отправил полноценный визит со страницей, длительностью, кукой и разрешением экрана. В отчёте такой визит ничем не отличается от человеческого.

Headless Chrome без маскировки

Сначала самый простецкий вариант — chromium.launch(headless=True) в Playwright без всяких настроек.

Такой запуск берёт отдельную сборку chrome-headless-shell, бывший «старый headless», который в Chrome 132 выкинули из основного бинарника и оставили отдельным пакетом. Выдаёт он себя сразу и везде:

User-Agent:        ... HeadlessChrome/153.0.8010.12 Safari/537.36
Sec-CH-UA:         "HeadlessChrome";v="153", "Not_A Brand";v="8", "Chromium";v="153"
Accept-Language:   (заголовка нет)
navigator.webdriver           true
navigator.plugins             []
window.chrome                 undefined
Notification.permission       denied      permissions.query → prompt
navigator.connection.rtt      0
screen                        1280x720

HeadlessChrome стоит и в UA, и в Client Hints, заголовка Accept-Language нет, плагины пустые, а два способа спросить разрешение на уведомления противоречат друг другу.

Фильтру тут хватило бы одной проверки строки UA.

С channel='chromium' Playwright запускает полноценный Chrome в новом headless‑режиме, и картина уже другая. Плагины на месте, window.chrome [2] есть, разрешения друг другу не противоречат.

HeadlessChrome остаётся только в строке User‑Agent, а в Sec-CH-UA и navigator.userAgentData.brands стоят обычные "Chromium";v="153", "Not_A Brand";v="8".

Детектор, который перешёл на Client Hints, потому что «UA устарел», новый headless пропускает.

navigator.webdriver равен true во всех запусках через Playwright, даже с видимым окном, и становится false от одного флага при запуске: --disable-blink-features=AutomationControlled.

Забавно, что голый chrome --headless, запущенный без всякой автоматизации, webdriver вообще не выставляет. Зато chrome-headless-shell, запущенный тем же способом, его выставляет.

Кстати, флаг --headless=old по объявлению команды Chrome с версии 132 должен печатать ошибку [3]. Chrome 153 принял его молча и отработал в новом режиме с тем же отпечатком.

Что остаётся после пары строк маскировки

Теперь повторим то, что делает любой, кто хоть раз писал парсер. Подменяем User‑Agent на Chrome под Windows, ставим нормальный экран 1536×864, русский язык, московское время, флаг против webdriver, реферер с Яндекса и десяток движений мыши со скроллом:

browser = p.chromium.launch(channel='chromium', headless=True,
    args=['--disable-blink-features=AutomationControlled'])
ctx = browser.new_context(
    user_agent=WINDOWS_CHROME_UA,
    viewport={'width': 1536, 'height': 730},
    screen={'width': 1536, 'height': 864},
    device_scale_factor=1.25,
    locale='ru-RU', timezone_id='Europe/Moscow',
)
page = ctx.new_page()
page.goto(url, referer='https://yandex.ru/')
for i in range(10):
    page.mouse.move(100 + i * 30, 200 + i * 10)
page.mouse.wheel(0, 1200)

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

Мышь и скролл пришли с isTrusted = true. Для скрипта на странице это настоящие события, и по флагу их не отличить.

Хит счётчика после маскировки выглядит так:

User-Agent         Windows NT 10.0; Win64; x64 ... Chrome/153.0.0.0
navigator.platform Linux x86_64
Sec-CH-UA          "Chromium";v="153", "Not_A Brand";v="8"
Accept-Language    ru-RU
outer / inner      1536x730 / 1536x730
WebGL              ANGLE (Google, Vulkan 1.3.0 (SwiftShader Device ...))
cookie             новая на каждый визит в новом контексте

UA говорит «Windows», navigator.platform говорит «Linux». Playwright подменил заголовок и Client Hints, а свойство в JavaScript оставил как есть.

Похожее расхождение находили у ChatGPT agent, только там оно видно прямо в заголовках, где UA от Chrome на macOS соседствует с Sec-Ch-Ua-Platform: "Linux".

Среди брендов нет "Google Chrome", потому что Playwright запускает сборку Chrome for Testing, а у живых людей стоит фирменный Chrome.

Accept-Language пришёл одним значением, без хвоста вида ru-RU,ru;q=0.9,en;q=0.8. Живой Chrome пока обычно шлёт такой хвост, но Google давно готовит урезание заголовка до одного языка, так что признак временный.

Внешний размер окна равен внутреннему, потому что Playwright эмулирует окно в headless без рамки, вкладок и адресной строки. В видимом окне outerHeight больше innerHeight на высоту вкладок и адресной строки.

SwiftShader в WebGL — программный рендерер, который Chrome включает, когда нет видеокарты. Он был во всех прогонах, включая браузер с окном, так что к headless отношения не имеет.

Облачный сервер без GPU выдаёт себя им, но и живой человек в виртуалке на работе тоже. Поэтому признак годится только в сумму с другими.

К тому же Chrome 153 уже пишет в лог, что автоматический откат на программный WebGL устарел, и в будущих версиях без GPU WebGL может не создаться вовсе.

IP‑адрес датацентра в браузере никак не правится.

Фильтры Метрики и GA4

GA4 автоматически исключает трафик известных ботов по списку, который составлен по исследованиям Google и по списку IAB.

Плюс там написано, что отключить это исключение нельзя и посмотреть, сколько трафика отсеяно, тоже нельзя.

Headless‑браузер с нормальным UA в такой список не попадает и проходит как пользователь. Канал «AI Assistant», который появился в GA4 в мае 2026, собирает переходы по ссылкам из ChatGPT, Gemini и Claude, ботов он не касается.

Роботов, которые представились в User‑Agent, Метрика исключает из статистики сразу, их видно в отчёте «Роботы».

Роботы, найденные по поведению [4], по умолчанию в статистике учитываются. Чтобы увидеть данные без них, в отчёте переключают «Данные: без роботов», и там же есть «Сравнить с данными с роботами».

Когда посещаемость растёт, а заказы нет, с этого сравнения проще всего начинать, и заметное расхождение двух режимов уже повод присмотреться к трафику.

Второе сравнение придётся делать уже вне Метрики. Рост в отчёте кладут рядом с ростом в логе сервера, и разница между ними и есть то, что прошло мимо фильтров.

В настройках счётчика есть опция «фильтровать роботов по поведению». Нужна она в основном для выгрузки через Logs API и действует только на данные, пришедшие после включения.

В Logs API у визита есть поле ym:s:isRobotPro, но только для Метрики Про и с данными с 19 апреля 2025. Поля с провайдером или ASN там нет вообще, его придётся добавлять самим по IP.

Почерк в выгрузке

Раз аналитика не говорит, сколько ботов она пропустила, смотрим сами по визитам из Logs API.

Я смоделировал четыре недели трафика. Со второй половины месяца к людям добавляется поток headless‑визитов, а с ним и немного агентов, которые скроллят и сидят на странице.

Доли я задал руками, поэтому сами проценты ничего не доказывают. Смотреть имеет смысл на то, какие признаки двигаются вместе:

SELECT period, count(*) / 14                      AS sessions_per_day,
       round(avg(ref = 'direct') * 100, 1)        AS direct_pct,
       round(avg(bounce) * 100, 1)                AS bounce_pct,
       round(avg(asn_type = 'hosting') * 100, 1)  AS hosting_pct,
       round(avg(tz = 'UTC') * 100, 1)            AS tz_utc_pct,
       round(avg(lang = 'en-US') * 100, 1)        AS en_pct,
       round(avg(is_returning) * 100, 1)          AS returning_pct
FROM visits GROUP BY period;
period  sessions_per_day  direct  bounce  hosting  tz_utc  en-US  returning
до                   650    24.3    20.2     11.8     2.2    6.1       29.7
после               1092    51.0    45.3     46.5    28.7   39.8       17.5

По отдельности каждый сдвиг объясним. Прямые заходы растут от рассылки, отказы — от кривого лендинга, английский язык — от рекламы на зарубежную аудиторию.

Объяснить так же рост всех трёх сразу, да ещё вместе с падением доли вернувшихся, уже трудно.

Среди разрешений экрана 1280×720 выросло в 35 раз, а 800×600 появилось с нуля. Оба значения дают по умолчанию Playwright и голый Chrome.

А 1920×1080 выросло всего в 2,6 раза, хотя ботов с ним много, потому что это самое частое разрешение и у людей. Признак «одинаковые экраны» работает только на значениях, нетипичных для вашей аудитории.

Поведенческие признаки поодиночке бьют по людям. В модели я задал людям 24% прямых заходов и 20% отказов, и столько же живых посетителей эти правила и пометили бы, а «новый посетитель» не говорит вообще ничего.

Признаки окружения вроде UTC или экрана 1280×720 людей почти не задевают, зато ловят только часть ботов.

Связка «хостинговая сеть, прямой заход и либо визит до 2 секунд, либо ноль скролла» ловит 86% ботов и задевает 0,43% людей, и ради неё к выгрузке из Logs API приходится дописывать разметку IP по ASN.

Из агентов, которые ведут себя по‑человечески, та же связка поймала 215 из 844.

Связка без поведения [5], «хостинговая сеть, новый посетитель и серверный экран», поймала 745 агентов из 844 и задела 1,2% людей.

Поведение хорошо отсекает тупых краулеров и проваливается на агентах. Дольше держатся сеть и то, что не правится в контексте браузера, вроде рендерера WebGL, рамки окна и navigator.platform.

Сеть в модели ловит всех ботов только потому, что я так её задал. В жизни у людей есть квн, а у ботов прокси.

Подпись, которую видит только сервер

У настоящих агентов появился способ представиться, и ChatGPT agent им пользуется.

Он работает на облачной виртуальной машине OpenAI и подписывает свои запросы по RFC 9421 заголовками Signature, Signature-Input и Signature-Agent: "https://chatgpt.com [6]".

Подписи видит сервер, а JavaScript‑счётчику заголовки запроса недоступны, поэтому сосчитать такие визиты можно только по логу nginx:

log_format bots '$remote_addr "$http_user_agent" '
                'agent="$http_signature_agent" "$request" $status';
access_log /var/log/nginx/bots.log bots;

Кавычки внутри значения nginx по умолчанию экранирует как x22, и грепать такой лог придётся с поправкой на это.

Подпись сверяют с ключами, которые агент публикует у себя в /.well-known/http-message-signatures-directory.

Сам протокол Web Bot Auth пока черновик рабочей группы IETF от 1 сентября 2026, но подписывают по нему уже OpenAI, Google и AWS.

Агент в браузере пользователя и есть пользователь

Всё это касается агентов, которые ходят из облака. Агенты, которые живут в браузере самого человека, вроде Perplexity Comet, ChatGPT Atlas и Claude in Chrome, для Метрики и GA4 от него неотличимы.

Atlas и Comet отдают стандартный UA Chrome.

Atlas в агентном режиме, по наблюдениям исследователей из HUMAN Security, выдаёт себя в основном фоновыми запросами favicon.ico со своим UA, и увидеть это опять же можно только в логе сервера.

Comet оставляет на странице следы своего внутреннего расширения, но стандартный счётчик их не ищет.

Если человек попросил агента сравнить цены в трёх магазинах, в каждом из них останется визит с глубиной и временем на сайте.

Остаётся ещё ровный ночной трафик, на который рассчитывают при поиске ботов. Против краулеров он работает, против агентов, по данным того же Cloudflare, нет. Их трафик повторяет человеческий недельный цикл и даже летний спад, потому что запускают их люди.

Ловилось в этих прогонах только то, что выдаёт машину, на которой крутится браузер, с её датацентровым IP, программным WebGL и окном без рамки. Заголовки, язык, экран и движения мыши меняются парой строк в контексте Playwright.

У агента в браузере пользователя машина та же, что у человека, и ни один из этих признаков на нём не срабатывает.

Как с такими визитами поступит Метрика, я не проверял. По справке, где нет даже слова headless, этого не понять. Похоже, считать их придётся новым видом посетителя, у которого просто другая конверсия.

А у вас в логе nginx уже попадался Signature-Agent?

Кто открывает ваш сайт, когда растёт посещаемость? - 1

Если хотите отличать реальный интерес [7] пользователей от активности ботов и AI‑агентов, важно научиться анализировать события, находить аномалии и настраивать мониторинг.

На бесплатных уроках разберём инструменты, которые помогут лучше контролировать происходящее в системе:

  • 18 ноября, 20:00. «Что SIEM не увидит “из коробки”: корреляция событий и оценка качества детектора». Записаться [8]

  • 30 ноября, 20:00. «Grafana на практике: от настройки дашбордов до автоматизации». Записаться [9]

Больше вебинаров по разработке, аналитике и ИИ — в ноябрьском дайджесте [10]

Автор: badcasedaily1

Источник [11]


Сайт-источник BrainTools: https://www.braintools.ru

Путь до страницы источника: https://www.braintools.ru/article/38133

URLs in this post:

[1] AI‑агентов: https://otus.pw/zZ3Q/

[2] window.chrome: http://window.chrome

[3] ошибку: http://www.braintools.ru/article/4192

[4] поведению: http://www.braintools.ru/article/9372

[5] поведения: http://www.braintools.ru/article/5593

[6] https://chatgpt.com: https://chatgpt.com

[7] интерес: http://www.braintools.ru/article/4220

[8] Записаться: https://otus.pw/ika7/

[9] Записаться: https://otus.pw/0nLv/

[10] ноябрьском дайджесте: https://otus.pw/Vk19/

[11] Источник: https://habr.com/ru/companies/otus/articles/1099254/?utm_source=habrahabr&utm_medium=rss&utm_campaign=1099254

www.BrainTools.ru

Rambler's Top100