Daily MaverickOUR CITY NEWS: Zille to ‘go into opposition’ if DA doesn’t win a workable coalition in JoburgThe Jerusalem PostFirst women on ultra-Orthodox party slate running for Knesset seek change - interviewInquirerPCSO lotto results Oct. 12: No winner of ₱265.5-M jackpotESPN DeportesBrewers vino de atrás ante Dodgers y abrió con triunfo SCLNESPNKCP: Sixers' success hinges on chemistry, players 'liking each other'RTP DesportoTreinador do Lens avisa para experiência do SportingAnime News NetworkKilling Bites Manga Publishes 1st Part of Final ChapterGIGAZINE各社のAIがリリース後にどれだけ性能変化したかがグラフでわかるベンチマーク「Nerf Bench」BBC NewsUS actress Selma Blair accused of assault after incident with flight attendantsCBS NewsSaudi airport stays shut as Houthi attacks kill 20 people in a weekMeduzaВ Беларуси освятили икону, созданную искусственным интеллектом3DNewsIntel вырезала из GPU блоки 3D-графики и трассировки лучей ради ИИ — представлен D270 с поддержкой до 480 Гбайт LPDDR5X
The Daily Newsstand · Free, Always
Monday, October 12, 2026

Конверсия упала на 14% за ночь. Найдите причину за 20 минут

Translate

Всем привет, меня зовут Сергей Прощаев, я Tech Lead и руководитель направления Java | Kotlin разработки в FinTech & E-commerce и преподаю на курсах разработки и архитектуры в ОТУС. В этой статье расскажу про задачу, которую любят давать продуктовым аналитикам на собеседованиях и которая в жизни приходит без предупреждения: метрика упала, у вас двадцать минут и созвон с директором.

Четверг, 09:40. Ночью пересчитался дашборд, и в рабочем чате сообщение от продакта: «Конверсия за среду 3,18%, во вторник была 3,70%. Минус 14% за ночь. Что случилось? В 11:00 созвон с директором, нужен ответ». Цены не менялись, ассортимент тот же.

Ниже все вводные, которые есть у аналитика в этот момент. Попробуйте сначала решить сами, а потом сверьтесь с разбором.

Рис. 1. Одна линия на дашборде, а под лупой две разные причины

Рис. 1. Одна линия на дашборде, а под лупой две разные причины

Условие

Интернет-магазин продаёт через сайт и два мобильных приложения. Конверсия на дашборде считается просто: число событий purchase в продуктовой аналитике делим на число сессий. Строго говоря, это покупки на сессию, но в учебной модели сессия даёт не больше одного заказа, а исправный трекинг — одно событие на заказ, так что метрика совпадает с долей сессий с покупкой. Сравниваем полные сутки вторника и среды.

Что известно о среде:

  • в 06:00 вышел релиз iOS-приложения 5.2, главное в нём — новый экран оплаты;

  • с утра маркетинг запустил посевы в Telegram-каналах, ссылки ведут на сайт и в магазины приложений;

  • ошибок на бэкенде нет, время ответа обычное.

Таблица 1. Дашборд по платформам, конверсия по событиям purchase

Платформа

Сессии, вт

Покупки, вт

CR, вт

Сессии, ср

Покупки, ср

CR, ср

Изменение

Web

50 000

1 650

3,30%

61 500

1 899

3,09%

−6,4%

Android

30 000

1 050

3,50%

37 200

1 201

3,23%

−7,8%

iOS

30 000

1 370

4,57%

31 300

1 035

3,31%

−27,6%

Итого

110 000

4 070

3,70%

130 000

4 135

3,18%

−14,0%

Таблица 2. Тот же дашборд в разрезе новых и вернувшихся пользователей

Сегмент

Сессии, вт

Покупки, вт

CR, вт

Сессии, ср

Покупки, ср

CR, ср

Web, новые

20 000

300

1,50%

31 000

496

1,60%

Web, вернувшиеся

30 000

1 350

4,50%

