Один тег на всі івенти GA4: налаштувати раз і забути назавжди

Опубліковано:

Кожен новий івент - це новий тег, новий тригер і новий реліз контейнера. І так щотижня, аж поки від однотипних налаштувань не почне нудити, а кількість тригерів зростає пропорційно кількості нових тегів. Показую спосіб, у якому один тег обробляє всі івенти одразу, і чесно розповідаю про трейд-офи цього методу. Як бонус показую дещо схоже і для налаштування конверсій на прикладі Google Ads.

Давним-давно хотів поділитися цим матеріалом зі світом. Можливо, що хтось, десь, колись, щось таке вже імплементував, але чогось подібного на просторах інтернету я не знаходив.

Поговоримо про так звані авто-івенти в веб-ГТМі. Зауважу, що мова піде не про ті івенти, котрі ГА4 збирає за замовчуванням, і навіть не про розширені (Enhanced Measurement) івенти. Всю суть спробую описати на кейсі. Отже, уявімо…

Ви - перспективний веб-аналітик, пройшли якийсь з курсів по веб Гугл Таг Менеджеру, і працюєте над якимось проектом, де в перелік ваших обовʼязків входить налаштування івентів для гугл аналітики (що очевидно). Зараз абсолютно не важливо, чи то SaaS, онлайн-магазин або сайт послуг - на будь-якому сайті має працювати відстеження подій та конверсій.

Прийшла задача налаштувати якийсь івент для GA4. Нуль питань! Ви налаштували тег типу GA4 Event, нашвидкуруч взяли з форми селектор для тригера типу Form Submission, перевірили в дебаг моді - все працює, і зарелізили. Все чітко, бос подякував.

На наступний день приходить до вас ось та симпатична дизайнерка і просить повісити івент на відстеження он тієї кнопочки з котиками. Банальна задача, доріжка вже протоптана і через півгодини ви відписуєте їй, що кліки вже збираються в аналітику.

Далі так продовжується майже кожен день і на другий місяць ви вже лізете на стелю від того, як вас нудить налаштовувати ці однотипні івенти. Інтерфейс ГТМу зсередини починає бути все менш і менш охайним та зрозумілим, кількість тригерів росте пропорційно кількості тегів на окремі івенти. Та ви не засмучуйтесь (принаймні, поки), оскільки навчені користуватися пошуком всередині інтерфейсу. Але до вас приходить усвідомлення, що в такому режимі орієнтуватися всередині контейнеру скоро стане неможливо.

Саме цей біль ми і будемо лікувати методом, описаним нижче. Але перш ніж ми перейдемо до налаштувань, прочитайте декілька порад від мене.

Моя порада і трохи передісторії

Не використовуйте трігери на селекторах

Або намагайтесь їх використовувати по мінімуму. Так, ГТМ був створений для маркетологів, щоб бути менш залежним від розробників, але я не раз бачив, як фронт-енд розробники ламають трекінг банально змінюючи класи, айдішки або переставляючи вкладеності елементів.

Моя порада: намагайтесь по максимуму використовувати тригери типу Custom Event. Так, це треба писати ТЗ на даталеєр пуші, і виходить трохи довше через залученість інших осіб до налаштування, але на дистанції це дає більш стійкий і надійний результат. З приходом епохи AI і можливості Claude Code, кодова база, гіт і репозиторії - вже не такі страшні слова для маркетологів, тож можна обійтись і без третіх рук. В будь-якому випадку вважайте це невеликим дисклеймером, бо далі про даталеєр пуші ми ще обовʼязково будемо говорити.

Короткий екскурс в епоху Universal Analytics

Раніше, в старій аналітиці, ми налаштовували цілі (Goals). Їх було 20 штук на одне вʼю (так, це був третій рівень в Universal Analytics - один проперті аналітики міг містити декілька вʼю).

Передавати дані через даталеєр пуш було найбільш «правильним» тоді - і лишається таким зараз. Тоді це були параметри eventCategory, eventAction, eventLabel, які клав розробник.

Саме тоді і народився метод, котрий спеціалісти між собою називали авто-івентами. Стандартний даталеєр пуш при цьому мав наступний вигляд:

