12
0
0
Скопировать ссылку
Telegram
WhatsApp
Vkontakte
Одноклассники
Назад

Что такое dataLayer на самом деле: от аналитиков — разработчикам

Время чтения 16 минут
Нет времени читать?
Скопировать ссылку
Telegram
WhatsApp
Vkontakte
Одноклассники
12
0
0
Нет времени читать?
Скопировать ссылку
Telegram
WhatsApp
Vkontakte
Одноклассники

Если спросить разработчика, что такое dataLayer, чаще всего ответ будет примерно такой: «Ну это что-то из GTM». А если спросить аналитика, что нужно для настройки событий, ответ будет: «Нужно просто пушнуть это в dataLayer». Здесь начинается мистика и легкое раздражение с обеих сторон. Разработчику кажется, что это часть Google Tag Manager, которую он не обязан понимать. Аналитику кажется, что это очевидная вещь уровня «объявить переменную». В итоге dataLayer превращается в некий черный ящик, за который отвечает «кто-то другой».

Спойлер: никто.

На связи Влад Лукашенко, я руководитель отдела SEO и веб-аналитики компании «Тензор» (разработчик платформы saby.ru). И в этой статье я подробно разберу на составляющие этот черный ящик.

Что такое dataLayer на самом деле: от аналитиков — разработчикам

Главная мысль этой статьи простая и приземленная: dataLayer — это просто глобальная переменная в window. Всё остальное — это работа разработчика по задачам аналитика и последующий тюнинг аналитиком в тег-менеджере.

Никакой привязки к конкретному инструменту. Это не «функция GTM». Это не «фича аналитиков». Это часть фронтенда. Я пишу это как аналитик, который слишком много раз слышал что-то подобное: «Мы не можем, это же GTM».

Можем. Потому что это — JavaScript. И только потом — аналитика.

Глобальная переменная в браузере

Начнем с базы. В браузере есть глобальный объект window. Всё, что объявлено на верхнем уровне, по сути, становится его свойством.

Когда мы пишем:


<script>
  window.dataLayer = window.dataLayer || [];
</script>

 

мы не делаем ничего сложного. Мы просто говорим:

  • если dataLayer уже существует — используй его;
  • если нет — создай новый пустой массив.

Это обычная инициализация. dataLayer — это массив, он живет внутри window. Он доступен любому скрипту на странице, фреймворку, самописному JS, стороннему виджету или тег-менеджеру. 

Глобальная область видимости означает, что переменная существует в рамках всей страницы, а не внутри функции или модуля. Пока страница открыта, она доступна. Почему это важно объявлять до загрузки тег-менеджера? Потому что менеджер при инициализации «подписывается» на этот массив. Если переменная появится позже или будет перезаписана, он просто не увидит часть данных.

Еще раз важный архитектурный момент: тег-менеджер не создает dataLayer как концепцию. Он лишь использует уже существующую глобальную переменную как точку входа. По сути, это контракт между фронтом и аналитикой. Фронт кладет данные в массив. Инструмент их читает. Остальное — детали реализации.

Почему это массив, а не объект

Логичный вопрос разработчика: почему вообще массив? Почему не обычный объект вида window.dataLayer = {}? Ответ уходит корнями в историю появления Google Tag Manager. Изначально dataLayer задумывался как очередь команд, примерно так же, как раньше работали асинхронные трекеры аналитики. Скрипт еще не загрузился, а данные уже можно «складывать в очередь». Когда инструмент инициализируется, он проходит по накопленным элементам и обрабатывает их. Массив идеально подходит для такой модели: он хранит последовательность действий, сохраняет порядок событий, позволяет добавлять новые элементы через .push(). Объект бы постоянно перезаписывался. Массив же накапливает историю.

Когда вы пишете:


dataLayer.push({
  event: 'add_to_cart',
  ecommerce: {
    value: 1990,
    currency: 'RUB'
  }
});

 

происходит очень простая вещь. .push() добавляет объект в конец массива. Тег-менеджер, который уже «подписался» на этот массив, перехватывает этот вызов. Каждый пуш для него — это сигнал «появилось новое событие, проверь триггеры».

Это и есть событийная модель. Мы не меняем состояние глобального объекта. Мы генерируем последовательность событий. Каждое событие — атомарное действие, которое можно обработать независимо.

С точки зрения архитектуры это намного чище:

  • нет гонок из-за перезаписи значений;
  • сохраняется порядок событий;
  • можно обрабатывать данные, даже если они были добавлены до загрузки менеджера.

По сути, dataLayer — это примитивная event queue на глобальном уровне страницы.

Как тег-менеджеры используют dataLayer

Все популярные тег-менеджеры используют одну и ту же модель. Отличается интерфейс, но не принцип.

dataLayer в Google Tag Manager