30 500

1 403

4,60%

Android, новые

10 000

150

1,50%

17 000

272

1,60%

Android, вернувшиеся

20 000

900

4,50%

20 200

929

4,60%

iOS, новые

8 000

160

2,00%

9 000

136

1,51%

iOS, вернувшиеся

22 000

1 210

5,50%

22 300

899

4,03%

Таблица 3. Оплаченные заказы из биллинга, которые аналитик до этого момента не проверял. Тип пользователя записывается в заказ при оформлении.

Сегмент

Заказы, вт

Заказы, ср

Web, новые

300

496

Web, вернувшиеся

1 350

1 403

Android, новые

150

272

Android, вернувшиеся

900

929

iOS, новые

160

189

iOS, вернувшиеся

1 210

1 249

Итого

4 070

4 538

Попробуйте решить

Сначала короткий вопрос: что бы вы проверили первым, имея эти три таблицы и двадцать минут?

А теперь главный: что вы скажете директору в 11:00? Выберите вариант или сформулируйте свой:

  • А. Релиз iOS 5.2 сломал оплату, нужно откатывать.

  • Б. Упало на всех трёх платформах, значит, причина внешняя: день недели, погода, конкурент. Ждём.

  • В. Посевы привели нецелевой трафик, кампанию надо останавливать.

  • Г. Покупок больше, чем вчера, тревога ложная.

Остановитесь здесь. Дальше разбор.

Неправильные ответы и почему они выглядят логично

А. «Релиз сломал оплату»

Самый соблазнительный ответ. Падение на iOS почти 28%, релиз вышел в 06:00, новый экран оплаты — всё сходится. Мысль понятная: что выкатили, то и сломалось.

Ломается он на Таблице 3. Оплаченных заказов с iOS в среду 1 438, во вторник было 1 370. Люди платят, и даже чуть чаще. Сломалась не оплата, а событие о ней. Откат релиза вернул бы старый экран, но оплаты и так проходили. А главное, этот ответ не объясняет, почему просели Web и Android, где релизов не было.

Б. «Упало везде, значит, причина внешняя»

Логика такая: если просели все платформы, значит, дело не в коде, а в мире вокруг. Звучит разумно, и на Таблице 1 действительно минус на каждой строке.

Таблица 2 этот вывод опровергает. У Web и Android конверсия выросла во всех четырёх сегментах: у новых с 1,50% до 1,60%, у вернувшихся с 4,50% до 4,60%. Общего ухудшения внутри сегментов нет, а значит, внешний фактор если и был, то менял состав трафика, а не поведение покупателей.

В. «Посевы привели плохой трафик»

Этот ответ ближе всех к правде, поэтому он опаснее остальных. Новых сессий в среду заметно больше, у новых конверсия ниже, чем у вернувшихся, общая цифра падает — механика верная.

Но слово «плохой» здесь лишнее. По событиям конверсия новых почти не изменилась, 1,61% и 1,59%, а по биллингу выросла с 1,61% до 1,68%: события искажены пропусками на iOS. А ещё этот ответ объясняет только часть падения. Если остановиться на нём, сломанный счётчик на iOS останется незамеченным, и через неделю дашборд будет врать уже про другое.

Г. «Покупок больше, тревога ложная»

В среду зафиксировано 4 135 событий purchase против 4 070 во вторник. Кажется, всё в порядке. Но сессий стало на 18% больше, а покупок по аналитике — всего на 1,6%. Абсолютное число при росте трафика ничего не доказывает, и на собеседовании эту ловушку проверяют одной из первых.

Правильный ход мысли

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

Рис. 2. Порядок проверок: сначала измерение, потом структура метрики, потом поиск причины

Рис. 2. Порядок проверок: сначала измерение, потом структура метрики, потом поиск причины

Главная мысль схемы: вопрос «кто виноват» стоит в самом конце. Пока не доказано, что счётчик исправен, любая гипотеза о поведении пользователей строится на песке.

