gmaedev

gmaedev

Геймдев Чебурек. Делаю игры. https://t.me/gmaedev
На Пикабу
100 рейтинг 1 подписчик 2 подписки 1 пост 0 в горячем
3

Как две минуты первой сессии предсказывают судьбу вашей игры (и 4 SQL-запроса для анализа)

Анализ первой сессии -- это "момент истины" для твоей игры.

Представь, что игрок только что установил твою игру. У него нет лояльности, нет эмоциональной связи с проектом. Его первая сессия -- это как первое свидание: либо возникает магия, либо вы больше не увидитесь.

Замылил картинку для интриги :D

Замылил картинку для интриги :D

Ниже я расскажу, как на основе длительности этого "свидания", можно давать оценку и строить гипотезы. А еще прикреплю SQL запросы и поделюсь аналитикой по своей веб-игре Ферма на острове (https://yandex.ru/games/app/336608).

Что показывает длительность первой игровой сессии

1. Эффективность онбординга

  • Короткая сессия (менее 3-5 минут) часто означает, что игрок "уперся в стену" -- не понял механики, запутался в интерфейсе или столкнулся с техническими проблемами

  • Оптимальная длительность (5-15 минут) говорит о плавном вхождении в игру

  • Длинная сессия (15+ минут) — игрок "зацепился", он получил достаточно мотивации продолжать

2. Прогноз долгосрочного удержания

По моим данным (я их округлил для наглядности), игроки с первой сессией:

  • Менее 2 минут — 80% никогда не возвращаются

  • 5-10 минут — 45% возвращаются на следующий день

  • 15+ минут — 65% играют через 7 дней

3. Качество маркетингового трафика

Разная длительность сессии по источникам:

  • Рекламные сети — часто короткие сессии, если реклама не соответствует геймплею

  • Рекомендации друзей — более длинные сессии, так как есть социальное доверие

  • Органический поиск — самые вовлеченные пользователи

Сбор данных и SQL запросы

Данные я собираю в Unity Analytics.

Анализ длительности первой сессии за последние 90 дней

WITH first_sessions AS (

SELECT

USER_ID,

EVENT_JSON:sessionID::STRING as session_id,

MIN(EVENT_TIMESTAMP) as first_session_start

FROM EVENTS

WHERE EVENT_JSON:eventName::STRING = 'newPlayer'

GROUP BY USER_ID, EVENT_JSON:sessionID::STRING

),

session_durations AS (

SELECT

fs.USER_ID,

fs.session_id,

fs.first_session_start,

MIN(e.EVENT_TIMESTAMP) as session_start,

MAX(e.EVENT_TIMESTAMP) as session_end,

DATEDIFF(second, MIN(e.EVENT_TIMESTAMP), MAX(e.EVENT_TIMESTAMP)) as duration_seconds

FROM first_sessions fs

JOIN EVENTS e ON fs.USER_ID = e.USER_ID

AND fs.session_id = e.EVENT_JSON:sessionID::STRING

WHERE e.EVENT_DATE > CURRENT_DATE-90

GROUP BY fs.USER_ID, fs.session_id, fs.first_session_start

),

percentiles AS (

SELECT

APPROX_PERCENTILE(duration_seconds, 0.1) as p10_seconds,

APPROX_PERCENTILE(duration_seconds, 0.5) as p50_seconds,

APPROX_PERCENTILE(duration_seconds, 0.9) as p90_seconds,

AVG(duration_seconds) as avg_duration_seconds,

COUNT(*) as total_sessions

FROM session_durations

WHERE duration_seconds >= 0 -- исключаем отрицательные значения

)

SELECT

ROUND(p10_seconds, 2) as p10_duration_seconds,

ROUND(p50_seconds, 2) as median_duration_seconds,

ROUND(p90_seconds, 2) as p90_duration_seconds,

ROUND(avg_duration_seconds, 2) as average_duration_seconds,

total_sessions

FROM percentiles;

Анализ длительности первой сессий по платформам за последние 90 дней

Если аналитика по твоей игре собирается сразу для нескольких платформ, то будет полезно посмотреть на них отдельно.

WITH first_sessions AS (

SELECT

USER_ID,

EVENT_JSON:sessionID::STRING as session_id,

MIN(EVENT_TIMESTAMP) as first_session_start,

EVENT_JSON:platform::STRING as platform

FROM EVENTS

WHERE EVENT_JSON:eventName::STRING = 'newPlayer'

GROUP BY USER_ID, EVENT_JSON:sessionID::STRING, EVENT_JSON:platform::STRING

),

session_durations AS (

SELECT

fs.USER_ID,

fs.session_id,

fs.platform,

fs.first_session_start,

MIN(e.EVENT_TIMESTAMP) as session_start,

MAX(e.EVENT_TIMESTAMP) as session_end,

DATEDIFF(second, MIN(e.EVENT_TIMESTAMP), MAX(e.EVENT_TIMESTAMP)) as duration_seconds

FROM first_sessions fs

JOIN EVENTS e ON fs.USER_ID = e.USER_ID

AND fs.session_id = e.EVENT_JSON:sessionID::STRING

WHERE e.EVENT_DATE > CURRENT_DATE-90

AND fs.platform IS NOT NULL

GROUP BY fs.USER_ID, fs.session_id, fs.platform, fs.first_session_start

)

SELECT

COALESCE(platform, 'Не указана') as platform,

ROUND(APPROX_PERCENTILE(duration_seconds, 0.1), 2) as p10_duration_seconds,

ROUND(APPROX_PERCENTILE(duration_seconds, 0.5), 2) as median_duration_seconds,

ROUND(APPROX_PERCENTILE(duration_seconds, 0.9), 2) as p90_duration_seconds,

ROUND(AVG(duration_seconds), 2) as average_duration_seconds,

COUNT(*) as total_sessions

FROM session_durations

GROUP BY platform

ORDER BY total_sessions DESC;

Анализ длительности первой сессии понедельно за последние три квартала

Иногда может быть полезно посмотреть как изменилась длина первой сессии с течением времени.

WITH first_sessions AS (

SELECT

USER_ID,

EVENT_JSON:sessionID::STRING as session_id,

MIN(EVENT_TIMESTAMP) as first_session_start,

EVENT_JSON:platform::STRING as platform,

YEAR(EVENT_TIMESTAMP) as session_year,

WEEK(EVENT_TIMESTAMP) as session_week

FROM EVENTS

WHERE EVENT_JSON:eventName::STRING = 'newPlayer'

GROUP BY USER_ID, EVENT_JSON:sessionID::STRING, EVENT_JSON:platform::STRING,

YEAR(EVENT_TIMESTAMP), WEEK(EVENT_TIMESTAMP)

),

session_durations AS (

SELECT

fs.USER_ID,

fs.session_id,

fs.platform,

fs.first_session_start,

fs.session_year,

fs.session_week,

MIN(e.EVENT_TIMESTAMP) as session_start,

MAX(e.EVENT_TIMESTAMP) as session_end,

DATEDIFF(second, MIN(e.EVENT_TIMESTAMP), MAX(e.EVENT_TIMESTAMP)) as duration_seconds

FROM first_sessions fs

JOIN EVENTS e ON fs.USER_ID = e.USER_ID

AND fs.session_id = e.EVENT_JSON:sessionID::STRING

WHERE e.EVENT_DATE > CURRENT_DATE-270

AND fs.platform IS NOT NULL

GROUP BY fs.USER_ID, fs.session_id, fs.platform, fs.first_session_start,

fs.session_year, fs.session_week

)

SELECT

session_year,

session_week,

CONCAT(session_year, '-W', LPAD(session_week, 2, '0')) as year_week,

ROUND(APPROX_PERCENTILE(duration_seconds, 0.1), 2) as p10_duration_seconds,

ROUND(APPROX_PERCENTILE(duration_seconds, 0.5), 2) as median_duration_seconds,

ROUND(APPROX_PERCENTILE(duration_seconds, 0.9), 2) as p90_duration_seconds,

ROUND(AVG(duration_seconds), 2) as average_duration_seconds,

COUNT(*) as total_sessions

FROM session_durations

WHERE session_year IS NOT NULL

AND session_week IS NOT NULL

GROUP BY session_year, session_week

ORDER BY year_week ASC;

Анализ длительности первой сессии по версиям за последний год

И еще интереснее сравнить длительность первой сессии для каждой версии игры за последнее время.

WITH first_sessions AS (

SELECT

USER_ID,

EVENT_JSON:sessionID::STRING as session_id,

MIN(EVENT_TIMESTAMP) as first_session_start,

EVENT_JSON:clientVersion::STRING as version

FROM EVENTS

WHERE EVENT_JSON:eventName::STRING = 'newPlayer'

GROUP BY USER_ID, EVENT_JSON:sessionID::STRING, EVENT_JSON:clientVersion::STRING

),

session_durations AS (

SELECT

fs.USER_ID,

fs.session_id,

fs.version,

fs.first_session_start,

MIN(e.EVENT_TIMESTAMP) as session_start,

MAX(e.EVENT_TIMESTAMP) as session_end,

DATEDIFF(second, MIN(e.EVENT_TIMESTAMP), MAX(e.EVENT_TIMESTAMP)) as duration_seconds

FROM first_sessions fs

JOIN EVENTS e ON fs.USER_ID = e.USER_ID

AND fs.session_id = e.EVENT_JSON:sessionID::STRING

WHERE e.EVENT_DATE > CURRENT_DATE-360

AND fs.version IS NOT NULL

GROUP BY fs.USER_ID, fs.session_id, fs.version, fs.first_session_start

)

SELECT

version,

ROUND(APPROX_PERCENTILE(duration_seconds, 0.1), 2) as p10_duration_seconds,

ROUND(APPROX_PERCENTILE(duration_seconds, 0.5), 2) as median_duration_seconds,

ROUND(APPROX_PERCENTILE(duration_seconds, 0.9), 2) as p90_duration_seconds,

ROUND(AVG(duration_seconds), 2) as average_duration_seconds,

COUNT(*) as total_sessions

FROM session_durations

WHERE version IS NOT NULL

GROUP BY version

ORDER BY version DESC;

Пример например

На примере веб-игры Ферма на острове (https://yandex.ru/games/app/336608), я собрал следующий запрос (ниже опишу разницу):

WITH first_sessions AS (

SELECT

USER_ID,

EVENT_JSON:sessionID::STRING as session_id,

MIN(EVENT_TIMESTAMP) as first_session_start,

EVENT_JSON:clientVersion::STRING as version

FROM EVENTS

WHERE EVENT_JSON:eventName::STRING = 'newPlayer'

GROUP BY USER_ID, EVENT_JSON:sessionID::STRING, EVENT_JSON:clientVersion::STRING

),

session_durations AS (

SELECT

fs.USER_ID,

fs.session_id,

fs.version,

fs.first_session_start,

MIN(e.EVENT_TIMESTAMP) as session_start,

MAX(e.EVENT_TIMESTAMP) as session_end,

DATEDIFF(second, MIN(e.EVENT_TIMESTAMP), MAX(e.EVENT_TIMESTAMP)) as duration_seconds

FROM first_sessions fs

JOIN EVENTS e ON fs.USER_ID = e.USER_ID

AND fs.session_id = e.EVENT_JSON:sessionID::STRING

WHERE fs.version IS NOT NULL

GROUP BY fs.USER_ID, fs.session_id, fs.version, fs.first_session_start

)

SELECT

version,

ROUND(APPROX_PERCENTILE(duration_seconds, 0.1), 2) as p10_duration_seconds,

ROUND(APPROX_PERCENTILE(duration_seconds, 0.5), 2) as median_duration_seconds,

ROUND(APPROX_PERCENTILE(duration_seconds, 0.9), 2) as p90_duration_seconds,

ROUND(AVG(duration_seconds), 2) as average_duration_seconds,

COUNT(*) as total_sessions

FROM session_durations

WHERE version IS NOT NULL

GROUP BY version

HAVING total_sessions > 100

ORDER BY version DESC;

Номер версии генерируется автоматически при сборке -- могу рассказать другим постом, если интересно...

1. Я исключил данные по версиям, в которых было менее 100 первых сессий, чтобы убрать всплески:

Вот эти пики точеные портят картину

Вот эти пики точеные портят картину

Например тут было две сессии, где игроков затянуло

Например тут было две сессии, где игроков затянуло

2. Выгребаю данные за всё время, чтобы вот вообще всё увидеть :D

Вот, что получилось:

Результат анализа времени первой игровой сессии

Результат анализа времени первой игровой сессии

Релиз 1.1.2 от 30 октября 2024 года каким-то образом сломал первое впечатление об игре.

50% игроков проводили 43 секунды и меньше в свою первую игровую сессию

50% игроков проводили 43 секунды и меньше в свою первую игровую сессию

Тогда я об этом узнал не сразу, а только через неделю, потому что только-только настраивал аналитику. Это было мега печально, потому что эти игроки были привлечены рекламой за кровные.

Протестировав игру через инкогнито самостоятельно и привлекая друзей, удалось определить причину отвала: аналитика собиралась некорректно.

В браузерных играх, Unity Analytics складывает идентификатор пользователя в куки, а как только они протухают, то обновляет его. Получалось, что каждый раз, игра идентифицировала игрока по новой и считала, что это его первая сессия.

Решение было простым: генерировать случайный идентификатор и сохранять его в данных игрока, а затем использовать в качестве UnityServices.ExternalUserId.

20 октября была выпущена версия 1.2.0, в которой игра начала идентифицировать игроков корректно:

Это позволило адекватно оценить продолжительность первой игровой сессии и составить ряд гипотез. Первое, что бросилось в глаза после плейтестов: игра дарит игроку снаряжение, но не объясняет, как им пользоваться.

Спустя еще неделю игра начала обучать игрока экипировать и прокачивать снаряжение, и вот результат:

Это дало прирост в две минуты или ~28%!

После нескольких релизов летом, начиная с реализации защиты от накруток при переводе времени на устройстве, медиана начала падать:

Возможно, механики просто наскучили и игроки хотят чего-то нового.

Гипотезы закончились, проект наскучил и я переключился на новый.

Заключение

Надеюсь, что мне удалось рассказать что-то интересное и поделиться опытом аналитики.

Спасибо за внимание! Жду вопросы в комментариях.

Показать полностью 7
Отличная работа, все прочитано!

Темы

Политика

Теги

Популярные авторы

Сообщества

18+

Теги

Популярные авторы

Сообщества

Игры

Теги

Популярные авторы

Сообщества

Юмор

Теги

Популярные авторы

Сообщества

Отношения

Теги

Популярные авторы

Сообщества

Здоровье

Теги

Популярные авторы

Сообщества

Путешествия

Теги

Популярные авторы

Сообщества

Спорт

Теги

Популярные авторы

Сообщества

Хобби

Теги

Популярные авторы

Сообщества

Сервис

Теги

Популярные авторы

Сообщества

Природа

Теги

Популярные авторы

Сообщества

Бизнес

Теги

Популярные авторы

Сообщества

Транспорт

Теги

Популярные авторы

Сообщества

Общение

Теги

Популярные авторы

Сообщества

Юриспруденция

Теги

Популярные авторы

Сообщества

Наука

Теги

Популярные авторы

Сообщества

IT

Теги

Популярные авторы

Сообщества

Животные

Теги

Популярные авторы

Сообщества

Кино и сериалы

Теги

Популярные авторы

Сообщества

Экономика

Теги

Популярные авторы

Сообщества

Кулинария

Теги

Популярные авторы

Сообщества

История

Теги

Популярные авторы

Сообщества