В Google Tag Manager при загрузке происходит интересная вещь: он «перехватывает» массив. Если упростить, GTM подменяет метод .push() своей оберткой. Снаружи это всё тот же массив, а внутри уже логика обработки. Типичный код подключения выглядит так:


<script>
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({ 'gtm.start': new Date().getTime(), event: 'gtm.js' });
</script>

 

Что здесь происходит? event — это триггер. Все остальные параметры — это данные, которые станут переменными внутри GTM.

Когда выполняется пуш, GTM:

  1. Получает объект.
  2. Проверяет, есть ли триггер на событие (event).
  3. Если условие выполнено — запускает связанные теги.

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

Data Layer в Яндекс Тег Менеджере

Здесь используется та же модель. По умолчанию имя переменной — dataLayer, но его можно изменить в настройках контейнера. Это по-прежнему глобальная переменная в window. Событийная логика аналогична GTM: есть событие (event), есть данные, есть триггеры.

Пример:


dataLayer.push({
  event: 'form_submit',
  form_id: 'lead_form'
});

 

Дальше менеджер:

  1. Слушает вызовы .push().
  2. Проверяет условия триггеров.
  3. Передает значения в теги.

Отличия касаются интерфейса: как создаются переменные, как настраиваются триггеры, как устроена отладка. Фундамент остается прежним: глобальный массив + пуш + обработчик событий. Менеджеры разные — модель одна.

Data Layer в Matomo Tag Manager

В Matomo Tag Manager переменная называется иначе — window._mtm. Но технически это то же самое.


window._mtm = window._mtm || [];
window._mtm.push({
  event: 'purchase',
  revenue: 2990
});

 

Это массив, и он лежит в window. Он так же работает через .push(). Когда загружается Matomo Tag Manager, он так же перехватывает метод .push() и начинает обрабатывать каждое добавленное событие. Название отличается, архитектура — нет.

Жизненный цикл dataLayer

Создание

Инициализация должна происходить раньше любого подключения контейнера. Причина простая: менеджер при старте читает текущее состояние массива и затем «подписывается» на его изменения. Если переменная появится позже, часть данных будет потеряна.

Типичный корректный порядок:

  1. Инициализация window.dataLayer.
  2. Возможные ранние пуши (например, конфигурационные события).
  3. Подключение контейнера.
  4. Дальнейшие события приложения.

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

Типичная ошибка выглядит так: сначала подключают тег-менеджер, потом где-то ниже объявляют window.dataLayer = [];.

В этот момент происходит перезапись переменной. Если менеджер уже успел обернуть .push(), вы уничтожаете его обертку и создаете новый «чистый» массив. Визуально всё работает. Фактически события больше не обрабатываются.

Вторая распространенная проблема — повторная инициализация:

window.dataLayer = [];

Без проверки существования. Это сбрасывает всю накопленную очередь. Именно поэтому базовая конструкция window.dataLayer = window.dataLayer || []; — не просто шаблон, а защита от архитектурной ошибки.

Добавление элементов

Когда вызывается:

dataLayer.push({ event: ‘add_to_cart’ });

происходит несколько шагов. Сначала в массив добавляется объект. Это обычное поведение JavaScript. Затем срабатывает перехваченная функция .push(). Менеджер подменяет стандартный метод своей оберткой. Внутри нее:

  1. Данные добавляются в массив.
  2. Менеджер получает уведомление о новом элементе.
  3. Запускается механизм проверки триггеров.

Дальше система проходит по списку условий. Если есть триггер на event = add_to_cart, соответствующие теги выполняются. С точки зрения браузера всё это укладывается в обычную модель event loop. push() — синхронная операция. Она выполняется в текущем call stack. После завершения вызова управление возвращается основному потоку. Если внутри менеджера есть асинхронные операции (загрузка скриптов, отправка запросов), они уже ставятся в очередь задач. Важно понимать: push() — это не «отправка данных в аналитику», это генерация события внутри страницы.

Архитектурный подход к работе с dataLayer

Если относиться к dataLayer как к «месту, куда можно что-нибудь положить», очень быстро получится хаос. События будут называться по-разному. Структуры будут отличаться от страницы к странице. Поля начнут менять формат в зависимости от настроения разработчика. В этот момент аналитика становится нестабильной системой. dataLayer — это интерфейс. А любой интерфейс требует спецификации.

Именно поэтому появляется понятие Data Layer Specification — документа, который описывает правила взаимодействия. В него обычно входит:

  • перечень событий и их назначение;
  • структура e-commerce блоков;
  • обязательные поля для каждого события;
  • форматы данных (строка, число, ISO-дата, boolean и т. д.);
  • правила именования.

Это уже контракт. Фронтенд обязуется отправлять данные в определенном формате. Аналитика обязуется корректно их обрабатывать. Когда спецификация есть, подключение любого тег-менеджера — вопрос техники. Если же спецификации нет, каждый релиз превращается в ручную отладку.