Шаг 1. Проверить измерение, пять минут

Первым делом сверяем события аналитики с источником фактических оплат, то есть с биллингом. Не в целом за день, а по платформам и по часам, в явных границах суток:

-- сверка событий аналитики с оплаченными заказами за среду по платформам и часам
SELECT b.platform,
       date_trunc('hour', b.paid_at, 'Europe/Moscow')  AS hour,
       count(DISTINCT b.order_id)                      AS orders_billing,
       count(DISTINCT e.order_id)                      AS orders_with_event,
       count(DISTINCT b.order_id)
         - count(DISTINCT e.order_id)                  AS orders_without_event,
       count(e.order_id) - count(DISTINCT e.order_id)  AS duplicate_events,
       round(1 - count(DISTINCT e.order_id)::numeric
                 / count(DISTINCT b.order_id), 3)      AS gap
FROM billing.orders b                       -- только оплаченные заказы
LEFT JOIN analytics.purchase_events e ON e.order_id = b.order_id
WHERE b.paid_at >= '2026-10-07 00:00 Europe/Moscow'::timestamptz
  AND b.paid_at <  '2026-10-08 00:00 Europe/Moscow'::timestamptz
GROUP BY 1, 2
ORDER BY 1, 2;

count(DISTINCT ...) здесь не для красоты. Если одно событие пришло дважды, обычный count(*) после соединения размножит строки и спрячет пропуски за дублями. Поэтому сверка показывает отдельно заказы без события и повторные события. Границы суток заданы с часовым поясом бизнеса, иначе их сдвинет настройка сессии базы. И честное ограничение: запрос проверяет, есть ли у оплаченного заказа хоть одно сопоставленное событие. Опоздавшее событие он засчитает как вовремя пришедшее, а событие без order_id с заказом не свяжет. Для поиска пропусков этого достаточно, задержки доставки контролируют отдельно.

Результат: у Web и Android разрыв нулевой, дублей нет. У iOS до 06:00 среды разрыва нет, а начиная с часа релиза 30% оплаченных заказов остаются без события, за сутки выходит 28%. Если в заказе пишется версия приложения, добавьте её в группировку: весь разрыв окажется у версии 5.2. Самая вероятная гипотеза — новый экран оплаты не отправляет purchase, подтверждают её логами отправки событий с клиента. Это задача мобильной команде, а не откат.

Этот шаг пропускают чаще всего, а поломки учёта случаются по расписанию. Свежий пример — Shopify. По документации платформы, 26 августа 2026 года на странице статуса заказа перестали выполняться script tags у всех магазинов не на тарифе Plus, у Plus это случилось ещё 28 августа 2025-го. Для отслеживания конверсий Shopify заранее предлагал замену, web pixels. Но если покупку в аналитику и рекламные кабинеты отправлял старый скрипт, а его не перенесли, заказы продолжали идти, а событие покупки просто перестало приходить. Витрина и оформление заказа при этом работают как обычно, так что такую поломку замечают по просевшим конверсиям, а не по алертам. Сверка с биллингом из шага 1 ловит такую поломку в первый же час.

Шаг 2. Пересчитать конверсию по оплаченным заказам

Берём заказы из биллинга: 4 538 на 130 000 сессий, это 3,49%. Падение уже не 14%, а 5,7%. Больше половины тревоги дал сломанный счётчик. Но 5,7% — тоже не ноль, и тут большинство останавливается, решив, что «остальное — шум». Не останавливаемся.

Следующий вопрос простой: что сдвинулось, числитель или знаменатель? Конверсия — дробь, и падение дроби ещё не значит, что стало меньше покупок. Заказов по биллингу стало больше на 11,5%, сессий — на 18,2%. Покупатели никуда не ушли, просто в магазин пришло заметно больше людей, чем обычно, и знаменатель обогнал числитель. Значит, искать надо не того, кто «отпугнул» покупателей, а того, кто привёл новых посетителей.

