Короткий ответ
Строю пошаговую воронку (просмотр → корзина → оплата) с помощью условной агрегации для расчёта доли перехода между соседними шагами, затем сравниваю эти доли по периодам, чтобы локализовать шаг с падением.
Как это работает подробнее
общая конверсия — это произведение конверсий на каждом шаге воронки; падение на одном шаге может маскироваться стабильностью остальных, поэтому нужно считать conversion rate между каждой парой соседних шагов отдельно.
Пример кода
Пример SQL
WITH steps AS (
SELECT user_id,
min(event_ts) FILTER (WHERE event_type = 'view') AS t_view,
min(event_ts) FILTER (WHERE event_type = 'add_to_cart') AS t_cart,
min(event_ts) FILTER (WHERE event_type = 'purchase') AS t_purchase
FROM events
WHERE event_date = '2026-10-01'
GROUP BY user_id
)
SELECT
count(*) FILTER (WHERE t_view IS NOT NULL) AS viewed,
count(*) FILTER (WHERE t_cart IS NOT NULL) AS carted,
count(*) FILTER (WHERE t_purchase IS NOT NULL) AS purchased,
round(count(*) FILTER (WHERE t_cart IS NOT NULL)::numeric /
nullif(count(*) FILTER (WHERE t_view IS NOT NULL), 0), 2) AS view_to_cart,
round(count(*) FILTER (WHERE t_purchase IS NOT NULL)::numeric /
nullif(count(*) FILTER (WHERE t_cart IS NOT NULL), 0), 2) AS cart_to_purchase
FROM steps;Что использовать на практике
- Порядок действий. для каждого пользователя/сессии определяю, до какого шага он дошёл (первое событие view, первое добавление в корзину, первая оплата), затем считаю step-to-step conversion по периодам и сравниваю текущий период с базовым. Это позволяет точно указать: «конверсия из корзины в оплату упала с 40% до 25%», а не просто «конверсия упала».
Подводные камни
- Частые ошибки. считать общую воронку без разбивки по шагам и не находить, где именно проблема; не учитывать, что пользователь мог вернуться на предыдущий шаг несколько раз (нужно брать MIN(event_ts) на шаг); сравнивать абсолютные числа шагов вместо долей перехода, что чувствительно к изменению объёма трафика.