javascript
dataLayer.push({
  'event': 'autoEvent',
  'eventCategory': {{[dlv] eventCategory}},
  'eventAction': {{[dlv] eventAction}},
  'eventLabel': {{[dlv] eventLabel}}
});

де {{[dlv] eventCategory}}, {{[dlv] eventAction}}, {{[dlv] eventLabel}} - змінні в веб-ГТМі типу Data Layer Variable з відповідними ключами eventCategory, eventAction, eventLabel.

В доповнення до схеми також налаштовували тригер типу Custom Event зі спрацюванням по івенту з назвою autoEvent.

Фінальний акорд - сам тег типу Universal Analytics Event (точно вже не памʼятаю його назву, але не суть), де в поля event Category, event Action, event Label проставляли відповідні змінні {{eventCategory}}, {{eventAction}}, {{eventLabel}}. Далі - реліз нової версії контейнеру і на цьому налаштування зі сторони Таг Менеджеру можна було вважати завершеним.

І тепер, щоб зробити спрацювання цілі, скажімо, по кліку на кнопку підписки, ми мали би віддати розробнику невелике ТЗ на даталеєр пуш наступного виду:

javascript
dataLayer.push({
  'event': 'autoEvent',
  'eventCategory': 'button',
  'eventAction': 'click',
  'eventLabel': 'subscribe'
});

На виході мали дуже елегантне рішення, майже магічне, котре на початку трохи конфʼюзило по своїй концепції, але все ж працювало, як швейцарський годинник. Краса методу була якраз в тому, що для додавання ще одного івенту, все, що від нас очікувалося - віддати розробнику ТЗ на даталеєр пуш з новим набором параметрів eventCategory, eventAction, eventLabel в ньому.

Я не знаю точно, хто придумав цей метод, але, здається, це був Сімо Ахава власною персоною. Принаймні, вперше про концепцію авто-івентів я прочитав у нього на блозі. І називав він це Generic Event Tag. Така концепція налаштувань івентів (неважливо, як ви її називаєте), і стала стандартом індустрії на довгі роки, аж до приходу GA4.

Чому в ГА4 цей прийом (начебто) помер?

Стара аналітика мала фіксовану схему івенту: всього 4 параметра, категорія, дія, ярлик, значення. Чотири сталі характеристики хіту, завжди ті самі. Саме тому один тег в ГТМі міг обробити будь-яку комбінацію параметрів - мапити нема чого, бо всі слоти були сталими.

Хіти (івенти) в ГА4 в цьому відрізняються - сталих параметрів category, action, label, value тут нема. Є назва івенту і довільний набір параметрів з довільними назвами. І саме на цьому місці концепція авто-івентів розсипається, бо щоб тег відправив параметр, його руками треба задекларувати (дати йому назву).

Девід Вальєхо, відомий як Thyngster, розбираючи цю схему в проекції ГА4, формулює це прямо: цього не зробити в новій аналітиці, бо назви івент параметрів довільні і кожен з них доводиться мапити індивідуально залежно від того, який івент хочемо передати. Простіше: назву івенту передати в один спільний тег можна, а імена параметрів (відповідно, і значення) - ні.

Народження моєї ідеї

Чесно, я був дуже гордий за те, що сам придумав спосіб, як можна підігнати концепцію авто-івентів під реалії нової аналітики. Якщо в івенті нема фіксованих назв параметрів, то чому б нам не передавати такі собі пари ключ:значення на кожний параметр, котрим ми хочемо доповнити наш івент? Трошки покрутивши ідею в голові, я дійшов до наступного шаблонного даталеєр пуша:

javascript
dataLayer.push({
  event: "CE_*category*_*action*",
  pairs: [
    { ep_name: *PARAM_NAME_1*, ep_value: *PARAM_VALUE_1* },
    { ep_name: *PARAM_NAME_2*, ep_value: *PARAM_VALUE_2* },
,
    { ep_name: *PARAM_NAME_N*, ep_value: *PARAM_VALUE_N* }
  ]
});

Суть:

  • параметри йдуть масивом пар. Назва параметру (ep_name) плюс значення параметру (ep_value).
  • Назва івенту може змінюватись, але префікс CE_ має бути присутнім обовʼязково.
  • Все, що потрапляє в масив pairs - передається в аналітику. Якщо бажаєте передати якийсь параметр (наприклад, email), і не бажаєте, щоб він потрапив до аналітики - додавайте його на тому ж рівні, що і event та pairs.

