Контекст: фитнес-соцсеть и релиз онбординга
Продукт — мобильное приложение для бега и силовых, с социальной частью (лента тренировок друзей, лайки, комменты). DAU ≈ 240K, MAU ≈ 800K. Главная метрика северной звезды — weekly_active_users, ключевой драйвер — D7 retention новых юзеров: на нём держится весь рост.
Команда роста готовила релиз больше месяца. Гипотеза была чёткая: «если показать новичку ленту друзей в первый день — он быстрее увидит ценность, и D7 retention вырастет на 3–5 п.п.». Тест сначала на 10% трафика, потом — раскатка на 100% утром 1 апреля. На пилотных 10% за неделю никакой деградации не было, замер показал даже лёгкий +1.4% (не значимо).
3 апреля: дашборд краснеет
3 апреля утром продакт пишет в чат: «посмотри retention новых, что-то не нравится». Аналитик открывает дашборд:
Картина пугающая: D1 −9%, D7 −18% — и не только у когорты, которая увидела новый онбординг. Старые когорты (зарегистрированные ещё в марте) тоже подсели по dau-возвратам. Продакт уже репетирует «откатываем релиз сегодня вечером».
Аналитик берёт паузу. Откатить успеется — это вопрос пары часов. А вот понять, что именно произошло, до отката — куда полезнее, иначе после отката будет неясно, помог откат или нет.
5 гипотез: от дешёвых проверок к дорогим
Алгоритм диагностики «упавшей метрики» — стандартный, я его подробно разбирал в статье «Декомпозиция метрики». Сначала самые дешёвые проверки (1–5 SQL-запросов), потом — дорогие (целые расследования по логам и коду).
| # | Гипотеза | Цена проверки | Почему пробуем |
|---|---|---|---|
| H1 | Сезонность / внешний фактор | Дешёвая | 1–2 апреля выпали на пятницу-субботу + были майские праздники у части аудитории |
| H2 | Маркетинговый микс изменился | Средняя | 30 марта запустили новую закупку в TikTok — могли пойти юзеры «не той» аудитории |
| H3 | Технический баг трекинга | Средняя | Стандартный first-suspect: при любом релизе мобильного приложения SDK-события могут поломаться |
| H4 | Сам релиз онбординга | Дорогая | Очевидная по времени корреляция, но не объясняет старые когорты |
| H5 | Внешний фактор: App Store / конкурент | Дешёвая | Резкое падение оценки в сторе или вирусный конкурент могли увести часть юзеров |
Иду в порядке цены проверки, не в порядке «правдоподобия». Это важно: «правдоподобие» легко смещается под текущую тревогу команды (все смотрят на релиз и кричат «откатывай»), а цена проверки — объективна.
Проходим гипотезы по очереди
H1 + H5: внешние факторы (15 минут)
Сравниваю DAU и retention с теми же датами годом ранее (YoY) и с двумя предыдущими неделями (WoW):
SELECT DATE_TRUNC('day', event_date) AS d, COUNT(DISTINCT user_id) AS dau FROM events WHERE event_date BETWEEN '2025-03-25' AND '2025-04-05' -- год назад GROUP BY 1 UNION ALL SELECT DATE_TRUNC('day', event_date), COUNT(DISTINCT user_id) FROM events WHERE event_date BETWEEN '2026-03-25' AND '2026-04-05' -- этот год GROUP BY 1;
Результат: ни в YoY, ни в WoW тех же провалов нет. Сезонность — мимо. Открываю App Store Connect и Google Play Console: средняя оценка стабильна (4.6), отзывов с упоминанием багов чуть больше, но не лавина. Конкурентов мониторю через Sensor Tower — никаких всплесков. H1 и H5 закрыты за 15 минут.
H2: маркетинговый микс (30 минут)
30 марта действительно расширили закупку в TikTok — это могло привести «более лёгкую» аудиторию, у которой retention ниже от природы. Проверяю срез retention по utm-источнику:
WITH new_users AS ( SELECT user_id, signup_date, utm_source FROM users WHERE signup_date BETWEEN '2026-03-25' AND '2026-04-02' ), d7 AS ( SELECT n.user_id, n.utm_source, MAX(CASE WHEN e.event_date BETWEEN n.signup_date + 7 AND n.signup_date + 7 THEN 1 ELSE 0 END) AS retained FROM new_users n LEFT JOIN events e ON e.user_id = n.user_id GROUP BY 1, 2 ) SELECT utm_source, COUNT(*) AS n, AVG(retained::numeric) AS d7_retention FROM d7 GROUP BY 1 ORDER BY n DESC;
В разрезе по источникам — TikTok действительно слабее (D7 ≈ 22% против 34% органики), но его доля в новых юзерах не выросла: 8% и до релиза, 9% после. Эффект на общий retention — максимум 1 п.п. Это часть истории, но не объясняет −18%. Внутри каждого источника отдельно D7 тоже просел на 4–6 п.п. H2 объясняет максимум 1 п.п. из 6.
H3: баг трекинга (1 час)
Самый банальный, но самый частый источник ложных тревог при релизе. Что я смотрю:
- Распределение событий по платформам: до релиза 50/50 iOS/Android, после релиза — что?
- Распределение по типам событий:
session_start,workout_complete,feed_view— какие из них упали? - Версии приложения: пришли ли все юзеры на новую сборку, или часть осталась на старой?
SELECT event_date, platform, COUNT(*) FILTER (WHERE event_name = 'session_start') AS sessions, COUNT(*) FILTER (WHERE event_name = 'workout_complete') AS workouts, COUNT(*) FILTER (WHERE event_name = 'feed_view') AS feed FROM events WHERE event_date BETWEEN '2026-03-25' AND '2026-04-03' GROUP BY 1, 2 ORDER BY 1, 2;
И вот тут картина, которую я не ожидал увидеть:
| Дата | Платформа | Sessions | Workouts | Feed views |
|---|---|---|---|---|
| 30 мар | iOS | 432K | 118K | 286K |
| 30 мар | Android | 418K | 112K | 272K |
| 2 апр | iOS | 261K (−40%) | 116K | 172K (−40%) |
| 2 апр | Android | 421K | 114K | 275K |
Стоп. На Android — всё спокойно. На iOS — session_start и feed_view упали на 40%, а workout_complete — на месте. Это не падение продукта. Юзер, который записывает тренировку, никуда не делся. У него просто не считается «открытие приложения» и «просмотр ленты».
Дело не в продукте — дело в SDK
Иду в репозиторий, поднимаю diff релиза 1 апреля. В iOS-сборке среди 80 коммитов один — небольшой, на 12 строк: «upgrade analytics SDK from 4.7.2 to 5.0.0». В changelog SDK на 5.0 — мелким шрифтом: «autoTrackingMode по умолчанию изменён с full на essential». В режиме essential события session_start отправляются только при холодном старте — а при возврате из push или из бэкграунда (что у фитнес-приложения происходит постоянно) — больше нет.
Тот же эффект для feed_view: его триггер был на «открытие приложения с экраном ленты», а в новом режиме часть таких открытий не классифицировалась как сессия и не получала event-обёртку. Workout-события не пострадали — их триггерила сама кнопка «начать тренировку», независимо от SDK-сессий.
А retention считается так: «пользователь засчитывается как retained на день N, если у него был хотя бы один session_start в этот день». То есть формально — мы считаем долю юзеров, у которых было событие сессии. И если событий стало на 40% меньше у iOS-юзеров (а это половина базы), то retention механически сжался — без какой-либо реальной потери в продукте.
users и не зависит от SDK. Числитель (вернувшиеся) считается из events.session_start — и упал на 40% у половины базы. Метрика просела математически, без всякого участия онбординга. Релиз тут случайный сосед по времени. Если бы откатили онбординг — retention не вернулся бы. Это и есть самый убедительный аргумент против поспешного отката.Что починили и в каком порядке
1. Прозрачность сразу, а не «когда разберёмся»
К 14:00 того же дня иду к продакту и пишу в чат команды: «3-часовой апдейт по retention. С большой вероятностью это не релиз, а баг трекинга iOS-сессий из-за обновления SDK. Откат онбординга задерживаю — он метрику не починит. Финальные доказательства в течение часа». Это снимает панику и переключает разговор с «откатывать или нет» на «как чинить SDK».
Урок здесь простой и не аналитический: продакт боится тишины аналитика сильнее, чем плохих новостей. Полтора часа без апдейта в кризис — это уже срыв доверия. Лучше написать «я ещё разбираюсь, основная гипотеза такая, обновлю через час», чем закрыться в саркофаг.
2. Откат SDK, а не релиза
Мобильная команда срочно делает hotfix: возвращает SDK к 4.7.2 (или явно прописывает autoTrackingMode = full). Это требует ревью в App Store, ускоренное прохождение — 18 часов. На это время дашборды по retention помечаются жёлтым стикером «iOS tracking issue, ETA fix 4 апр 18:00».
3. Восстановление исторических данных
Параллельно — backfill: используя данные с Android в качестве «контроля» и долю iOS в DAU до релиза, оцениваю «честный» retention за 1–4 апреля. Дашборд получает дополнительную колонку «retention_corrected» с пометкой про методику. После фикса SDK эта колонка не нужна, но за период инцидента она сохраняет ретроспективу.
4. Что показал «настоящий» эффект релиза
Когда SDK поправили (4 апреля вечером) и накопилась чистая неделя данных — пересчитал D7 retention отдельно по когорте «видели новый онбординг» против «видели старый» (на 10% holdout-сегменте, который у нас остался для подобных случаев):
Релиз сработал. Скромно, но в плюс. И если бы 3 апреля откатили в панике — мы бы потеряли реальный +2 п.п. к D7, потому что списали его на воображаемый −6 п.п. от баги SDK.
Что унести из этого кейса
Самая короткая формулировка: метрика — это сначала pipeline, потом продукт. Прежде чем разбирать падение как продуктовое, проверяй, не сломались ли данные. Это не паранойя, это рутина.
Связанные материалы
Главное про падение retention
Самое дорогое в разборе «упавшей метрики» — это не сам разбор, а решения, принятые до него. Откатить релиз за час до проверки — значит уничтожить шанс понять, что было настоящей причиной. Любая метрика — это сначала числитель/знаменатель и pipeline, и только потом — продукт. В этом кейсе релиз и баг SDK совпали по времени; алгоритм диагностики разнял их за 2 часа.
В реальности подобные ситуации повторяются. SDK обновляется, версия события меняется, фильтр в дашборде сбрасывается, аналитик в отпуске — и метрика «падает на 18%». Защита одна и та же: чек-лист первых 2 часов, шаблон апдейта продакту, разрез по платформам и типам событий по умолчанию.
Следующий шаг: возьми любую свою ключевую метрику и проверь — есть ли у тебя в дашборде разрез по платформам? Если нет — добавь. Стоит 20 минут и однажды спасёт целый квартал.