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

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

Зачем session depth

Session depth (events per session или pages per session) — насколько глубоко юзер «погружается» в продукт за один заход. Низкий depth + высокий traffic = плохой content / UX, юзеры уходят сразу. Высокий depth + низкий traffic = вовлекают тех, кто пришёл, но мало приходящих.

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

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

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 событий — типично для consumer apps.

Перцентили

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;

Median 2-3, mean 5 — heavy long tail. Это норма (большинство сессий короткие, мало супер-длинных).

По cohort и устройству

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 vs Android: разница в depth обычно ~20%. Резкая разница = UX-проблема на одной платформе.

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

Bot-фильтр

Сессии с depth 50+ — часто bots или scraping:

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. Average на skewed данных. Distribution depth long-tail. Mean даст 5, median 2 — большая разница. Сообщайте оба.

Ошибка 2. Session gap 30 минут — слишком жёстко. Для long-read контента типичная пауза 1+ час. Калибруйте gap.

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

Ошибка 4. Bots не отфильтрованы. Bot session с 1000 hits раздует mean. Filter > 95th percentile или by user-agent.

Ошибка 5. Сравнение depth с конкурентом без context. Контентный сайт vs SaaS app — несравнимы. Depth metaning разный.

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

FAQ

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

Editorial site: 1.5-3. SaaS dashboard: 5-15. Социалка: 10+.

Считать unique pages или total events?

Unique pages для content (avoid scroll inflation). Total events для apps.

Bounce — это depth = 1?

Часто да. Bounce rate = % sessions с depth 1.

Депт ниже — плохо?

Не всегда. Сильно зависит от типа продукта.

Sessionization gap какой?

30 минут — стандарт. Для контента иногда 60+.