Проверяем разрезом по источнику трафика. По UTM-меткам на сайте и атрибуции установок через Universal Links и App Links в приложениях из 20 000 дополнительных сессий 19 000 пришли из Telegram: 11 000 на сайт, 7 000 в Android и 1 000 в iOS. Во вторник таких не было, а прямые заходы, поиск и прочие источники вместе дали ещё 1 000. Это связь по времени и по меткам, а не эксперимент, но для ответа директору её достаточно.

Шаг 3. Разложить оставшееся падение

Общая конверсия — это средневзвешенное конверсий сегментов, где вес — доля сессий сегмента. Значит, она может упасть по двум причинам: либо сегменты стали хуже конвертировать, либо вырос вес сегментов, которые конвертируют хуже. Это разные диагнозы и разные действия, поэтому их надо разделить в цифрах:

# Разложение изменения конверсии: эффект состава, эффект сегментов и перекрёстный член.
# Сегмент = платформа x тип пользователя, заказы из биллинга (Таблица 3).
tue = {("web", "new"): (20000, 300), ("web", "ret"): (30000, 1350),
       ("android", "new"): (10000, 150), ("android", "ret"): (20000, 900),
       ("ios", "new"): (8000, 160), ("ios", "ret"): (22000, 1210)}
wed = {("web", "new"): (31000, 496), ("web", "ret"): (30500, 1403),
       ("android", "new"): (17000, 272), ("android", "ret"): (20200, 929),
       ("ios", "new"): (9000, 189), ("ios", "ret"): (22300, 1249)}

def decompose(a, b):
    assert a.keys() == b.keys(), "наборы сегментов должны совпадать"
    sa = sum(s for s, _ in a.values())
    sb = sum(s for s, _ in b.values())
    w = lambda d, s, k: d[k][0] / s          # доля сессий сегмента
    r = lambda d, k: d[k][1] / d[k][0]       # конверсия сегмента
    mix = sum((w(b, sb, k) - w(a, sa, k)) * r(a, k) for k in a)
    seg = sum(w(a, sa, k) * (r(b, k) - r(a, k)) for k in a)
    cross = sum((w(b, sb, k) - w(a, sa, k)) * (r(b, k) - r(a, k)) for k in a)
    return mix * 100, seg * 100, cross * 100  # в процентных пунктах

print("состав %+.2f, сегменты %+.2f, перекрёстный %+.2f п.п." % decompose(tue, wed))
# состав -0.31, сегменты +0.10, перекрёстный +0.00 п.п.

Все три таблицы, сверку и это разложение можно пересчитать самому: данные и скрипт лежат в репозитории conversion-drop-diagnosis-demo, запуск одной командой ./run.sh.

Состав трафика отнял 0,31 процентного пункта, а конверсия внутри сегментов добавила 0,10. Перекрёстный член после округления равен нулю: в учебных данных конверсия всех сегментов выросла примерно на одну и ту же величину, около 0,10 пункта. На живых данных он бывает заметным, поэтому считать его нужно всегда. Доля новых пользователей выросла с 34,5% до 43,8%, и по времени и меткам это совпадает с посевами. При этом все шесть сегментов по биллингу стали конвертировать лучше, включая оба сегмента iOS. Каждая часть растёт, а целое падает — это парадокс Симпсона в чистом виде, и на дашборде без разреза его не увидеть.

На Рис. 3 всё падение собрано в одну картину.

Рис. 3. Из чего сложились минус 0,52 пункта: красным сломанное измерение, жёлтым сдвиг состава, зелёным рост внутри сегментов

Рис. 3. Из чего сложились минус 0,52 пункта: красным сломанное измерение, жёлтым сдвиг состава, зелёным рост внутри сегментов

Вывод из Рис. 3: внутри сегментов ухудшения нет, их конверсия выросла. Общая цифра снизилась из-за сдвига состава, а ещё 0,31 пункта дал недоучёт событий на iOS, который чинится тикетом.

Шаг 4. Ответ директору

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

Три фразы, которые я бы предложил принести на созвон:

