Как посчитать session depth в SQL

Проверь себя · 1/3разбор после ответа
Нужно построить отчёт: по каждому продукту и каждому дню месяца — сумма продаж, включая дни с нулевыми продажами. Как сформировать каркас из всех пар дата–продукт?

Зачем session depth

Session depth (число событий или страниц за сессию) — насколько глубоко пользователь «погружается» в продукт за один заход. Низкий depth при высоком трафике — плохой контент или UX: люди уходят сразу. Высокий depth при низком трафике — вы вовлекаете тех, кто пришёл, но приходит их мало.

События за сессию

Сначала нужна сессия. Простейшая определяется как 30-минутный перерыв в активности:

WITH events_with_session AS (
    SELECT
        user_id,
        event_timestamp,
        SUM(CASE
            WHEN EXTRACT(EPOCH FROM (event_timestamp - LAG(event_timestamp) OVER (PARTITION BY user_id ORDER BY event_timestamp))) > 1800
            THEN 1 ELSE 0
        END) OVER (PARTITION BY user_id ORDER BY event_timestamp) AS session_id
    FROM events
    WHERE event_timestamp >= CURRENT_DATE - INTERVAL '30 days'
),
session_depth AS (
    SELECT
        user_id,
        session_id,
        COUNT(*) AS events_in_session
    FROM events_with_session
    GROUP BY user_id, session_id
)
SELECT
    AVG(events_in_session) AS avg_depth,
    COUNT(*) AS total_sessions
FROM session_depth;

Среднее 4-6 событий — типично для потребительских приложений.

Перцентили

SELECT
    AVG(events_in_session) AS avg_depth,
    PERCENTILE_CONT(0.25) WITHIN GROUP (ORDER BY events_in_session) AS p25,
    PERCENTILE_CONT(0.5)  WITHIN GROUP (ORDER BY events_in_session) AS median,
    PERCENTILE_CONT(0.75) WITHIN GROUP (ORDER BY events_in_session) AS p75,
    PERCENTILE_CONT(0.95) WITHIN GROUP (ORDER BY events_in_session) AS p95
FROM session_depth;

Медиана 2-3, среднее 5 — тяжёлый длинный хвост. Это норма: большинство сессий короткие, а очень длинных мало.

По когорте и устройству

SELECT
    DATE_TRUNC('month', u.created_at)::DATE AS cohort_month,
    s.platform,
    COUNT(DISTINCT s.session_id) AS sessions,
    AVG(sd.events_in_session) AS avg_depth,
    PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY sd.events_in_session) AS median_depth
FROM session_depth sd
JOIN sessions s USING (session_id)
JOIN users u USING (user_id)
WHERE u.created_at >= CURRENT_DATE - INTERVAL '90 days'
GROUP BY DATE_TRUNC('month', u.created_at), s.platform
ORDER BY cohort_month, s.platform;

Сравните iOS и Android: разница в depth обычно около 20%. Резкий разрыв — признак UX-проблемы на одной из платформ.

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

Фильтр ботов

Сессии с depth 50+ — это часто боты или скрейпинг:

SELECT
    user_id,
    COUNT(*) AS suspicious_sessions
FROM session_depth
WHERE events_in_session > 100
GROUP BY user_id
HAVING COUNT(*) >= 5
ORDER BY suspicious_sessions DESC;

Эти пользователи — кандидаты на исключение из общей статистики.

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

Ошибка 1. Среднее на скошенных данных. Распределение depth — с длинным хвостом. Среднее даст 5, медиана 2 — разница большая. Сообщайте обе величины.

Ошибка 2. Перерыв между сессиями в 30 минут — слишком жёстко. Для лонгридов типичная пауза больше часа. Калибруйте окно перерыва под свой продукт.

Ошибка 3. Считать только события page_view. Если интересна глубина взаимодействия, считайте все события (клики, скроллы), а не только просмотры страниц.

Ошибка 4. Боты не отфильтрованы. Сессия бота с 1000 событий раздует среднее. Отсекайте по 95-му перцентилю или по user-agent.

Ошибка 5. Сравнивать depth с конкурентом без контекста. Контентный сайт и SaaS-приложение несравнимы — глубина сессии означает у них совершенно разное.

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

FAQ

Какой depth «хороший»?

Всё зависит от типа продукта. Для контентного сайта нормой считается 1.5-3, для SaaS-дашборда — 5-15, для соцсети — 10 и выше. Универсального «хорошего» значения нет: сравнивайте себя с собой во времени, а не с чужими цифрами.

Считать уникальные страницы или все события?

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

Отказ (bounce) — это depth = 1?

Чаще всего да: отказ — это сессия из одного события. Bounce rate тогда считается как доля сессий с глубиной 1.

Depth ниже — это плохо?

Не всегда. Всё зависит от типа продукта: для лендинга низкая глубина нормальна, а для SaaS-дашборда это уже тревожный сигнал.

Какой перерыв брать для сессий?

Стандарт — 30 минут неактивности. Для контентных сайтов иногда берут 60 минут и больше, потому что люди читают долго и с паузами.