Gtm

dataLayer: как работает и как использовать

dataLayer — глобальный массив между сайтом и GTM. Как устроен, как правильно пушить события, читать значения через переменные и избегать типичных ошибок.

Автор: Андрій Коваленко 9 мин чтения
Содержание

dataLayer — глобальный JavaScript-массив на странице, через который сайт передаёт структурированные данные в Google Tag Manager. GTM слушает этот массив и, когда видит нужное событие, активирует теги. Без dataLayer трекинг опирается на хрупкий DOM — изменили класс кнопки и всё сломалось.

Эта статья — практический разбор: как устроен dataLayer, как правильно пушить события, как читать значения в GTM, реальные примеры для e-commerce и кастомных user properties, порядок инициализации и типичные ошибки.

Материал является продолжением основ GTM — если вы ещё не разобрались с тегами и триггерами, сначала прочитайте тот посибник.

Что такое dataLayer и зачем он нужен

GTM может извлекать данные двумя способами: из DOM (класс элемента, текст кнопки, значение поля) или из dataLayer. DOM-подход ненадёжен: любой редизайн ломает трекинг. dataLayer — это контракт между командами разработки и аналитики: разработчик пушит чётко описанные объекты, аналитик читает их через GTM независимо от вёрстки.

Смотрите разницу на примере трекинга клика «Купить»:

ПодходНастройкаЧто случится при редизайне
DOM (Click trigger на CSS класс)Trigger: .btn-buyРазработчик переименовал класс — трекинг молчит
dataLayer.pushevent: 'add_to_cart' в onClickКнопка изменила вид — push остался, всё ок

Отдельный плюс: через DOM никогда не получишь данные, которых нет на странице — цену из бекенда, ID авторизованного пользователя, статус заказа. dataLayer позволяет передать всё это из серверного шаблона или клиентского JS.

Если хотите разобраться в термине подробнее — смотрите glossary: dataLayer.

Структура dataLayer

window.dataLayer — обычный массив JavaScript. Каждый элемент — объект с произвольными ключами и обязательным полем event (если хотите тригернуть GTM).

window.dataLayer = [
  // Объект 0 — контекст страницы (без event, просто данные)
  {
    pageType: "product",
    pageLanguage: "ru",
    userId: "u_8821"
  },
  // Объект 1 — событие при загрузке
  {
    event: "page_view_ready",
    pageTitle: "Кроссовки Nike Air Max"
  }
];

GTM при старте обрабатывает весь массив сверху вниз. Если находит объект с полем event — проверяет Custom Event триггеры с таким именем. Если объект без event — просто обновляет внутреннее состояние переменных.

Ключевые поля

  • event (string) — имя события, которое GTM будет матчить по Custom Event триггерам. Называйте snake_case: add_to_cart, form_submit, video_play.
  • Любые другие поля — это параметры события, которые вы читаете через Data Layer Variable.

Инициализация dataLayer: порядок важен

Одна из самых распространённых ошибок — неправильный порядок скриптов. Правило простое: dataLayer должен быть объявлен до сниппета GTM.

Структура <head> должна выглядеть так:

<head>
  <!-- 1. Сначала инициализация dataLayer и первый push -->
  <script>
    window.dataLayer = window.dataLayer || [];
    // Контекст страницы, известный в момент рендера (серверные данные)
    window.dataLayer.push({
      pageType: "product",
      userId: "u_8821",        // если есть авторизованный пользователь
      userType: "returning"
    });
  </script>

  <!-- 2. Потом сниппет GTM -->
  <script>
    (function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
    new Date().getTime(),event:'gtm.js'});...
  </script>
</head>

Почему window.dataLayer = window.dataLayer || []? Защита от двойной загрузки фрагмента (SPA-навигация, ошибки сборки). Если просто window.dataLayer = [] — вы каждый раз стираете накопленные данные.

Если контекст страницы придёт после GTM, он всё равно попадёт в массив, но GTM уже обработает первый Page View без этих данных. Тегам, привязанным к pageview, эти переменные будут недоступны.

dataLayer.push: как правильно отправлять события

dataLayer.push(obj) — основной метод. Вызывайте его в любой момент после инициализации:

// При клике на кнопку (ваш JS)
document.querySelector('#btn-add-to-cart').addEventListener('click', function() {
  dataLayer.push({
    event: 'add_to_cart',
    ecommerce: {
      currency: 'RUB',
      value: 4990,
      items: [{
        item_id: 'SKU_1234',
        item_name: 'Кроссовки Nike Air Max',
        item_category: 'Обувь',
        price: 4990,
        quantity: 1
      }]
    }
  });
});

GTM получает этот push, находит Custom Event триггер с именем add_to_cart, активирует GA4 Event тег — и событие летит в аналитику.

