Как отличить падение конверсии от потери событий
В тесте одна версия теряет почти все события покупки, а общий порог не срабатывает. Разбираем, как найти такое изменение и какие данные нужны, чтобы установить его причину.
8 минут чтенияОбновлено 6 сентября 2026
Падение конверсии может означать, что люди реже покупают, часть покупок перестала попадать в аналитику или изменился сам расчёт. Эти причины могут совпасть. По одной форме графика разделить их нельзя.
Общий порог пропускает потерю почти всех событий на одной версии
В тесте три версии приложения сначала отправляют по 900 событий checkout_completed в час. Затем у одной версии остаётся 20 событий в час, а у двух других ничего не меняется. До изменения тест содержит 20 часов наблюдений, после него — четыре часа.
| Версия | До | После |
|---|---|---|
| 4.11.0 | 900 | 900 |
| 4.12.0 | 900 | 900 |
| 4.13.0 | 900 | 20 |
| Все версии | 2 700 | 1 820 |
На версии 4.13.0 поток сократился на 97.8%, а суммарно — на 32.6%. Если проверка ищет падение минимум втрое, общий счётчик должен опуститься с 2 700 до 900. Значение 1 820 этого порога не достигает. Проверка каждой версии отдельно обнаруживает изменение.
Такой тест подтверждает способность найти заложенное отклонение. В рабочем приложении те же числа ещё не объясняют его причину: пользователи могли уйти со старой версии, перестать доходить до покупки или столкнуться с ошибкой её записи. Для конверсии нужен знаменатель — число попыток, в которых покупка могла состояться.
Числитель и знаменатель должны относиться к одним попыткам
Отношение числа завершений за сутки к числу стартов за те же сутки не всегда равно конверсии. Человек может начать оформление до полуночи и закончить после неё. Повторное открытие экрана может добавить ещё один старт, а повторная доставка — ещё одно завершение.
Для учебного расчёта определим конверсию как долю попыток оформления, у которых за 24 часа после старта есть событие завершения. Каждая попытка имеет уникальный checkout_id, который передаётся на обоих шагах. Повторные записи одной попытки не создают новый старт. Если продукт считает конверсию по людям или заказам, нужен другой ключ и соответствующее правило объединения.
Предположим, мы подготовили таблицу checkout_attempts: в ней одна строка на checkout_id, время первого старта started_at и версия на старте app_version. В таблице events лежат события с полями checkout_id, event_name и ts. Это схема примера, которую нужно сопоставить со своим хранилищем.
-- PostgreSQL. Все временные поля имеют тип timestamptz.
-- Источник уже полностью загружен до 25 августа, 00:00 UTC.
WITH attempts AS (
SELECT checkout_id, started_at, app_version
FROM checkout_attempts
WHERE started_at >= timestamptz '2026-08-17 00:00:00+00'
AND started_at < timestamptz '2026-08-24 00:00:00+00'
), outcomes AS (
SELECT a.*,
EXISTS (
SELECT 1
FROM events e
WHERE e.checkout_id = a.checkout_id
AND e.event_name = 'checkout_completed'
AND e.ts >= a.started_at
AND e.ts < a.started_at + interval '24 hours'
) AS completed
FROM attempts a
)
SELECT
(started_at AT TIME ZONE 'UTC')::date AS start_day,
app_version,
count(*) AS attempts,
count(*) FILTER (WHERE completed) AS completed_attempts,
round(100.0 * count(*) FILTER (WHERE completed)
/ count(*), 1) AS conversion_pct
FROM outcomes
GROUP BY 1, 2
ORDER BY 1, 2;Старт поздно вечером 23 августа получает полные 24 часа наблюдения. Для этого нужны завершения за 24 августа, хотя этот день не входит в список дней старта. При переносе запроса на свежие данные важно сохранить этот запас и дождаться их загрузки. Иначе последние попытки будут выглядеть неуспешными только потому, что ещё не успели завершиться или попасть в хранилище.
Сравнение по версиям должно учитывать переход пользователей
Сравните число стартов и долю завершений по версиям, платформам и часам. Для текущей проверки версию закрепляем на старте попытки: иначе обновление приложения между шагами может разделить её числитель и знаменатель между разными версиями.
| Что изменилось | Что проверять дальше |
|---|---|
| На старой версии стало меньше стартов и завершений, доля завершений прежняя. | Проверьте переход аудитории на новую версию. Одного падения объёма для вывода о поломке мало. |
| Старты новой версии сохраняются, а доля завершений снизилась. | Разделите ошибку оплаты и ошибку её записи: сопоставьте попытки с серверным результатом. |
| Доля завершений каждой версии стабильна, но общая конверсия снизилась. | Проверьте состав попыток: могла вырасти доля версии или аудитории с более низкой конверсией. |
Например, у двух групп конверсия остаётся 80% и 40%. При равном числе попыток общая конверсия составляет 60%. Если доля первой группы снизится до четверти, общая конверсия станет 50%, хотя внутри групп ничего не ухудшилось. Это расчётный пример изменения состава аудитории.
Часовой график и журнал релизов помогают выбрать период и версию для проверки. Резкое изменение может совпасть как с ошибкой SDK, так и с отключением способа оплаты. Плавное изменение может сопровождать постепенное распространение сломанной версии. Форма кривой помогает сузить поиск, но не определяет результат.
Серверный результат позволяет проверить конкретные покупки
Если в базе есть подтверждения оплаты, сопоставьте их с событиями по order_id или другому согласованному ключу. Сначала выберите одинаковые платформы, период и статусы, исключите тестовые операции и дождитесь загрузки обоих источников. Серверная оплата и открытие клиентского экрана могут описывать разные факты — это нужно установить до сравнения.
Для тех заказов, которые должны иметь событие завершения, посчитайте долю найденных событий. Затем откройте несколько несовпавших заказов и проверьте последовательность действий. Так общий недостаток записей превращается в конкретные случаи для воспроизведения.
| Что удалось установить | Какой вывод допустим |
|---|---|
| Сервер подтвердил оплату, но ожидаемого события по этому заказу нет после повторной полной загрузки. | Для этого заказа обнаружено расхождение. Следующая проверка отделит отсутствие отправки от потери при доставке или загрузке. |
| Попытка оплаты завершилась ошибкой сервера; успешной оплаты и события нет. | Отсутствие события согласуется с неуспешной покупкой. Нужно разбирать причину отказа оплаты. |
| Количество оплат и событий снизилось одинаково. | Это поддерживает гипотезу о снижении покупок, но не подтверждает полноту данных: сопоставьте записи, а не только суммы. |
Две системы могут одновременно терять данные, если зависят от одного загрузчика. Поэтому второй источник полезен настолько, насколько независим его путь записи. Отдельная таблица в той же неисправной загрузке не даёт независимой проверки.
Структура события и распределение значений требуют разных проверок
Отсутствие обязательного поля, число вместо строки и неизвестное имя события можно сопоставить с планом. Изменение доли оплат картой само по себе не нарушает схему: состав покупателей и доступность способов оплаты тоже меняются.
Если доля payment_method=card снизилась, посмотрите, вырос ли другой способ оплаты или доля записей без параметра. В первом случае проверьте изменение поведения и доступности способов оплаты. Во втором — условия заполнения поля по версиям и сценариям. Если доля считается только среди непустых значений, пропуски могут остаться незаметными.
Даже полное совпадение типов не гарантирует прежнего смысла. Приложение могло начать отправлять событие покупки после одобрения заявки вместо подтверждения оплаты. Такой случай разбирается в статье о поддержке плана при изменении события.
Проверка по срезам полезна, если не превращает обычные колебания в ошибки
Проверять каждую комбинацию версии, страны и экрана без ограничений нельзя: в малых группах отсутствие нескольких событий может быть обычным колебанием. Доля группы в общем потоке не задаёт универсальный порог. Один процент от тысячи событий и от миллиона событий даёт разный объём для сравнения.
Для автоматизации задайте минимальный объём наблюдений, сопоставимый базовый период и допустимую частоту ложных срабатываний. Проверьте правило на периодах без известных инцидентов и на примерах с заложенными потерями. Учитывайте, что при одновременной проверке множества групп случайных отклонений становится больше.
Тест из начала статьи покрывает один случай с постоянным потоком. Он не отвечает за сезонность, новые версии без истории и изменение аудитории. В таких случаях нужно явно решить, с чем сравнивать данные и когда наблюдений ещё недостаточно для вывода.
Разбор заканчивается выводом о проверенных данных и следующим действием
Полезный результат можно передать разработчику или владельцу метрики без пересказа всех графиков. В нём должны быть четыре вещи.
- Что изменилось. Укажите метрику, период, платформу и версию. Отдельно запишите изменения числа попыток и доли завершений.
- Какая проверка различила причины. Например, серверные оплаты найдены по ID заказа, а ожидаемые события отсутствуют после обновления выгрузки.
- Что осталось неизвестным. Например, пока не установлено, событие не отправилось или потерялось при загрузке. Эта граница определяет следующую проверку.
- Что делать с отчётом. Укажите затронутый период, возможность восстановления и данные, на которые пока можно опираться.
Если данные подтверждают снижение покупок, дальше проверяют продуктовые причины. Если обнаружена потеря событий, исправляют их путь и оценивают возможность восстановления. Если найдены обе проблемы, исправление разметки не отменяет разбор покупок.
Я разрабатываю Tarn и веду этот блог. Пишу о проверке событийных данных: как согласовать разметку, найти расхождение и установить, какие отчёты оно затронуло.
Tarn хранит план трекинга и каждый час сравнивает с ним события из вашей аналитики. Если возникает расхождение, разбор показывает, что изменилось, когда и в каком срезе, и помогает проверить возможные причины. Открыть демо можно без регистрации.