Содержание ↓
Разметку проверяют руками и по памяти
Аналитик открывает сайт с отладкой счётчика, кликает по кнопке, смотрит, какое событие ушло, делает скриншот и вставляет его в документ. На средний сайт так уходит день. Через месяц проверку не повторить: результат зависит от того, куда человек догадался нажать.
Этот инструмент я сделал вкладкой «События» в своём расширении для Chrome. Он отвечает на два вопроса: какое событие уходит в счётчик при клике по каждому элементу и где разметки нет совсем. Главное требование к нему скучное: свой сбой инструмент не должен выдавать за дефект сайта, иначе по отчёту полезут чинить исправную разметку.
Три слоя перехвата
Панель отладки Метрики на странице я не разбираю: это интерфейс для человека, и её вёрстка меняется без предупреждения. Вместо неё перехватываются три источника, и каждый видит своё.
| Слой | Что видит | Как снимается |
|---|---|---|
| Вызовы | что вызвал код сайта | обёртка над функцией счётчика, встаёт раньше его тега |
| Сеть | какие запросы ушли в Метрику и когда | наблюдатель ресурсов: адреса и время маячков, картинок и запросов без их содержимого, ничего не подменяя |
| Консоль | строки режима отладки _ym_debug=2 | перехват вывода в консоль |
Когда слои расходятся, это уже находка. Вызов есть, запроса нет — значит, счётчик не поднялся или цель отфильтрована. Бывает, что консоль не даёт ни строки ни в одном режиме отладки, поэтому отчёт держится на вызовах и сети.
Подмену отправки маячка я сначала поставил и в боевой режим. Метрика это заметила и написала в консоль сайта, что функцию переопределили. Теперь подмена живёт только в сухом прогоне, где отправку и надо глушить.
Запись и автообход
Оператор жмёт «Начать запись», вкладка перезагружается с параметром отладки, и дальше он ходит по сайту как обычно. Кадр элемента снимается на нажатии кнопки мыши. До отпускания проходит около 100 миллисекунд, и этого хватает, чтобы снять экран раньше, чем клик уведёт на другую страницу.
Автообход устроен как граф состояний. Клик необратим, поэтому движок помнит путь от входа, перезагружает страницу, повторяет путь и жмёт следующее неопробованное действие. Новый экран встаёт в конец очереди: сначала проходятся все карточки развилки, потом обход идёт вглубь. На квизе с пятью вариантами ответа бюджета в пять действий хватает на все пять веток.
Флоу оператор описывает словами: маски адресов, за которые обход не выходит, цели, по которым видно, что флоу дошёл до конца, и адрес финального экрана. Границу движок проверяет по адресу ссылки до клика. Точка в маске экранируется, иначе условная маска site.ru/quiz* пропустила бы и siteXru. Заканчивается флоу одним из трёх итогов — пройден, исчерпан или не начат. Пройденным он бывает только при заданных целях: если счётчик просто молчал, успехом это не засчитывается.
Тот же движок запускается и без расширения, из скрипта с Playwright и системным Chrome. Перехватчик скрипт берёт из собранного расширения, поэтому проверяется ровно тот код, который стоит у коллег. Так аудит можно ставить по расписанию.
Модели в аудите пока нет
Разбор хитов, отпечатки элементов, привязка событий к кликам, находки и сборка отчёта — чистые функции, их держат 166 тестов. В расширении осталась только работа с браузером: код внутри него тестами не покрыть, он расходится с ожиданиями молча, и замечают это уже у заказчика.
Модель появится в одном месте: она будет предлагать имя цели для неразмеченного элемента. Шаблон имени задаёт оператор, например {проект}-{год}_{экран}_{действие}-{объект}: действие из закрытого словаря на семь слов, объект не длиннее трёх слов. Условный пример: shop-2026_cart_click-checkout. Проверка имён регулярным выражением уже работает и даёт находку «имя вне шаблона». Имя, которое предложит модель, должно будет пройти ту же проверку: имена «почти в стиле» ломают любую сверку по префиксу. Сама подсказка имён ещё в работе.
Что в отчёте
Весь отчёт помещается в один HTML-файл. Кадры и стили лежат внутри, внешних ссылок нет, файл открывают с диска и пересылают в мессенджере. В шапке счётчики и покрытие в числах, дальше матрица вариантов флоу, экраны со строками «слева кадр элемента, справа его события», события вне кликов вроде автозагрузки и таймеров, дыры и аномалии, отказы обхода и сырой лог.
Находки бывают семи видов: элемент без события, вызов без запроса, одна цель на разных элементах, имя вне шаблона, цель вне эталона, цель-призрак из эталона, которая ни разу не сработала, и пропуски. Три вывода я развёл намеренно: «проверено, событий нет», «проверка не состоялась» и «пропущено». Спутаешь первые два — и разработчик пойдёт чинить кнопку, у которой с разметкой всё в порядке.
Грабли
Инструмент трижды выдавал свою ошибку за дефект сайта. Один раз он терял события на переходах: копил их в памяти страницы, и клик по ссылке уносил буфер с собой. Служебный вызов инициализации попадал под правило «хит не ушёл». А ненайденный элемент записывался как дыра в разметке. Каждую находку на контрольном сайте я теперь подтверждаю отдельным замером.
Сниппет Метрики начинается с присваивания функции самой себе. Без проверки на этот случай обёртка уходила в бесконечную рекурсию, страница висла, и виноватым выглядел сайт.
Служебный воркер третьего манифеста засыпает примерно через 30 секунд простоя, а между кликами оператора проходит больше. Если держать запись в переменной воркера, из сорока кликов до отчёта доедут последние два. Поэтому состояние живёт в сессионном хранилище браузера. Клоны карусели склеиваются по атрибуту цели, иначе каждый клон дал бы ложное «элемент без события».
Из находок ревью DeepSeek и GPT две были самыми неприятными. В обходе не было ни одного перехвата ошибок, и элемент, исчезнувший между снимком и кликом, убивал весь прогон вместе с кадрами. А мост между скриптом страницы и расширением принимал любое сообщение с нашей меткой, то есть любой скрипт сайта мог подсунуть в отчёт выдуманную цель.
Один флоу для начала
Хватит одного флоу, по которому считаются деньги, например заявки или корзины. Под вашу аналитику такой контур удобно раскладывать на консультации, а если задача шире одного инструмента, пригодится страница про внедрение ИИ в маркетинг. Логику я бы снова писал первой и сразу под тесты, браузерную обвязку — после неё, обход — последним. Алгоритм обхода, написанный прямо поверх браузера, проверить нечем: живой сайт меняется между запусками.
- расширение Chrome (Manifest V3)
- Plasmo
- TypeScript
- Playwright
- Vitest
- Яндекс Метрика