Важный нюанс: очистка ecommerce

Google требует очищать предыдущий ecommerce-объект перед каждым новым пушем. Если вы пушите add_to_cart после view_item, GTM смержит оба объекта — и во втором событии появятся поля первого.

Правило: перед любым ecommerce-пушем всегда делайте:

dataLayer.push({ ecommerce: null }); // очистить предыдущее состояние
dataLayer.push({
  event: 'add_to_cart',
  ecommerce: { ... }
});

Это официальная рекомендация Google в документации GA4 ecommerce (Make ecommerce measurements with Tag Manager).

Чтение dataLayer в GTM через Data Layer Variable

Чтобы использовать значение из dataLayer в тегах или триггерах — создайте переменную типа Data Layer Variable.

Путь: Variables → User-Defined Variables → New → Variable Type → Data Layer Variable.

Базовые настройки

  • Variable Name — ключ или путь к вложенному значению через точку.
  • Data Layer Version — всегда версия 2 (по умолчанию). Версия 1 — legacy, не поддерживает пути через точку (например, ecommerce.value).

Примеры Variable Name для разных структур:

Простая пара ключ-значение:
  Variable Name: pageType
  Значение из push: { pageType: "product" } → вернёт "product"

Вложенный объект (через точку):
  Variable Name: ecommerce.value
  Значение из push: { ecommerce: { value: 4990 } } → вернёт 4990

Первый элемент массива:
  Variable Name: ecommerce.items.0.item_name
  Значение из push: { ecommerce: { items: [{ item_name: "Кроссовки" }] } } → "Кроссовки"

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

После создания переменной её можно использовать в GA4 Event Tag как параметр:

Tag: GA4 Event
Event Name: add_to_cart
Event Parameters:
  currency → {{DL - ecommerce.currency}}
  value    → {{DL - ecommerce.value}}
  items    → {{DL - ecommerce.items}}

Префикс DL - в названии — рекомендованная конвенция для удобства чтения в GTM.

Примеры: ecommerce events для GA4

Ниже — полные примеры пушей для основных ecommerce-событий GA4. Структура items[] стандартизирована Google.

view_item — просмотр карточки товара

dataLayer.push({ ecommerce: null });
dataLayer.push({
  event: 'view_item',
  ecommerce: {
    currency: 'RUB',
    value: 4990,
    items: [{
      item_id: 'SKU_1234',
      item_name: 'Кроссовки Nike Air Max',
      item_brand: 'Nike',
      item_category: 'Обувь',
      item_category2: 'Кроссовки',
      price: 4990,
      quantity: 1
    }]
  }
});

purchase — завершение покупки

Обычно отправляется на thank-you-page, где бекенд уже знает детали заказа:

dataLayer.push({ ecommerce: null });
dataLayer.push({
  event: 'purchase',
  ecommerce: {
    transaction_id: 'ORDER_88210',  // обязательно, уникальный
    currency: 'RUB',
    value: 9980,                    // без доставки и налогов
    shipping: 290,
    tax: 0,
    coupon: 'SALE10',               // если применялся
    items: [
      {
        item_id: 'SKU_1234',
        item_name: 'Кроссовки Nike Air Max',
        price: 4990,
        quantity: 2
      }
    ]
  }
});

Важно: transaction_id должен быть уникальным. GA4 дедуплицирует повторные отправки по transaction_id — дубликаты purchase с одним ID игнорируются.

begin_checkout — начало оформления заказа

dataLayer.push({ ecommerce: null });
dataLayer.push({
  event: 'begin_checkout',
  ecommerce: {
    currency: 'RUB',
    value: 9980,
    items: [
      { item_id: 'SKU_1234', item_name: 'Кроссовки Nike Air Max', price: 4990, quantity: 2 }
    ]
  }
});

Примеры: user properties через dataLayer

Помимо ecommerce, dataLayer — удобный канал для передачи атрибутов пользователя, которые нужны в GTM для сегментации или персонализации.

Обычно эти данные устанавливаются при загрузке страницы — если есть авторизация:

// Серверный шаблон (PHP, Python и т.д.) рендерит это в <head>
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
  userId: "u_8821",             // не Email и не PII, только хешированный/внутренний ID
  userType: "returning",        // new / returning
  userPlan: "pro",              // free / pro / enterprise
  userCountry: "RU"
});

В GTM создайте Data Layer Variables: userId, userType, userPlan. Затем используйте их в GA4 Configuration Tag → User Properties:

user_id    → {{DL - userId}}
user_type  → {{DL - userType}}
plan       → {{DL - userPlan}}

Важно про PII: не передавайте Email, имя, телефон через dataLayer напрямую — это нарушает условия Google Analytics и GDPR. Только анонимизированные ID или категориальные атрибуты.

