Как посчитать Returning Users в SQL

Закрепи формулу returning users в Карьернике
Запомнить надолго — 5 коротких сессий с задачами на эту тему. Бесплатно
Тренировать returning users в Telegram

Зачем Returning Users

DAU 100K — кажется хорошо. Но: 70K new, 30K returning. Через месяц new падает (закончилась реклама), DAU становится 30K. Returning ratio — здоровый сигнал sustainability бизнеса.

Что такое Returning

Returning User — активный за период, чья первая активность была ДО начала периода.

Returning ∈ period: first_activity < period_start AND has_activity_in_period

Базовый расчёт

WITH first_activity AS (
    SELECT user_id, MIN(event_date) AS first_date
    FROM events
    GROUP BY user_id
)
SELECT
    DATE_TRUNC('month', e.event_date) AS month,
    COUNT(DISTINCT CASE
        WHEN fa.first_date < DATE_TRUNC('month', e.event_date)
        THEN e.user_id
    END) AS returning_users,
    COUNT(DISTINCT CASE
        WHEN fa.first_date >= DATE_TRUNC('month', e.event_date)
         AND fa.first_date <  DATE_TRUNC('month', e.event_date) + INTERVAL '1 month'
        THEN e.user_id
    END) AS new_users,
    COUNT(DISTINCT e.user_id) AS total_active
FROM events e
JOIN first_activity fa ON fa.user_id = e.user_id
WHERE e.event_date >= '2026-01-01'
GROUP BY 1
ORDER BY 1;

Returning vs New vs Reactivated

Тип Определение
New Первая активность ∈ period
Returning Был активен сразу до period
Reactivated Был активен давно, потом был неактивен X+ дней, вернулся в period
WITH user_state AS (
    SELECT
        user_id,
        MIN(event_date) AS first_date,
        MAX(CASE WHEN event_date < '2026-04-01' THEN event_date END) AS last_before_period,
        MIN(CASE WHEN event_date >= '2026-04-01' AND event_date < '2026-05-01' THEN event_date END) AS first_in_period
    FROM events
    GROUP BY user_id
)
SELECT
    CASE
        WHEN first_date >= '2026-04-01' AND first_date < '2026-05-01' THEN 'new'
        WHEN last_before_period >= '2026-03-01' THEN 'returning'
        WHEN last_before_period IS NOT NULL THEN 'reactivated'
    END AS user_type,
    COUNT(*) AS users
FROM user_state
WHERE first_in_period IS NOT NULL
GROUP BY 1;
Закрепи формулу returning users в Карьернике
Запомнить надолго — 5 коротких сессий с задачами на эту тему. Бесплатно
Тренировать returning users в Telegram

Разрезы

По segments / channels:

SELECT
    u.acquisition_channel,
    COUNT(DISTINCT CASE
        WHEN MIN(e.event_date) OVER (PARTITION BY e.user_id) < DATE_TRUNC('month', CURRENT_DATE)
        THEN e.user_id
    END) AS returning_users
FROM events e
JOIN users u ON u.user_id = e.user_id
WHERE e.event_date >= DATE_TRUNC('month', CURRENT_DATE)
GROUP BY u.acquisition_channel;

Частые ошибки

Ошибка 1. Returning = всё, что не new. В этой логике reactivated засчитывается как returning. Различайте.

Ошибка 2. Boundary issues. Юзер с first_date = period_start — это new или returning? Договоритесь.

Ошибка 3. Cross-device. Без unified user_id новый device = «new». Учитывайте.

Ошибка 4. NOT IN с NULL. Ломается. Используйте NOT EXISTS.

Ошибка 5. Сравнение returning across periods без normalization. Юзер в апреле = «returning» если был активен в марте. В мае может стать «reactivated» если в апреле не зашёл. Состояние user-type меняется по периодам.

Связанные темы

FAQ

Returning vs Reactivated?

Returning — был активен недавно (< lapse threshold). Reactivated — вернулся после долгого отсутствия.

Какой Returning ratio хороший?

Зависит от growth-стадии. Стартап в hyper-growth: new > returning. Зрелый продукт: returning >> new.

Returning DAU падает — что делать?

Скорее всего проблема в retention или engagement. Декомпозиция по cohort.

Cross-device — обязательно?

Желательно. Без unification — overcount new и undercount returning.

Returning стабильный, new упал — что делать?

Проблема в acquisition (маркетинг / SEO). Returning — здоровая база.