Одразу про реєстр, поки не забули

Перш ніж йти по інструкції нижче, домовтеся про документ (реєстр), у якому будуть описані всі події і всі пари ep_name:ep_value до кожної. Раніше новий івент коштував час аналітика - і саме це відсіювало зайве. Тепер завести новий івент майже нічого не вартує. І тут важливо не наплодити зайвого, бо те, що безкоштовно на реалізацію, може розростися і швидко вийти з-під контролю.

Реєстр і є той фільтр, який ви ставите замість зниклої ціни. Далі розкажу, хто і коли до нього звертається, а без нього конструкція за кілька місяців перетворюється на смітник.

Як метод авто-івентів збирається в веб контейнері?

Отже, що нам знадобиться:

  1. 5 змінних типу Data Layer Variable для назв параметрів;
  2. 5 змінних типу Data Layer Variable для значень параметрів;
  3. Змінна типу Google Tag: Event Settings - як контейнер для решти змінних;
  4. Змінна типу Custom JavaScript для назви івенту;
  5. Тег типу GA4 Event з назвою [GA4] all autoEvents;
  6. Тег типу Custom HTML для чистки даталеєру;
  7. Тригер для тегу типу Custom Event.

Пару нюансів:

  • цифра 5 - умовна. Можна більше, можна менше. Це - максимальна кількість параметрів, котрі здатен обробити трюк по івенту. На своїй практиці я не бачив, щоб один івент мав більше за 7 кастомних параметрів (в додачу до стандартних).
  • пункти 3 та 4 - опціональні, вони більше про чистоту і охайність в контейнері, працювати може і без них. Далі я буду показувати з ними.

Отже, давайте збирати.

Всі необхідні змінні для авто-івентів

Створюємо послідовно 5 змінних для назв і 5 - для значень. В назві і в ключі кожної буде індекс від нуля до чотирьох. Імʼя змінної повторює ключ один в один - так їх не переплутати; під час копі-пастів раджу двічі перевіряти індекс, бо налаштування робиться один раз.

Отже створимо пару змінних з нульовим індексом:

Змінна pairs.0.ep_name типу Data Layer Variable: ключ у даталеєрі той самий, версія друга, значення за замовчуванням не задане.Змінна pairs.0.ep_name типу Data Layer Variable: ключ у даталеєрі той самий, версія друга, значення за замовчуванням не задане.

Решта девʼять робляться за образом і подобою: змінюється лише індекс та закінчення, ep_name або ep_value. На виході - 10 змінних.

Десять змінних даталеєра в контейнері GTM: від pairs.0.ep_name до pairs.4.ep_value, усі типу Data Layer Variable.Десять змінних даталеєра в контейнері GTM: від pairs.0.ep_name до pairs.4.ep_value, усі типу Data Layer Variable.

Далі створюємо змінну-контейнер для наших пар, тип Google Tag: Event Settings. Назвемо [ev.config] autoEvent Dynamic Parameters.

Змінна autoEvent Dynamic Parameters: пʼять рядків, де ліворуч стоїть змінна з імʼям параметра, а праворуч - змінна з його значенням.Змінна autoEvent Dynamic Parameters: пʼять рядків, де ліворуч стоїть змінна з імʼям параметра, а праворуч - змінна з його значенням.

Зверніть увагу на головне: у лівому стовпці стоїть не стале імʼя параметра, а ЗМІННА в фігурних дужках.

Остання змінна, що нам потрібна - {{[c.js] autoEvent name without prefix}}. Тип - Custom JavaScript Variable:

javascript
function() {
  var evt = {{Event}};
  return evt.indexOf('CE_') === 0 ? evt.slice(3) : evt;
}

На вхід бере назву івенту і, якщо він починається з CE_, то повертає варіант без префіксу. Ця часточка нам потрібна як сигнатура для тих івентів, котрі варто обробляти в нашій схемі. Далі від неї можна здихатись, що ми останньою змінною і робимо.

Було CE_button_click, стало button_click. Було CE_form_submit, стало form_submit. І так далі.

