Разработка инструмента для аналитики сервиса без помощи программистов
Руководитель группы веб-аналитики eLama Антон Леонтьев — о том, какие сервисы помогут составить график динамики активности пользователей.
Любому сервису, будь то система автоматизации работы для маркетологов, образовательная онлайн-площадка или игра, необходимо анализировать взаимодействие пользователей с разработанными инструментами.
В eLama есть ряд инструментов для контекстной рекламы: кроссминусация ключевых слов, комбинатор ключевых слов, загрузка расходов «Яндекс.Директа» в Google Analytics, «Рекомендатор», автоматическое управление ставками и другие. Коллег интересуют простые данные: сколько людей пользуются инструментами, какими опциями, насколько часто. Как получить ответы, особенно если ты работаешь в маркетинге, как я?
Первая мысль — поставить задачу разработчикам инструментов. Но у этого варианта есть ряд минусов:
Чтобы получать отчёты, аналитика должна быть встроена в инструмент изначально; если её нет, то придётся дописывать инструмент.
Все действия пользователей нужно логировать в базу, что создаст дополнительную нагрузку на неё. Это может сильно не понравиться программистам.
Задачи от маркетинга обычно не являются приоритетными для команд разработки, поэтому их могут откладывать.
Даже если отдел разработки и сделает аналитику и отчётность, то затем её нужно будет постоянно поддерживать, что-то менять, добавлять новые возможности — а это означает новые задачи и согласования с продакт-менеджерами и постоянное ожидание.
Разные инструменты создают разные команды разработки, используя свой инструментарий. Следовательно, каждый отчёт будет выглядеть иначе — нужно будет самостоятельно приводить их к единому стандарту.
Если логгировать действия в базу данных, то возникнут затруднения с созданием аудиторий для ремаркетинга в рекламных системах (как правило, нужно отправлять события с фронтенда сайта в их пиксели и счётчики). И аудитории можно будет создавать только вручную по email-адресам и другим данным о пользователях.
Хорошим решением задачи может быть введение отдельной должности аналитика в отделе разработки в подчинении у технического директора. Но мы рассмотрим вариант, когда веб-аналитик работает в маркетинге, и сделаем всё сами.
Нам понадобятся:
Google Analytics, если у вас сайт. Все действия пользователей внутри инструментов будем передавать как события;
Google BigQuery;
сбор несэмплированных данных Google Analytics в BigQuery (если у вас Google Analytics 360, то это будет бесплатно, иначе можно использовать платное решение OWOX BI Pipeline, как делаем мы);
Разработку аналитики рассмотрим на примере инструмента «Рекомендатор», который проверяет соответствие кампаний в «Яндекс.Директе» и Google AdWords рекомендациям рекламных систем. Мы построим два отчёта, которые будут ежедневно автоматически обновляться:
1. Какие рекомендации показывались и как с ними взаимодействовали пользователи:
Обозначения полей разберём ниже, когда будем строить этот отчёт.
2. Динамика использования по месяцам: количество пользователей, кампаний, заходов.
1. С каждым действием внутри инструмента нам нужно передавать в Google Analytics user_id пользователя в eLama. Для этого попросим программистов передавать его на фронтенд сайта при каждой загрузке страницы через JavaScript в глобальный массив dataLayer. Например, для пользователя с user_id равным 53300 это будет такая команда:
window.dataLayer = [{ 'user_id': '53300' }];
Её нужно разместить в самом начале исходного кода HTML-страницы:
2. Каждое событие в инструменте будем отправлять в dataLayer. Например, «запросил рекомендации» — когда пользователь заходит в «Рекомендатор»:
В этот момент нужно отправить в dataLayer следующую команду:
где event — название события;
recommendationsExternalCid — ID кампании в рекламной системе;
recommendationsAdSystem — название рекламной системы.
User_id пользователя мы в этот момент не передаём, так как его значение определяется при загрузке страницы благодаря настройке из первого пункта.
В отладчике Google Tag Manager это событие будет выглядеть следующим образом:
3. Аналогичным образом реализуем событие «пришли рекомендации»:
где event — название события;
recommendationsCount — количество пришедших рекомендаций;
User_id пользователя, recommendationsExternalCid и recommendationsAdSystem в этот момент мы не передаём, так как они уже определены в первом и втором пунктах.
Количество событий «запросил рекомендации» и «пришли рекомендации» в отчёте отличается, так как системе нужно несколько секунд на анализ кампании — не все пользователи дожидаются, пока придут рекомендации, иногда происходят ошибки, бывает недостаточно баллов API «Яндекс.Директа». Кроме того, рекомендации приходят после другого события — «обновить рекомендации».
4. Аналогично настраиваем событие «переход на ссылку — статью» (переход в Справочный центр eLama из описания рекомендации):
где event — название события;
recommendationType — идентификатор рекомендации, с которой пользователь взаимодействовал (может быть только одна).
Так же реализуем остальные события в «Рекомендаторе»: «кликнул на подробнее», «переход на ссылку — кнопку», «переход на ссылку — объявление», «обновил список», «закончились баллы API «Яндекс.Директа», «попросил новую». Вот как эти опции выглядят в интерфейсе инструмента:
5. Теперь нужно создать переменные в Google Tag Manager, соответствующие каждой переменной из dataLayer (кроме event). Например, для recommendationsExternalCid:
6. Для каждого события (event в dataLayer) создадим триггер и тег в Google Tag Manager, чтобы отправлять события в Google Analytics. Например, «пришли рекомендации»:
В категории «события» Google Analytics мы указываем название инструмента, то есть «Рекомендатор». «События» — это тип взаимодействия с инструментом, например, «пришли рекомендации».
В ярлык события нам нужно передать остальные параметры: название рекламной системы, id кампании, количество пришедших рекомендаций и их идентификаторы. Поэтому будем передавать их в формате JSON, чтобы можно было обрабатывать в дальнейшем, то есть для нашего примера: {"adSystem":"direct","externalCid":"29833481", "count":"5","list":"r03 r04 r05 r08 r20"}.
В Google Tag Manager при настройке тега в ярлыке нужно указывать названия переменных в двойных фигурных скобках: {"adSystem":"{{recommendationsAdSystem}}","externalCid":"{{recommendationsExternalCid}}", "count":"{{recommendationsCount}}","list":"{{recommendationsList}}"}
User_id пользователя, воспользовавшегося инструментом, тоже можно передавать в ярлыке, но мы сделали иначе, передаём через поле userId и специальный параметр при вызове Google Analytics на странице:
7. Если всё настроили правильно, то в Google Analytics станет доступна статистика по событиям:
Если необходимо посмотреть user_id пользователя, то нужно добавить дополнительным параметром в отчёте специальный параметр с индексом четыре, который настроили в шестом пункте.
8. В простом виде у нас уже есть вся статистика по инструменту. Все события можно выгрузить из Google Analytics в файле Excel и вручную обработать. Но, конечно, этот вариант нас не устроит, поэтому мы будем обрабатывать данные автоматически, используя стриминг несэмплированных данных Google Analytics OWOX BI Pipeline в BigQuery.
Создадим в BigQuery view виртуальную таблицу tools_web.recommender, которая будет содержать все события в инструменте. Дальнейшие отчёты будем строить на её основе. Эта таблица будет выглядеть следующим образом:
Например, пользователь 184145 сначала запросил рекомендации, потом ему пришло три рекомендации, в том числе r03 и ещё две, которые не поместились на скриншоте. Затем он кликнул на «подробнее» в рекомендации r03 и перешёл в справку к статье по этой же рекомендации и так далее.
Сохранение view в интерфейсе BigQuery выглядит следующим образом:
9. Построим первый отчёт со статистикой по всем событиям:
где eventAction — название события;
adSystem — рекламная система;
count — сколько событий всего было;
campaigns — количество разных кампаний, в которых происходило событие;
users — количество юзеров;
count_r — суммарное количество пришедших рекомендаций;
count_r_avg — среднее количество рекомендаций, которое приходит за один раз;
count_r_median — медианное количество рекомендаций, которое приходит за один раз;
r03, r04, r05 — количество событий, которые произошли с конкретной рекомендацией, например рекомендация r05 пришла всего 5098 раз, в то время, как r03 приходила гораздо чаще — 41294 раза.
SQL-запрос для получения отчёта будет иметь следующий вид:
С этим отчётом можно работать не только в интерфейсе Google BigQuery, но и сохранить его в Google Sheets или скачать в CSV. Можно поступить другим образом — создать Google Sheets с доступом коллегам, а в него данные подтягивать через OWOX BI BigQuery Reports, там же можно настроить ежедневное обновление по расписанию.
10. Построим второй отчёт с динамикой использования «Рекомендатора» по месяцам. В табличном виде он будет выглядеть так:
Если же подключить инструмент визуализации, например, Redash, можно получить отчёт в графическом виде:
11. Используя таблицу tools_web.recommender, содержащую все события, можно построить множество других отчётов: возвращаемость пользователей, частоту использования, найти самые проблемные кампании с точки зрения «Рекомендатора», или наоборот. Данные можно сегментировать по географии клиентов (регион определять по Google Analytics), по различным сегментам пользователей, например, по средним чекам, если в BigQuery хранятся транзакции клиентов и так далее.
12. Так как все события отправляются через Tag Manager, то без проблем можно добавить события «Яндекс.Метрики», Facebook, «ВКонтакте» для сбора рекламных аудиторий для ремаркетинга. А для Google AdWords можно сразу настраивать аудитории по описанным событиям Google Analytics.
Мы разметили события в инструменте, они сохраняются в облачной базе данных, мы научились строить различные отчёты. И всё это собственными руками, практически не отвлекая разработчиков. Если вы не знаете SQL, вам должно хватить скриптов, которые прилагаются к статье.
Недостатки описанного метода:
события не будут срабатывать, если у пользователя не подгрузился Google Analytics или система мобильной аналитики (включён анонимайзер или сама система веб-аналитики заглючила) — будут некоторые потери данных;
стриминг несэмплированных данных в BigQuery платный; или бесплатен в платных версиях систем веб-аналитики;
чтобы разместить события на сайте (в приложении), нужно привлечь разработчиков, но всё равно это гораздо менее трудозатратно, чем полностью отдать всю аналитику на их сторону;
за сбор статистики отвечает не внутренняя система, поэтому возможна подделка событий (спам).
"}},{"type":"list","cover":false,"hidden":false,"anchor":"","data":{"items":["где event — название события;","recommendationsExternalCid — ID кампании в рекламной системе;","recommendationsAdSystem — название рекламной системы."],"type":"UL"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"
User_id пользователя мы в этот момент не передаём, так как его значение определяется при загрузке страницы благодаря настройке из первого пункта.
3. Аналогичным образом реализуем событие «пришли рекомендации»:
"}},{"type":"rawhtml","cover":false,"hidden":false,"anchor":"","data":{"raw":"\n"}},{"type":"list","cover":false,"hidden":false,"anchor":"","data":{"items":["где event — название события;","recommendationsCount — количество пришедших рекомендаций;","recommendationsList — идентификаторы рекомендаций, разделённые запятыми."],"type":"UL"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"
User_id пользователя, recommendationsExternalCid и recommendationsAdSystem в этот момент мы не передаём, так как они уже определены в первом и втором пунктах.
Количество событий «запросил рекомендации» и «пришли рекомендации» в отчёте отличается, так как системе нужно несколько секунд на анализ кампании — не все пользователи дожидаются, пока придут рекомендации, иногда происходят ошибки, бывает недостаточно баллов API «Яндекс.Директа». Кроме того, рекомендации приходят после другого события — «обновить рекомендации».
4. Аналогично настраиваем событие «переход на ссылку — статью» (переход в Справочный центр eLama из описания рекомендации):
"}},{"type":"rawhtml","cover":false,"hidden":false,"anchor":"","data":{"raw":"\n"}},{"type":"list","cover":false,"hidden":false,"anchor":"","data":{"items":["где event — название события;","recommendationType — идентификатор рекомендации, с которой пользователь взаимодействовал (может быть только одна)."],"type":"UL"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"
Так же реализуем остальные события в «Рекомендаторе»: «кликнул на подробнее», «переход на ссылку — кнопку», «переход на ссылку — объявление», «обновил список», «закончились баллы API «Яндекс.Директа», «попросил новую». Вот как эти опции выглядят в интерфейсе инструмента:
5. Теперь нужно создать переменные в Google Tag Manager, соответствующие каждой переменной из dataLayer (кроме event). Например, для recommendationsExternalCid:
6. Для каждого события (event в dataLayer) создадим триггер и тег в Google Tag Manager, чтобы отправлять события в Google Analytics. Например, «пришли рекомендации»:
В категории «события» Google Analytics мы указываем название инструмента, то есть «Рекомендатор». «События» — это тип взаимодействия с инструментом, например, «пришли рекомендации».
В ярлык события нам нужно передать остальные параметры: название рекламной системы, id кампании, количество пришедших рекомендаций и их идентификаторы. Поэтому будем передавать их в формате JSON, чтобы можно было обрабатывать в дальнейшем, то есть для нашего примера: {\"adSystem\":\"direct\",\"externalCid\":\"29833481\", \"count\":\"5\",\"list\":\"r03 r04 r05 r08 r20\"}.
В Google Tag Manager при настройке тега в ярлыке нужно указывать названия переменных в двойных фигурных скобках: {\"adSystem\":\"{{recommendationsAdSystem}}\",\"externalCid\":\"{{recommendationsExternalCid}}\", \"count\":\"{{recommendationsCount}}\",\"list\":\"{{recommendationsList}}\"}
User_id пользователя, воспользовавшегося инструментом, тоже можно передавать в ярлыке, но мы сделали иначе, передаём через поле userId и специальный параметр при вызове Google Analytics на странице:
Если необходимо посмотреть user_id пользователя, то нужно добавить дополнительным параметром в отчёте специальный параметр с индексом четыре, который настроили в шестом пункте.
8. В простом виде у нас уже есть вся статистика по инструменту. Все события можно выгрузить из Google Analytics в файле Excel и вручную обработать. Но, конечно, этот вариант нас не устроит, поэтому мы будем обрабатывать данные автоматически, используя стриминг несэмплированных данных Google Analytics OWOX BI Pipeline в BigQuery.
Создадим в BigQuery view виртуальную таблицу tools_web.recommender, которая будет содержать все события в инструменте. Дальнейшие отчёты будем строить на её основе. Эта таблица будет выглядеть следующим образом:
Например, пользователь 184145 сначала запросил рекомендации, потом ему пришло три рекомендации, в том числе r03 и ещё две, которые не поместились на скриншоте. Затем он кликнул на «подробнее» в рекомендации r03 и перешёл в справку к статье по этой же рекомендации и так далее.
9. Построим первый отчёт со статистикой по всем событиям:
"}},{"type":"media","cover":false,"hidden":false,"anchor":"","data":{"items":[{"title":"","image":{"type":"image","data":{"uuid":"99872b1a-160a-c630-c3a9-f34d8339c58e","width":901,"height":467,"size":23853,"type":"png","color":"","hash":"","external_service":[]}}}]}},{"type":"list","cover":false,"hidden":false,"anchor":"","data":{"items":["где eventAction — название события;","adSystem — рекламная система;","count — сколько событий всего было;","campaigns — количество разных кампаний, в которых происходило событие;","users — количество юзеров;","count_r — суммарное количество пришедших рекомендаций;","count_r_avg — среднее количество рекомендаций, которое приходит за один раз;","count_r_median — медианное количество рекомендаций, которое приходит за один раз;","r03, r04, r05 — количество событий, которые произошли с конкретной рекомендацией, например рекомендация r05 пришла всего 5098 раз, в то время, как r03 приходила гораздо чаще — 41294 раза."],"type":"UL"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"
SQL-запрос для получения отчёта будет иметь следующий вид:
С этим отчётом можно работать не только в интерфейсе Google BigQuery, но и сохранить его в Google Sheets или скачать в CSV. Можно поступить другим образом — создать Google Sheets с доступом коллегам, а в него данные подтягивать через OWOX BI BigQuery Reports, там же можно настроить ежедневное обновление по расписанию.
11. Используя таблицу tools_web.recommender, содержащую все события, можно построить множество других отчётов: возвращаемость пользователей, частоту использования, найти самые проблемные кампании с точки зрения «Рекомендатора», или наоборот. Данные можно сегментировать по географии клиентов (регион определять по Google Analytics), по различным сегментам пользователей, например, по средним чекам, если в BigQuery хранятся транзакции клиентов и так далее.
12. Так как все события отправляются через Tag Manager, то без проблем можно добавить события «Яндекс.Метрики», Facebook, «ВКонтакте» для сбора рекламных аудиторий для ремаркетинга. А для Google AdWords можно сразу настраивать аудитории по описанным событиям Google Analytics.
Мы разметили события в инструменте, они сохраняются в облачной базе данных, мы научились строить различные отчёты. И всё это собственными руками, практически не отвлекая разработчиков. Если вы не знаете SQL, вам должно хватить скриптов, которые прилагаются к статье.
"}},{"type":"list","cover":false,"hidden":false,"anchor":"","data":{"items":["события не будут срабатывать, если у пользователя не подгрузился Google Analytics или система мобильной аналитики (включён анонимайзер или сама система веб-аналитики заглючила) — будут некоторые потери данных;","стриминг несэмплированных данных в BigQuery платный; или бесплатен в платных версиях систем веб-аналитики;","чтобы разместить события на сайте (в приложении), нужно привлечь разработчиков, но всё равно это гораздо менее трудозатратно, чем полностью отдать всю аналитику на их сторону;","за сбор статистики отвечает не внутренняя система, поэтому возможна подделка событий (спам)."],"type":"UL"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"
#кейсы
"}}],"summaryContent":null,"isExistSummaryContent":false,"warningFromEditor":null,"warningFromEditorTitle":null,"counters":{"comments":7,"favorites":16,"reposts":0,"views":5,"hits":3630,"reads":null,"online":0},"dateFavorite":0,"hitsCount":3630,"isCommentsEnabled":true,"isLikesEnabled":true,"isRemovedByUserRequest":false,"isFavorited":false,"isPinned":false,"repostId":null,"repostData":null,"subscribedToTreads":false,"isEditorial":false,"isAudioAvailable":false,"audioUrl":null,"isAudioAvailableToGenerate":false,"commentEditor":{"enabled":true,"who":null,"text":"","until":null,"reason":null,"type":"everybody"},"isBlur":false,"isPublished":true,"isDisabledAd":true,"withheld":[],"ogTitle":null,"ogDescription":null,"url":"https://vc.ru/flood/30439-razrabotka-instrumenta-dlya-analitiki-servisa-bez-pomoshi-programmistov","author":{"id":126010,"name":"Антон Леонтьев","nickname":null,"description":null,"uri":"","avatar":{"type":"image","data":{"uuid":"7682c757-58be-3cec-af7a-95062b9dfd84","width":0,"height":0,"size":1,"type":"jpg","color":"","hash":"","external_service":[]}},"cover":null,"achievements":[{"title":"Год на vc.ru","code":"registration_1_year","description":"Первый год с vc.ru. Получена 24 июля 2025.","previewUuid":"0d11c244-49de-50e7-894e-b9b27945d42b","formats":{"glb":"https://static.vc.ru/achievements/fish.glb","usdz":"https://static.vc.ru/achievements/fish.usdz"},"viewData":{"contentColor":"#C67AA3","textMaxWidth":0.634765625,"textX":0.5888671875,"textY":0.54296875,"logoX":0.5859375,"logoY":0.6669921875,"logoXNoText":0.6044921875,"logoYNoText":0.5439453125},"id":5295770,"userId":126010,"count":0,"shareImage":"https://api.vc.ru/achievements/share/5295770"},{"title":"3 года на vc.ru","code":"registration_3_years","description":"Провёл 3 года вместе с vc.ru. Получена 23 июля 2025.","previewUuid":"d9d72ac5-bcb5-55e0-8c72-b99251e5cdd9","formats":{"glb":"https://static.vc.ru/achievements/shark.glb","usdz":"https://static.vc.ru/achievements/shark.usdz"},"viewData":{"contentColor":"#8E6F09","textMaxWidth":0.66796875,"textX":0.5205078125,"textY":0.341796875,"logoX":0.5205078125,"logoY":0.4609375,"logoXNoText":0.5,"logoYNoText":0.3662109375},"id":1671683,"userId":126010,"count":0,"shareImage":"https://api.vc.ru/achievements/share/1671683"},{"title":"5 лет на vc.ru","code":"registration_5_years","description":"Провёл 5 лет вместе с vc.ru. Получена 23 июля 2025.","previewUuid":"a9140d54-73b8-5f40-afa8-449fbaafd42b","formats":{"glb":"https://static.vc.ru/achievements/whale.glb","usdz":"https://static.vc.ru/achievements/whale.usdz"},"viewData":{"contentColor":"#8E6F09","textMaxWidth":0.66796875,"textX":0.533203125,"textY":0.658203125,"logoX":0.533203125,"logoY":0.77734375,"logoXNoText":0.4375,"logoYNoText":0.66015625},"id":444975,"userId":126010,"count":0,"shareImage":"https://api.vc.ru/achievements/share/444975"}],"lastModificationDate":1765023790,"isSubscribed":false,"isSubscribedToNewPosts":false,"isMuted":false,"isAvailableForMessenger":true,"badgeId":null,"isDonationsEnabled":false,"isPlusGiftEnabled":true,"isUnverifiedBlogForCompanyWithoutPro":false,"isRemovedByUserRequest":false,"isFrozen":false,"isDisabledAd":false,"isPlus":false,"isVerified":false,"isPro":false,"yandexMetricaId":null,"badge":null,"isOnline":false,"tgChannelShortname":null,"isUnsubscribable":true,"type":1,"subtype":"personal_blog"},"subsite":{"id":199791,"name":"Офтоп","description":"Всё, что не поместилось в другие подсайты, но всё равно может быть интересно посетителям vc.ru.","uri":"/flood","avatar":{"type":"image","data":{"uuid":"42328f5f-b62f-541e-b4e0-2029f8489d47","width":1200,"height":1200,"size":14734,"type":"png","color":"3c3c3c","hash":"406020346c486c64","external_service":[]}},"cover":{"type":"image","data":{"uuid":"ea4f90c7-7ebb-57f7-b3ec-9d7890cad203","width":960,"height":280,"size":177,"type":"png","color":"fcdcfc","hash":"","external_service":[]}},"lastModificationDate":1612968637,"isSubscribed":false,"isSubscribedToNewPosts":false,"isMuted":false,"isAvailableForMessenger":false,"isDisabledAd":false,"nickname":"flood","isUnsubscribable":true,"badge":null,"badgeId":null,"isDonationsEnabled":false,"isOnline":false,"isPlus":false,"isUnverifiedBlogForCompanyWithoutPro":false,"isVerified":false,"isRemovedByUserRequest":false,"isFrozen":false,"isPro":false,"type":2,"subtype":"community"},"reactions":{"counters":[{"id":1,"count":5}],"reactionId":0},"isNews":false,"source":null,"clusters":[],"donations":{"amount":0,"isDonated":false},"commentsSeenCount":null,"keywords":["кейсы"],"media":null,"customCover":null,"robotsTag":null,"categories":[],"isAnonymized":true}};