Как считать Retention: формулы, SQL-запросы и подводные камни

Что такое retention и почему его всегда спрашивают

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

На собеседованиях аналитиков retention спрашивают почти всегда. Причём не «что это такое», а «как посчитаете», «какие подводные камни» и «напишите SQL». Если вы готовитесь к собеседованию, эту тему нужно знать глубоко.

Кривая Retention

Виды retention

Классический retention (Day-N)

Доля пользователей, которые были активны ровно на N-й день после регистрации (или первого визита).

Формула:

Retention(Day N) = Пользователи, активные на день N / Все пользователи когорты

Примеры:

  • D1 retention — вернулись на следующий день
  • D7 retention — вернулись ровно на 7-й день
  • D30 retention — вернулись ровно на 30-й день

Важно: «ровно на N-й день» означает именно этот конкретный день. Если пользователь пришёл на 6-й и 8-й день, но не на 7-й — в D7 он не попадает.

Rolling retention (возвратный)

Доля пользователей, которые были активны на N-й день или позже. Более мягкая метрика — учитывает всех, кто не ушёл навсегда.

Формула:

Rolling Retention(Day N) = Пользователи, активные на день N или позже / Все пользователи когорты

Rolling retention всегда >= классического. Он лучше подходит для продуктов с нерегулярным использованием (например, сервисы бронирования, маркетплейсы).

Bounded retention (интервальный)

Доля пользователей, активных в определённом окне. Например, D7 bounded — «был активен хотя бы раз в дни 1–7».

Этот вид чаще используется внутри компаний для отчётности, но на собеседованиях обычно спрашивают про классический Day-N.

Когортный анализ

Retention всегда считается по когортам. Когорта — группа пользователей, объединённых по дате первого действия (регистрация, установка, первая покупка).

Зачем когорты:

  • Сравнивать поведение пользователей из разных периодов
  • Видеть, как изменения в продукте влияют на удержание
  • Отделять эффект роста от улучшения качества

Типичная таблица когортного анализа:

Когорта D0 D1 D7 D14 D30
1–7 янв 100% 25% 12% 8% 5%
8–14 янв 100% 28% 14% 9% 6%
15–21 янв 100% 30% 15% 10%

Строки — когорты по неделям, столбцы — дни после первого визита. Видно, что каждая следующая когорта удерживается чуть лучше — значит, продукт улучшается.

SQL-запросы для расчёта retention

Главное правило: единица анализа (user) и определение «активности» должны быть чётко зафиксированы до начала расчёта.

D1 retention по когортам

WITH cohort AS (
    SELECT
        user_id,
        MIN(event_date) AS cohort_date
    FROM user_activity
    GROUP BY user_id
),
activity AS (
    SELECT DISTINCT
        user_id,
        event_date
    FROM user_activity
)
SELECT
    c.cohort_date,
    COUNT(DISTINCT c.user_id) AS cohort_size,
    COUNT(DISTINCT a.user_id) AS returned_d1,
    ROUND(
        COUNT(DISTINCT a.user_id)::numeric / COUNT(DISTINCT c.user_id) * 100, 1
    ) AS d1_retention_pct
FROM cohort c
LEFT JOIN activity a
    ON c.user_id = a.user_id
    AND a.event_date = c.cohort_date + INTERVAL '1 day'
GROUP BY c.cohort_date
ORDER BY c.cohort_date

Логика: для каждого пользователя находим дату первого визита (когорта), затем через LEFT JOIN проверяем, был ли он активен на следующий день.

Универсальный retention для произвольного дня N

WITH cohort AS (
    SELECT
        user_id,
        MIN(event_date) AS cohort_date
    FROM user_activity
    GROUP BY user_id
),
retention_data AS (
    SELECT
        c.user_id,
        c.cohort_date,
        a.event_date,
        a.event_date - c.cohort_date AS day_number
    FROM cohort c
    JOIN user_activity a ON c.user_id = a.user_id
)
SELECT
    cohort_date,
    day_number,
    COUNT(DISTINCT user_id) AS active_users
FROM retention_data
WHERE day_number IN (0, 1, 3, 7, 14, 30)
GROUP BY cohort_date, day_number
ORDER BY cohort_date, day_number

Этот запрос считает retention для нескольких дней одновременно. Чтобы получить проценты, разделите active_users на размер когорты (day_number = 0).

Rolling retention