Отже, префікс залишається в даталеєр пушах і в тригері, а в аналітику йде чисте імʼя івенту. На цьому етапі зі змінними ми покінчили, залишилося трохи - тригер і два теги.

Тригер для тегу авто-івентів

Створюємо тригер типу Custom Event, називаємо його, наприклад, [c.event] all autoEvents.

В Event name прописуємо ^CE_, ставимо галочку «Use regex matching», зберігаємо.

Тег авто-івентів і тег-очищувач

Створюємо тег типу GA4 Event, назвемо [GA4] all autoEvents.

  • Measurement ID - підставляємо свій;
  • Event Name - {{[c.js] autoEvent name without prefix}};
  • Event Parameters -> Event Settings Variable - {{[ev.config] autoEvent Dynamic Parameters}};
  • Tag firing priority - 1 або будь-яке значення більше за нуль

В якості тригеру обираємо створений нами [c.event] all autoEvents.

Тег GA4 Event для авто-івентів: імʼя події береться зі змінної без префікса, параметри - зі змінної налаштувань, пріоритет спрацювання 1.Тег GA4 Event для авто-івентів: імʼя події береться зі змінної без префікса, параметри - зі змінної налаштувань, пріоритет спрацювання 1.

Окремо про пріоритет, бо тут важливо. Більший пріоритет спрацьовує раніше, а в тега-очищувача він за замовчуванням нульовий. Саме це гарантує, що подія поїде ДО того, як масив почистять. Без пріоритету порядок не визначений.

Останній ривок - тег-очищувач.

Створюємо тег типу Custom HTML, назвемо [c. HTML] clearfix after all autoEvents. Вставляємо код:

html
<script>
(function () {
  dataLayer.push({ event: "pairs values clearfix", pairs: undefined });
})();
</script>

В якості тригеру обираємо той самий [c.event] all autoEvents.

Тег Custom HTML, який чистить масив pairs після кожної події: пуш pairs values clearfix зі значенням undefined.Тег Custom HTML, який чистить масив pairs після кожної події: пуш pairs values clearfix зі значенням undefined.

Пару слів про цей, так би мовити, тег-очищувач.

  1. Модель даних даталеєра накопичувальна. Це головне, і саме тому в схемі є тег-очищувач. Якщо в наступному пуші пар менше, ніж у попередньому, тег візьме хвости старого: подія отримає параметр, якого в ній не було. Сімо радив на цей випадок передавати undefined у невикористані поля; я зробив інакше - окремим тегом, який чистить масив після кожної події.
  2. Позиції в масиві важливі. Третій параметр однієї події і третій параметр іншої - різні речі. Саме тому очищувач не опція, а частина конструкції.

На цьому все з налаштуваннями. Якщо ви йшли покроково зі мною, то на виході маєте ось такі зміни.

Список змін у контейнері GTM: два теги, один тригер і дванадцять змінних, навпроти кожного рядка стоїть Added.Список змін у контейнері GTM: два теги, один тригер і дванадцять змінних, навпроти кожного рядка стоїть Added.

Перевіряємо

Відкриваємо превʼю мод, відкриваємо консоль сайту. Робимо тестові івенти, щось зрозуміле і осмислене:

javascript
dataLayer.push({
  event: "CE_button_click",
  pairs: [
    { ep_name: "element_name", ep_value: "subscribe" },
    { ep_name: "variant",      ep_value: "A" }
  ]
});
javascript
dataLayer.push({
  event: "CE_form_submit",
  pairs: [
    { ep_name: "element_name", ep_value: "subscription" },
    { ep_name: "placement",    ep_value: "footer" }
  ]
});

Вставляємо по черзі в консоль. Що ми очікуємо?

  1. При даталеєр пуші автоматично відправляються івенти в ГА4;
  2. При цьому назви параметрів і їх значення також проставлені автоматично;
  3. Івент в даталеєрі має префікс CE_, на виході в аналітику префікса вже нема.

І ось як це виглядає:

Консоль браузера: пуш CE_button_click з парами імʼя-значення, за ним чистка масиву, і подія button_click уже без префікса.Консоль браузера: пуш CE_button_click з парами імʼя-значення, за ним чистка масиву, і подія button_click уже без префікса.

А ось як те саме виглядає в превʼю моді ГТМу - назви і значення параметрів на місцях у відповідних змінних.

