Как посчитать Bounce Rate в SQL
Содержание:
Зачем Bounce Rate
Маркетолог жалуется: «Я вливаю бюджет в Performance Max, трафик растёт, а конверсии стоят». Аналитик смотрит — bounce rate новых сессий 85%. Значит, юзер заходит, видит лендинг и сразу уходит. Креатив привлекает «не тех» — деньги тратятся вхолостую.
Bounce rate — быстрый сигнал качества трафика, релевантности контента и UX лендинга. В статье — SQL для расчёта по разным определениям (single-page, engagement-based) и подводные камни.
Что такое Bounce Rate
Bounce rate — доля сессий, в которых пользователь не совершил действий (классически — посмотрел только одну страницу и ушёл).
Bounce rate = sessions с одной page view / all sessionsВ GA4 — определение изменилось: bounce = «не engaged», где engaged = сессия >10 сек или с конверсией или с 2+ страницами.
Базовый расчёт
Данные: pageviews(session_id, page_url, timestamp).
Классический (single-page-bounce)
WITH session_pages AS (
SELECT session_id, COUNT(*) AS page_count
FROM pageviews
GROUP BY session_id
)
SELECT
COUNT(*) AS total_sessions,
SUM(CASE WHEN page_count = 1 THEN 1 ELSE 0 END) AS bounced,
SUM(CASE WHEN page_count = 1 THEN 1 ELSE 0 END) * 100.0
/ NULLIF(COUNT(*), 0) AS bounce_rate_pct
FROM session_pages;Простой и понятный. Минус: засчитывает как bounce пользователя, который прочитал лендинг 5 минут и нажал кнопку «Связаться» (она открыла WhatsApp, а не следующую страницу).
Bounce по страницам и источникам
«На какой странице пользователи отваливаются чаще»:
WITH session_info AS (
SELECT
session_id,
MIN(page_url) FILTER (WHERE rn = 1) AS landing_page,
COUNT(*) AS page_count
FROM (
SELECT
session_id,
page_url,
ROW_NUMBER() OVER (PARTITION BY session_id ORDER BY TIMESTAMP) AS rn
FROM pageviews
) ranked
GROUP BY session_id
)
SELECT
landing_page,
COUNT(*) AS sessions,
SUM(CASE WHEN page_count = 1 THEN 1 ELSE 0 END) * 100.0
/ NULLIF(COUNT(*), 0) AS bounce_rate_pct
FROM session_info
GROUP BY landing_page
HAVING COUNT(*) >= 100
ORDER BY bounce_rate_pct DESC;HAVING COUNT(*) >= 100 — отсекаем страницы с микро-трафиком (10 заходов и 100% bounce ничего не говорят).
По источникам:
WITH session_summary AS (
SELECT
s.session_id,
s.utm_source,
COUNT(p.page_url) AS page_count
FROM sessions s
LEFT JOIN pageviews p ON p.session_id = s.session_id
GROUP BY s.session_id, s.utm_source
)
SELECT
utm_source,
COUNT(*) AS sessions,
SUM(CASE WHEN page_count <= 1 THEN 1 ELSE 0 END) * 100.0
/ NULLIF(COUNT(*), 0) AS bounce_rate_pct
FROM session_summary
GROUP BY utm_source
ORDER BY bounce_rate_pct DESC;Engaged-session bounce
Современное определение (GA4-style): bounce = сессия не engaged. Engaged = длительность >10 сек, ИЛИ конверсия, ИЛИ 2+ страницы.
WITH session_metrics AS (
SELECT
session_id,
COUNT(*) AS page_count,
EXTRACT(EPOCH FROM (MAX(TIMESTAMP) - MIN(TIMESTAMP))) AS duration_sec,
BOOL_OR(event_type = 'conversion') AS had_conversion
FROM events
GROUP BY session_id
)
SELECT
COUNT(*) AS total,
SUM(CASE
WHEN page_count >= 2 THEN 0
WHEN duration_sec >= 10 THEN 0
WHEN had_conversion THEN 0
ELSE 1
END) AS bounced,
SUM(CASE
WHEN page_count >= 2 THEN 0
WHEN duration_sec >= 10 THEN 0
WHEN had_conversion THEN 0
ELSE 1
END) * 100.0 / NULLIF(COUNT(*), 0) AS bounce_rate_pct
FROM session_metrics;Этот bounce ниже классического — обычно на 10-30 п.п.
Частые ошибки
Ошибка 1. Считать bounce там, где это SPA
В Single Page App все «страницы» — это hash-навигация. Если не трекаете SPA route changes — все сессии будут single-page и bounce 95%+. Проверьте, что route change шлёт pageview event.
Ошибка 2. Игнорировать time-on-page
Пользователь прочитал блог-пост 8 минут и ушёл — классический bounce, но в реальности это позитивный engagement. Используйте engaged-session bounce или scroll-depth.
Ошибка 3. Сравнивать bounce на лендинге vs внутренней странице
Bounce главной 30% и лендинга 60% — это нормально. Лендинг — пункт назначения для конкретного запроса. Сравнивайте однотипные страницы между собой.
Ошибка 4. Считать total bounce без сегментации
Total bounce 50% — бесполезный показатель. Сегментируйте по источнику, девайсу, типу страницы — это даст actionable signal.
Ошибка 5. Доверять bounce из бота-трафика
Если в данных нет фильтрации ботов — bounce будет завышен (боты часто заходят на одну страницу). Фильтруйте по user_agent или используйте flag is_bot.
Ошибка 6. Bounce vs Exit rate
Bounce — % сессий с одной страницы. Exit — % сессий, где страница была последней. Разные вещи.
Связанные темы
- Что такое engagement rate
- Как посчитать конверсию в SQL
- Как посчитать funnel в SQL
- DAU/MAU и stickiness
FAQ
Какой bounce rate считается нормальным?
Контент-блог: 60-80% — норма (пользователь прочитал и ушёл). E-commerce главная: 30-50%. Лендинг с конкретным CTA: 40-60%. SaaS dashboard: 10-20%. Сравнивайте только однотипные страницы.
Bounce 100% — что делать?
Сначала проверьте трекинг. Если SPA — смена маршрутов должна отправлять pageview-событие. Если десктоп-only — нет ли проблем с баннером согласия, блокирующим скрипты на мобильных.
Bounce rate важнее или session duration?
Зависит от страницы. Для блога — duration. Для лендинга с CTA — CR + bounce. Для каталога e-com — depth (страниц за сессию).
Можно ли уменьшить bounce искусственно?
Да, добавив 10-секундный auto-redirect или фейковый «второй pageview». Делать НЕЛЬЗЯ — обманывает себя и команду. Лучше работать с реальным engagement.
Bounce у моб vs десктопа отличаются?
Часто моб выше на 5-15 п.п. — экран меньше, скорость медленнее, юзер торопится. Нормально, сегментируйте.