WITH cohort AS (
    SELECT
        user_id,
        MIN(event_date) AS cohort_date
    FROM user_activity
    GROUP BY user_id
),
last_seen AS (
    SELECT
        user_id,
        MAX(event_date) AS last_activity_date
    FROM user_activity
    GROUP BY user_id
)
SELECT
    c.cohort_date,
    COUNT(DISTINCT c.user_id) AS cohort_size,
    COUNT(DISTINCT CASE
        WHEN l.last_activity_date >= c.cohort_date + INTERVAL '7 days'
        THEN c.user_id
    END) AS rolling_d7
FROM cohort c
JOIN last_seen l ON c.user_id = l.user_id
GROUP BY c.cohort_date
ORDER BY c.cohort_date

Здесь считаем rolling D7: пользователь попадает в числитель, если его последняя активность была на 7-й день или позже.

Подводные камни

1. Часовые пояса

Пользователь зарегистрировался в 23:50 по Москве, а данные хранятся в UTC. В UTC это уже следующий день. Если считать retention по UTC-дате, этот пользователь окажется «вернувшимся на D0», а не на D1. Всегда уточняйте часовой пояс — на собеседовании за это дают бонусные очки.

2. Определение «активности»

Что считать возвращением? Открыл приложение? Совершил целевое действие? Провёл больше 10 секунд? Разные определения дают разные цифры retention. На собеседовании уточните определение — это показывает зрелость мышления.

3. Маленькие когорты

Если в когорте 20 пользователей, retention скачет от 0% до 50% случайным образом. Группируйте когорты по неделям или месяцам, чтобы получить статистически значимые результаты.

4. Незавершённые когорты

Когорта «последняя неделя» ещё не может показать D30 retention — прошло слишком мало времени. Если не обрезать такие когорты, retention будет искусственно занижен. В SQL это решается фильтром:

WHERE cohort_date <= CURRENT_DATE - INTERVAL '30 days'

5. Путаница классического и rolling retention

На собеседовании могут спросить: «У вас D7 retention 12%. Это много или мало?» Уточните, какой именно D7: классический или rolling. Rolling всегда выше — сравнивать их между собой нельзя.

Совет: всегда проверяйте retention на маленькой выборке вручную, прежде чем доверять запросу на всей базе.

Что спрашивают на собеседованиях

Типовые вопросы по retention, которые встречаются на интервью в продуктовую аналитику:

  1. Напишите SQL для расчёта D1 retention по когортам — самый частый вопрос. Решение выше.
  2. Чем отличается классический retention от rolling? — объясните на примере.
  3. Retention упал с 15% до 10%. Как будете разбираться? — сегментация: по источнику трафика, платформе, стране, фиче. Проверьте, не изменился ли состав когорты.
  4. Как учитывать часовые пояса при расчёте? — конвертировать в локальное время пользователя или зафиксировать один часовой пояс для всех.
  5. Что лучше: высокий D1 или высокий D30? — зависит от продукта. Для daily-use приложений (мессенджер, соцсеть) критичен D1. Для сервисов с нерегулярным использованием (такси, маркетплейс) важнее D30.

Больше вопросов по продуктовым метрикам — в разделе продуктовой аналитики. Если хотите системно разобрать все темы, посмотрите план подготовки к собеседованию.

Тренажёр Карьерник включает вопросы по retention и другим продуктовым метрикам с разборами. Удобно прогонять тему в Telegram перед собеседованием — 15 минут в день, и retention перестанет быть проблемой на интервью.

FAQ

Какой retention считается хорошим?

Зависит от типа продукта. Для мобильных приложений ориентиры: D1 — 25–40%, D7 — 10–20%, D30 — 5–15%. Для SaaS-продуктов D30 обычно выше: 20–40%. Для социальных сетей и мессенджеров D1 может быть 50%+. Сравнивайте только с бенчмарками своей категории — универсального «хорошего» значения нет.

В чём разница между retention и возвратом (return rate)?

Retention считается по когортам и привязан к конкретному дню от первого визита. Возврат — более общая метрика: «какая доля активных на прошлой неделе была активна на этой». Retention показывает качество удержания новых пользователей, возврат — стабильность активной базы. На собеседованиях чаще спрашивают именно retention.

Можно ли считать retention без когорт?

Технически да, но это бессмысленно. Без когорт вы смешиваете новых и старых пользователей, и метрика теряет диагностическую ценность. Если D1 упал — это новые пользователи хуже удерживаются или старые когорты закончились? Без когортного разреза не узнаете.