Відладчик GA4 показує подію button_click з параметрами element_name і variant - саме тими іменами, що прийшли з даталеєра.Відладчик GA4 показує подію button_click з параметрами element_name і variant - саме тими іменами, що прийшли з даталеєра.

Відладчик GA4 показує подію form_submit з параметрами element_name і placement, отриманими з даталеєра.Відладчик GA4 показує подію form_submit з параметрами element_name і placement, отриманими з даталеєра.

Якщо вас цікавили саме події для ГА4, то на цьому можна закривати превʼю мод ГТМу і релізити нову версію контейнеру. Проте схожу оптимізацію (але дещо іншу) можна провести і для тегів рекламних конверсій.

Чи варто це робити конкретно в вашому проекті? Якщо ви заводите конверсії в рекламних кабінетах у відповідності один до одного до івентів аналітики - так. Але тут ви маєте оцінювати трейд-офи: гнучкість налаштувань проти компактності + охайності в інтерфейсі ГТМу.

Як оптимізувати кількість рекламних тегів

Розглянемо на прикладі конверсій Google Ads.

Що знадобиться:

  1. Змінна типу Custom JavaScript - так званий каталог конверсій;
  2. Тригер типу Custom Event, майже аналог ранішнього, але цей буде фаєрити саме теги Google Ads;
  3. Тег типу Google Ads Conversion Tracking.

З інтерфейсу Гугл Едсу нам потрібні conversion label, котрі відповідають конверсіям, які ми хочемо запускати через тег авто-конверсій.

Далі створюємо змінну типу Custom JavaScript, називаємо, наприклад, [c. js] Google Ads conversions list, і задаємо відповідність, на який CE_ івент має спрацьовувати яка конверсія:

javascript
function() {
    var evt = {{Event}};
    switch (evt) {
        case "CE_leadform_submit":   return "CONVERSION_LABEL_1";
        case "CE_leadform_click":    return "CONVERSION_LABEL_2";
        case "CE_docs_click":        return "CONVERSION_LABEL_3";
        case "CE_freeTrial_click":   return "CONVERSION_LABEL_4";
        default:                     return undefined;
    }
}

Змінна Google Ads conversions list: switch зіставляє чотири події CE_ з ярликами конверсій, решті повертає undefined.Змінна Google Ads conversions list: switch зіставляє чотири події CE_ з ярликами конверсій, решті повертає undefined.

Фолбек у вигляді undefined - не просто так. У нас може бути 10 CE_ івентів, але конверсій - лише 4. Якщо для події конверсії не знайшлося, тег мовчить.

Тепер створимо тригер типу Custom Event, назвемо [c.event] Google Ads all autoConversions:

  • Event Name - ^CE_;
  • Use regex matching - ставимо галочку;
  • This trigger fires on - {{[c. js] Google Ads conversions list}} does not match RegEx ^$.

Тригер Custom Event для авто-конверсій: імʼя за регуляркою ^CE_, спрацьовує лише коли для події знайдено ярлик конверсії.Тригер Custom Event для авто-конверсій: імʼя за регуляркою ^CE_, спрацьовує лише коли для події знайдено ярлик конверсії.

Останнє якраз відповідає undefined значенню і буде блокувати спрацювання тегу у випадку, якщо в змінній {{[c. js] Google Ads conversions list}} не буде повертатись конкретний ярлик конверсії.

Далі створюємо тег типу Google Ads Conversion Tracking.

  • Conversion ID берете з інтерфейсу;
  • Conversion Label - {{[c. js] Google Ads conversions list}};
  • Event Parameters -> Event Settings Variable -> {{[ev.config] autoEvent Dynamic Parameters}};
  • Tag firing priority - 1 або будь-яке значення більше за нуль

В якості тригеру беремо [c.event] Google Ads all autoConversions.

Тег Google Ads Conversion Tracking: ярлик конверсії береться зі змінної, параметри - зі змінної налаштувань, пріоритет 1.Тег Google Ads Conversion Tracking: ярлик конверсії береться зі змінної, параметри - зі змінної налаштувань, пріоритет 1.

В принципі, це все.

Одне питання хочу закрити: чому ми створили окремий тригер для спрацювання тегу авто-конверсій, а не використали той, котрий робили для авто-івентів?