Антипаттерны 

Есть несколько типичных архитектурных ошибок:

  • Перезапись dataLayer = {} уничтожает очередь и ломает обработку событий. Использование объекта вместо массива убивает событийную модель. Вы теряете последовательность действий и начинаете перезаписывать состояние. 
  • Пуш без event — менеджеру не за что зацепиться. Без явного триггера вы создаете данные, но не событие.
  • Дубли e-commerce — повторная отправка одного и того же блока в разных событиях без контроля приводит к некорректной аналитике и задвоению транзакций.
  • Динамическое переопределение переменной — изменение имени dataLayer или _mtm после загрузки контейнера фактически отключает связь между страницей и менеджером.

Все эти ошибки происходят по одной причине: к dataLayer относятся как к «технической детали». На практике это точка интеграции. И к ней стоит относиться как к публичному API внутри фронтенд-архитектуры.

Практические кейсы

Передача данных о пользователе

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

Базовый пример выглядит так:


dataLayer.push({
  event: 'user_ready',
  user: {
    id: '12345',
    role: 'client'
  }
});

 

Технически это обычное событие. Есть event, есть объект user с набором свойств. Менеджер получает событие, переменные становятся доступными в тегах.

Когда так можно делать?

Когда передаются обезличенные данные: внутренний ID, сегмент, роль, тип клиента, статус авторизации. То есть то, что не позволяет напрямую идентифицировать человека вне вашей системы.

Когда так делать нельзя?

Когда в dataLayer начинают попадать email, телефон, Ф. И. О. или любые другие персональные данные в явном виде. dataLayer — это клиентская сторона. Любой пользователь может открыть DevTools и посмотреть содержимое массива.

Коротко о праве. В ЕС действует GDPR, в России — №152-ФЗ «О персональных данных». Оба документа сходятся в одном: персональные данные должны обрабатываться законно, с определенной целью и с минимизацией объема. Пушить email в глобальную переменную страницы — почти всегда плохая идея. Архитектурное правило простое: dataLayer для поведенческих и служебных данных. Идентифицирующие данные, только если они хешированы и действительно нужны для конкретной интеграции.

E-commerce события

E-commerce — это место, где различия форматов становятся особенно заметны. Подробнее про e-commerce я писал в цикле статей ранее (первая статья цикла). В Google Tag Manager исторически использовалась модель Enhanced Ecommerce для Universal Analytics. Там структура выглядела примерно так:


dataLayer.push({
  event: 'addToCart',
  ecommerce: {
    add: {
      products: [{
        id: 'sku_1',
        name: 'Product 1',
        price: 1990
      }]
    }
  }
});

 

С переходом на Google Analytics 4 структура изменилась. Теперь модель событийная, а товары передаются в массиве items:


window._mtm.push({

event: 'add_to_cart',
  ecommerce: {
    items: [{
      sku: 'sku_1',
      name: 'Product 1',
      price: 1990,
      quantity: 1
    }]
  }
});

 

Различия в названиях полей, вложенности, обязательных параметрах. Но принцип остается тем же: событие + структурированные данные. Именно поэтому важно не «копировать пример из документации», а проектировать свою Data Layer Specification так, чтобы она могла быть адаптирована под разные инструменты. Они меняются, тогда как архитектура данных должна быть стабильной.

Итоговая модель понимания

Если отбросить бренды, интерфейсы и маркетинг, остается очень простая модель, строящаяся на простых аксиомах:

  1. dataLayer — это глобальная переменная. 
  2. Это массив.
  3. Он живет в window.
  4. Тег-менеджер его не создает, а использует.
  5. Это интерфейс между фронтом и аналитикой.

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

Когда dataLayer не нужен

Есть ситуации, где он действительно избыточен. Если используется server-side трекинг и данные отправляются напрямую с сервера, без клиентской логики. Если аналитика встроена напрямую в код приложения, без тег-менеджера и без необходимости промежуточного слоя. Если в проекте уже есть полноценный custom event bus и аналитика подписывается на него напрямую, минуя глобальную переменную. Во всех остальных случаях dataLayer остается самым простым и универсальным способом связать интерфейс и аналитику.

Заключение

dataLayer — это не инструмент маркетинга, а часть фронтенд-архитектуры. Хорошо спроектированный dataLayer экономит десятки часов на отладке, упрощает масштабирование и делает подключение новых систем предсказуемым. Плохо спроектированный превращает аналитику в вечный режим «почини после релиза». Или другими словами и коротко: если фронтенд — это API для пользователя, то dataLayer — это API для аналитики.

Комментарии0
Тоже интересно
Комментировать
Поделиться
Скопировать ссылку
Telegram
WhatsApp
Vkontakte
Одноклассники