1. Оплаченных заказов в среду 4 538 против 4 070, на 11,5% больше. Выручку и средний чек сверим отдельно, но падения продаж по числу заказов нет.

2. На iOS 5.2 до аналитики не доходит событие покупки, дашборд недосчитывает 28% iOS-заказов. Задача заведена на мобильную команду, метрики заказов за среду пересчитаем по биллингу.

3. Конверсия по оплаченным заказам снизилась на 5,7% из-за сдвига состава: новых пользователей стало больше, и прирост совпадает с посевами по меткам источника. Внутри каждого сегмента она выросла. Кампанию оцениваем отдельно, по её собственной конверсии в заказы и с окном атрибуции: первые сутки её занижают.

Как это устроено у команд, которые не тушат такие пожары

Оба провала можно закрыть заранее, а не в 09:40.

  • Сверка аналитики с биллингом по расписанию. Ежечасный запрос из шага 1 с порогом разрыва и оповещением. Он ловит и пропавшие события, и дубли, то есть именно тот класс поломок, что в примере с Shopify.

  • Трекинг-план как контракт. Список событий с обязательными полями живёт рядом с кодом, а новый экран не уходит в релиз без проверки, что purchase с него отправляется.

  • Отметки релизов и кампаний на графиках. Когда на оси времени стоят «iOS 5.2» и «посевы», половина гипотез проверяется взглядом.

  • Конверсия в разрезе по умолчанию. Общая цифра на главном дашборде соседствует с конверсией новых и вернувшихся. Тогда парадокс Симпсона виден сразу, а не после разложения в ноутбуке.

Ограничения разбора

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

Тип пользователя здесь записан прямо в заказ. В реальной системе его получают через связь заказа с пользователем или сессией, и без надёжной связи пересчитывать конверсию по биллингу внутри сегментов нельзя. И последнее: биллинг честен про заказы, но не про сессии. Если сломан учёт сессий, знаменатель сверяют с логами веб-сервера или магазина приложений.

Усложнение

Допустим, в биллинге нет ни платформы, ни версии приложения, есть только order_id, время и сумма. Как за те же двадцать минут доказать, что потери событий идут именно с iOS 5.2? Подсказка: смотрите, где ещё в данных живёт order_id до момента оплаты.

Какой навык проверяла задача

Не знание SQL и не умение строить дашборды. Задача проверяет дисциплину диагностики: сначала усомниться в измерении, потом разделить метрику на числитель и знаменатель, состав и сегменты, и только после этого искать причину. Варианты А–Г неверны не потому, что их авторы плохо знают продукт, а потому, что каждый из них начинает с третьего шага.

Если вы выбрали В, вы заметили важный сигнал, сдвиг состава трафика, но остановка кампании требует проверки её собственной конверсии. Если заметили разрыв с биллингом раньше, чем дочитали до разбора, — это тот уровень, который отличает middle от senior.

Хотите проверить и другие навыки работы с данными? Попробуйте пройти вступительный тест курса «Аналитик данных». Он поможет оценить текущие знания и понять, какие темы стоит подтянуть.

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

Ссылка на мой репозиторий с задачей: https://github.com/sproshchaev/conversion-drop-diagnosis-demo

Начать стоит с expected.txt: там все три таблицы из условия, сверка событий с биллингом по часам и версиям приложения, разрез по источникам трафика и разложение минус 0,52 пункта. Как это считается, видно в diagnose.py, исходные заказы и события лежат в data/billing_orders.csv и data/purchase_events.csv, а ./run.sh пересобирает данные и сверяет вывод с эталоном.

Источники:

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

20 октября в 20:00 на бесплатном вебинаре курса «Качество данных» разберём, как выбирать метрики качества данных с учётом бизнес-задач и выстраивать мониторинг — от первых проверок до внедрения в рабочие процессы. Можно будет задать вопросы и разобраться в подходах к контролю качества данных. Записаться.

View the original on Хабр →

KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.