Все просто - шо занадто, то нездраво.

Тут головне не переоптимізувати і залишатися при здоровому глузді, балансуючи на межі зручності, компактності і, що точно не менш важливо, функціональності.

Заради чого все це

Коли конструкція стоїть, робота аналітика з новими подіями зводиться до видачі шаблону даталеєр пуша. Приходить стейкхолдер: «треба відстежувати он ту кнопку». Ви не йдете в GTM. Ви даєте бланк:

javascript
dataLayer.push({
  event: "CE_<обʼєкт>_<дія>",
  pairs: [
    { ep_name: "<імʼя параметра>", ep_value: <значення> }
  ]
});

І три правила до нього:

  1. Імʼя події - CE_, потім обʼєкт, потім дія. Спершу те, чого торкнулися, потім що сталося.
  2. Параметрів не більше, ніж заведено пар.
  3. Імена параметрів - шукаються в реєстрі (щоб не плодити подібні)

Далі стейкхолдер пише ТЗ (або заносить в реєстр івент новим рядком, а ви пишете ТЗ), розробник викочує в прод, подія починає збиратися сама. І тут вас чекає найдивніше відчуття: так просто? Нуль ваших зусиль, але ви бачите, як нові івенти ідеально починають збиратися в аналітиці. І жодного релізу в ГТМі.

Ціна методу

Параметри, включно з їхніми назвами, стали гнучкими. Решта тега - навпаки.

Бо в тегу крім таблиці параметрів є ще купа налаштувань, і тепер вони спільні на всі події одразу: ідентифікатор ресурсу один на всіх, налаштування згоди одні на всіх, правило спрацювання одне на всіх.

Раніше ви платили часом. Тепер платите гнучкістю.

Ось як це відчувається на практиці. Щоб вимкнути одну подію в одному конкретному випадку, доводиться писати блокувальний тригер із кількох умов і вішати його на спільний тег. У світі «тег на подію» це було б одне натискання «призупинити».

Це не поразка методу. Тег авто-івентів - для всього однотипного; а те, що має особливі налаштування, виноситься окремим тегом. Головне - не захопитися. Якщо окремих тегів набралося більше, ніж CE_ подій, схема перестала економити.

Відповідальність - на вас

Про реєстр ми домовилися на початку. І власник реєстру - аналітик.

За те, що збирає ГА4, також відповідає аналітик. Не розробник, не стейкхолдер, не той, хто написав ТЗ. Коли через півроку хтось спитає, чому в звіті по івентах повна каша, питати будуть не розробника, а аналітика. І тут виходить незручна річ: гарантувати можна тільки те, що контролюєш. Роздавши можливість заводити події всім в компанії, фінальне слово, валідація і перевірка все одно мають бути на аналітику.

Сенс методу, що я описав у статті, в тому, щоб зменшити кількість рутинних задач, повʼязаних з GTM, а не прибрати контроль. Даталеєр пуш - це код, а код їде через пул-реквест розробника. Непогана практика - ставити ревʼювером пул-реквесту саме аналітика. Справ на три хвилини - перевірити елементи даталеєр пушу у відповідність до реєстру ваших івентів.

Що в підсумку

Найлегша частина цієї історії - власне тег. Його наклацати в інтерфейсі ГТМу - двадцять хвилин. Реально важче вловити суть. Найскладніше і найцінніше - домовленість (реєстр івентів) і налагоджений процес. Що спочатку івент і його схема фіксується в табличці, а потім - в коді сайту.

Імплементувати подібний метод, не замкнувши процес на собі - мати замусорену аналітику, дублюючі по сенсу параметри (transaction_id/order_id, value/price) і криві назви івентів без жодної логіки в них.

В будь-якому випадку це лише +1 інструмент в вашому арсеналі і не варто впадати в крайності - вам ніхто не забороняє паралельно з імплементованим методом авто-івентів заводити окремі івенти так, як ви робили раніше (наприклад, для набору івентів ecommerce). Не переоптимізовуйте. Якщо відчуваєте, що падає гнучкість налаштувань - відкатуйтесь назад. Функціональністю жертвувати точно не варто.

Напишіть - все прочитаю і всім відповім.

Або просто напишіть на hello@ozthewizard.com