Как отлаживать dataLayer в Preview Mode

GTM Preview Mode — главный инструмент проверки. Откройте Preview, выполните нужное действие на сайте, затем в Tag Assistant:

  1. Выберите событие слева (например, add_to_cart).
  2. Вкладка Variables — показывает значения всех Data Layer Variables на момент события.
  3. Вкладка Data Layer — показывает полное состояние массива после каждого пуша.
  4. Вкладка Tags — показывает какие теги сработали или нет.

Если в Variables видите undefined — значение либо не пришло, либо путь написан неправильно.

Также удобно прямо в консоли браузера просмотреть текущее состояние:

// Показать весь массив
console.log(window.dataLayer);

// Показать последний push
console.log(window.dataLayer[window.dataLayer.length - 1]);

Типичные ошибки при работе с dataLayer

1. Инициализация после сниппета GTM

GTM стартовал, запустил первый Page View — а dataLayer с контекстом ещё не пришёл. Исправление: всегда window.dataLayer = window.dataLayer || [] и первый push до GTM сниппета.

2. Нет очистки ecommerce перед пушем

Без dataLayer.push({ ecommerce: null }) поля от предыдущего события остаются в состоянии. В purchase появятся items от view_item. Делайте очистку перед каждым ecommerce пушем.

3. Ошибка в названии ключа или регистре

GTM чувствителен к регистру: UserID и userId — разные ключи. Проверяйте Variable Name с точностью до символа.

4. Версия Data Layer Variable = 1

В GTM при создании Data Layer Variable есть выбор Version 1 или 2. Версия 1 — устаревшая, не поддерживает пути через точку (например, ecommerce.value). Всегда выбирайте версию 2.

5. Двойная отправка событий

Происходит при SPA-навигации (React, Vue): при переходах между страницами компонент может рендериться дважды или push вызывается из useEffect с некорректными зависимостями. Смотрите GA4 DebugView — если событие приходит дважды подряд с разницей <1с — это оно.

6. Передача PII

Email или телефон в dataLayer → в GA4 → в Google — прямое нарушение условий обслуживания и GDPR. Вместо email — SHA-256 хеш или внутренний CRM-ID.

7. Push до того, как страница загрузила JS-файл с логикой

В SPA при client-side навигации код компонента может запустить dataLayer.push до того, как GTM загрузил текущий контейнер (если используете lazy route). Решение — проверять window.google_tag_manager или использовать window.dataLayer.push с eventCallback.

8. Ненадёжные имена событий

Названия типа buttonClick, formsubmit, AddToCart (camelCase или без правил) усложняют поддержку. Стандарт GA4 — snake_case, в нижнем регистре: form_submit, add_to_cart, video_start. Придерживайтесь этого с первого дня.

Как связаны dataLayer, GTM и GA4

Для лучшего понимания — общая схема потока данных:

Действие пользователя (клик/переход/покупка)
       ↓
dataLayer.push({ event: 'purchase', ecommerce: {...} })
       ↓
GTM слышит новое событие в массиве
       ↓
GTM находит Custom Event триггер "purchase"
       ↓
GTM активирует GA4 Event тег
       ↓
Тег читает параметры из Data Layer Variables:
  {{DL - ecommerce.value}} → 9980
  {{DL - ecommerce.items}} → [...]
       ↓
GA4 получает событие purchase с параметрами

dataLayer — посредник. Сайт не знает, что существует GA4 или GTM; GTM не знает, что произошло на сайте. dataLayer — нейтральный протокол между ними. Если завтра вы меняете GA4 на Matomo или добавляете Meta Pixel — просто подключаете новый тег в GTM, пуши сайта не меняются.

Подробнее о событиях в аналитике — в глоссарии.

Контрольный список перед публикацией новых пушей

Перед тем как мёрджить код с новыми dataLayer пушами, пройдитесь по чек-листу:

  • window.dataLayer = window.dataLayer || [] стоит до сниппета GTM.
  • Перед ecommerce пушем есть dataLayer.push({ ecommerce: null }).
  • event назван в snake_case.
  • Вложенные поля (ecommerce.currency, ecommerce.value) соответствуют GA4-схеме.
  • Никаких PII в открытом виде.
  • Проверено в GTM Preview Mode — нужные теги сработали.
  • Проверено в GA4 DebugView — событие появилось с правильными параметрами.
  • Отсутствуют дубликаты (особенно для SPA).

Связанные материалы

Эту статью пишет и обновляет Андрій Коваленко — без AI-воды и партнёрских ссылок. Заметил устаревший факт или неточность — напиши, перепишу в ту же неделю.

Кто ведёт сайт и почему без AI