
Два чтения одного отчёта воронки
Возьмём типовой отчёт интернет-магазина: «Каталог → Товар → Корзина → Оформление заказа → Оплата». До последнего шага дошло 38% сессий, оставшиеся 62% потерялись между «Оформлением» и «Оплатой». Так это выглядит в Яндекс Метрике, Google Analytics и любой другой системе веб-аналитики: доля дошедших до цели известна, причина потерь — нет.
Продуктовая аналитика прочитает эти 62% как повод для гипотезы «форма оформления слишком длинная» и поставит задачу на редизайн. Команда разработки прочитает те же 62% как конкретную JavaScript-ошибку на странице оформления — с текстом, стек-трейсом, версией браузера и числом затронутых сессий. Разница практическая: гипотезу проверяют неделями, и по итогам может выясниться, что она была неверной; ошибка с трейсом — уже готовая задача к исполнению. Пока данные о конверсии и данные об ошибках лежат в разных системах, выбор между этими объяснениями делается наугад.
Почему воронка молчит о причине
Инструменты веб-аналитики знают только о состоявшихся событиях. Конверсия засчитывается, когда код магазина после успешного создания заказа вызывает reachGoal("purchase") или кладёт событие purchase в dataLayer. Если до этого вызова дело не дошло — в обработчике клика по «Оплатить» возникло исключение, запрос к /api/orders не ушёл, заказ не создался, — отправлять нечего. На шаге «Оплата» такая сессия в воронке просто не появится. Пользователь со сломанной кнопкой и пользователь, который передумал платить, в отчёте неразличимы: оба не дошли до цели.
При этом в момент, когда кнопка не сработала, в браузере были все нужные данные: текст ошибки, стек-трейс, версия браузера и приложения, время загрузки страницы, признак предшествующего rage click. Но воронка живёт в системе веб-аналитики и оперирует достигнутыми целями, а ошибки — в системе мониторинга. Общего измерения, по которому их можно сопоставить, между этими системами нет.
Что должно оказаться на одной карте
Связующим объектом здесь работает Customer Journey Map, собранная из данных Real User Monitoring. Браузерный SDK на каждую навигацию создаёт view-событие. В SPA агент различает первичную загрузку и смену роута через атрибут loading_type со значениями initial_load или route_change. Внутри сессии эти события выстраиваются в последовательность страниц, последовательности агрегируются по всем сессиям — получается потоковая диаграмма Sankey, где узел это страница, а толщина ленты между узлами — число сессий за переход.
Поверх графа на каждую страницу навешивается индикатор здоровья: доля просмотров с ошибками и время загрузки. Проблемная страница помечается восклицательным знаком жёлтого или красного цвета. Отдельный режим оставляет на карте только проблемные переходы, остальное окрашивает серым — так видно, лежит ли просевший шаг воронки в технической плоскости.
Пороги, за которыми признак становится сигналом
Отсечка по времени загрузки установлена на 8 секунд. Ориентир — Apdex: пользователь считается неудовлетворённым при отклике выше 4T, и при типовом T в 2 секунды это ровно 8 секунд.
Почему не 4 секунды, знакомые по Core Web Vitals как граница плохого Largest Contentful Paint. LCP перестаёт обновляться после первого взаимодействия пользователя со страницей. Смена роута в SPA всегда следует за кликом, поэтому для таких переходов LCP не существует вовсе, а на карте путей это заметная доля узлов. Метрика loading_time считается и для них — от клика до момента, когда активность на странице прекращается. Для первичных загрузок она тоже расходится с LCP: в неё попадают сетевые запросы и изменения DOM уже после отрисовки самого крупного элемента, поэтому значения систематически выше. На практике с порогом в 4 секунды значок появлялся почти у каждого узла, и карта переставала читаться.
Порог по времени отвечает на вопрос, не слишком ли долго грузилось. Вторая величина на узле — доля просмотров с ошибками, здесь два порога: от 5% предупреждение, от 25% критический уровень.
Путь от карты до строчки в трейсе
Карта отвечает, где пользователь упирается в баг; дальше нужно показать, что именно пошло не так. Клик по странице выводит список сессий, в которых её открывали. Клик по переходу показывает сессии, где был переход со страницы A на страницу B; переход в «Выход» даёт ровно те сессии, что завершились на этом шаге. Клик по идентификатору сессии открывает её хронологию.
В сессии видно не только саму ошибку, но и что ей предшествовало: какие страницы пользователь открывал, куда кликал, были ли длительные задачи, блокирующие основной поток UI, и сигналы фрустрации. Клик, после которого произошла ошибка, помечен отдельно. Разворачивая событие, сразу видим текст ошибки, стек-трейс и контекст, который обычно приходится выпытывать у пользователя: город, IP, устройство и версия ОС, браузер, версия приложения, часовой пояс, страница входа и реферер. По каждому просмотру показываются LCP, FCP, INP, TTFB, CLS, время загрузки, длительность визита и число действий. Внутри просмотра разворачивается список ресурсов со статусом, методом, типом, размером и длительностью, с пометками, что весило больше всего, что вернулось без ответа и что заблокировало отрисовку.
Как гипотеза превращается в факт
На этих данных те 62%, что потерялись между «Оформлением» и «Оплатой», перестают быть поводом для версий. Видно, что пользователь пришёл из поиска, что страница оформления грузилась 5,7 секунды при LCP 4,7, что три ресурса вернули ошибку, а основной поток на две секунды заблокировала конкретная библиотека. Форма не была длинной. У разработки — готовая задача, у продукта — сэкономленный спринт на редизайн, который ничего бы не изменил.
Обратный случай тоже читается с карты. Если страница на пути к цели не помечена как проблемная — сбоев нет, время загрузки в норме, доля ошибок ниже порога, — и гипотезу нужно искать в продуктовой плоскости: длина формы, порядок полей, стоимость доставки, показанная слишком поздно.
Проактивная часть: оповещение по конверсии
Узнавать о просадке из отчётов — значит узнавать последним: через сломанный шаг успеют пройти тысячи пользователей, а поверх проблемного релиза выйдет ещё несколько. Правило по конверсии отслеживает долю сессий, доходящих до целевой страницы, и присылает уведомление, как только она уходит вниз; порог настраивается.
Дальше сценарий такой. В четверг утром приходит алерт о падении конверсии. Открываете анализ путей в режиме «К странице», выбираете «Заказ оформлен», период — сутки. Платформа показывает пути, которые ведут к этой странице, и изменение конверсии к прошлым суткам в процентных пунктах. Включаете режим ошибок: если целевая страница подсвечена, причина техническая, и клик по ней ведёт к сессиям со стек-трейсом; если не подсвечена, разбираться нужно с продуктом.
Критерий для приоритета
Воронка без ошибок — вопрос без ответа: известно, что пользователи теряются, но неизвестно почему, и оптимизация идёт вслепую. Список ошибок без воронки — ответ без вопроса: тысяча ошибок в сутки, и непонятно, какие из них стоят денег, а какие фонят у трёх человек с экзотическим браузером. Ценность появляется, когда оба набора данных лежат в одном инструменте: у фронтенд-команды появляется честный критерий для отладки — приоритет отдаётся ошибкам, из-за которых сессии не доходят до цели, даже если по частоте они уступают фоновым.
Обсудить проект
Остались вопросы? Напишите нам
Оставьте имя и телефон — перезвоним в течение часа, разберём задачу и предложим решение.