Онлайн-школа в Алматы продаёт курс аналитики за 25 000 ₸, тот самый, для которого в уроке про GA4 настраивали generate_lead и purchase (цифры в уроке условные). Владелец хочет передавать оплаты в Meta и Google Ads с сервера, и разработчик спрашивает, что именно поднимать и куда пойдут данные. Начинать стоит не с выбора хостинга, а с того, как один запрос проходит через серверный контейнер. Проследим оплату заказа course_order_42, а потом соберём всю цепочку для GA4.
Путь запроса через серверный контейнер
HTTP-запрос
Приходит на адрес сервера
Клиент
Распознаёт формат и забирает запрос
Создаёт данные события
Триггер
Решает, каким тегам срабатывать
Преобразование
Меняет данные для выбранных тегов
Тег и получатель
Тег переводит данные в формат получателя и отправляет запрос
Преобразование меняет данные, которые видит тег, а входящий запрос не трогает.
Как запрос проходит через контейнер
Серверный контейнер GTM работает не в браузере посетителя, а на сервере со своим адресом. Сайт отправляет на этот адрес HTTP-запросы, а внутри контейнера с ними работают клиенты, триггеры и теги.
Клиент (client) переводит запрос с протокола отправителя на язык контейнера. Каждый входящий запрос по очереди получают все клиенты, начиная с того, у кого приоритет выше. Первый, кто узнал формат, забирает запрос себе, и остальные клиенты его уже не видят. Не узнал - пропускает дальше (как работают клиенты). В новом контейнере уже есть клиент GA4, который понимает запросы тега Google.
Забрав запрос, клиент собирает из него одно или несколько событий. Наша оплата превращается в событие purchase, а в его данных (event data) лежат value 25000, currency KZT, transaction_id course_order_42 и служебные поля вроде идентификатора посетителя. Триггеры смотрят на каждое событие и решают, каким тегам срабатывать. Тег берёт данные события, переводит их в формат своего получателя и отправляет исходящий запрос: тег GA4 - в Google Analytics, тег Conversions API - в Meta.
Теперь о том, чего контейнер не видит. Страницы у него нет, а значит, нет DOM, кликов, прокрутки и dataLayer сайта. Есть только то, что пришло в запросе: адрес, параметры, заголовки и cookies своего домена. Если сайт отправляет purchase при открытии страницы «Спасибо», а не после подтверждения оплаты, сервер разошлёт эту ошибку всем получателям. Исправляют её там, где рождается событие: на сайте или в веб-контейнере GTM.
Веб-GTM - только один из отправителей
Привычная схема выглядит так: на сайте стоит веб-контейнер, его тег Google отправляет события на сервер, а серверный контейнер раздаёт их получателям. Но веб-контейнер для этого не обязателен. Отправлять можно прямо из gtag.js, а из мобильного приложения или с бэкенда - запросами в формате Measurement Protocol, которые забирает клиент Measurement Protocol (способы отправки данных).
Школе это пригодится. Подтверждение оплаты приходит от платёжной системы на бэкенд, а человек может так и не вернуться на страницу «Спасибо». Если бэкенд сам отправит purchase на сервер, оплата дойдёт до получателей без участия браузера: так работает серверный трекинг S2S, когда вкладка давно закрыта, а платёж прошёл.
Произвольный JSON из CRM событием не станет, пока его не заберёт клиент, который понимает именно этот формат: встроенный, из галереи шаблонов или написанный под вашу систему. Без такого клиента ни один тег не сработает.
Где будет работать сервер
Серверный контейнер создают в GTM так же, как веб-контейнер, только в поле «Целевая платформа» выбирают «Сервер». Затем GTM предлагает настроить сервер тегов. Вариантов два, а ручной можно отдать провайдеру (обзор настройки):
- «Добавить сервер тегов автоматически». GTM создаёт проект в Google Cloud и сервер на Cloud Run, для этого нужен платёжный аккаунт Google Cloud.
- «Добавить сервер тегов вручную». Сервер тегов - это Docker-образ, его запускают на своей инфраструктуре. GTM показывает строку конфигурации контейнера (Container Config), её передают серверу (ручная настройка). Так же подключаются провайдеры вроде Stape: строку вставляют в их панели, а сервер они поднимают и обслуживают сами. Владелец среды, где работает сервер, может иметь доступ к вашим данным, поэтому условия провайдера читают до того, как пойдут данные заказчика.
Сколько экземпляров держать, что делать с журналами запросов и во что обходится server-side GTM, решают при выборе инфраструктуры sGTM.
Когда сервер работает, GTM должен знать его адрес. При ручной настройке адрес добавляют в «Администрирование» → «Настройки контейнера» кнопкой «Добавить URL» в поле адресов серверного контейнера (Server container URL). Связь проверяют сразу: открывается предварительный просмотр, а адрес сервера с /healthy на конце отвечает ok (руководство по Cloud Run).
Адрес сервера: путь, поддомен или адрес провайдера
Новый сервер получает адрес на домене провайдера, у Cloud Run это run.app. Данные по такому адресу доходят, но работает он в стороннем контексте. Для сайта https://www.example.com у Google три варианта (свой домен для сервера):
| Вариант | Пример адреса | Что настроить | Cookies от сервера |
|---|---|---|---|
| Путь на основном домене | https://www.example.com/metrics | CDN или балансировщик, который пересылает запросы с этого пути на сервер; иногда DNS | Да |
| Поддомен | https://metrics.example.com | Запись в DNS | Да |
| Адрес провайдера | https://metrics.run.app | Ничего, работает сразу | Нет, только cookies из JavaScript |
Разница в cookies. На пути и на поддомене сервер может ставить свои cookies прямо в ответе на запрос, в том числе с флагом HttpOnly, которые скрипты на странице не видят, а на адресе провайдера остаются только cookies из JavaScript. Путь даёт тот же origin, что у сайта, и именно этот вариант Google называет лучшей практикой, но для него нужен CDN или балансировщик. Поддомен - другой origin того же сайта, зато хватает записи в DNS.
Свой адрес меняет контекст, в котором работает сервер. Согласия посетителей и правил браузеров он не отменяет.
Настройка для GA4 по шагам
Порядок для тестового сайта или первого заказчика:
- Создайте серверный контейнер и сервер, как описано выше, и убедитесь, что адрес сервера есть в настройках контейнера.
- Привяжите к серверу поддомен или путь сайта и замените адрес в настройках контейнера на новый. На тестовом сайте этот шаг можно отложить.
- В серверном контейнере откройте «Клиенты» и посмотрите клиент GA4. Если других клиентов, претендующих на запросы GA4, нет, приоритет можно оставить 0. Пока сервер живёт на адресе провайдера, в настройке cookies клиента оставьте JavaScript Managed: до смены домена работает только этот вариант (настройка потока GA4).
- Создайте тег типа Google Analytics: GA4. Поля оставьте по умолчанию, идентификатор потока и параметры он возьмёт из данных события. Триггер нужен типа Custom с условием Some Events, в котором встроенная переменная Client Name равна имени клиента, например
GA4. Именно имени, а не типу клиента, который называется Google Analytics: GA4. - В веб-контейнере создайте переменную типа «Тег Google: Настройки конфигурации» с параметром
server_container_urlи адресом сервера в значении. Выберите её в разделе «Настройки конфигурации» тега Google и поставьте триггер «Инициализация - Все страницы». Если на сайте gtag.js без GTM, адрес передают в командеconfig:
- Откройте предварительный просмотр серверного контейнера, а в том же браузере - сайт. Слева появятся запросы
collect?v=2и события под ними. На вкладке «Запрос» видно, какой клиент забрал запрос, что пришло и какой исходящий запрос ушёл в GA4, вместе с кодом ответа (предварительный просмотр и отладка). Запросы из другого браузера в просмотр не попадают (проверка настройки). - Опубликуйте серверный контейнер, затем веб-контейнер.
На проекте заказчика рабочий тег сразу не переключают. Для серверных данных заводят отдельный ресурс GA4 и какое-то время собирают данные в оба ресурса, пока цифры не сойдутся (параллельный сбор). Допустим, за неделю старый ресурс показал 15 покупок, а новый 14. По одному заказу причину не назвать. Выгрузите из CRM номера заказов за неделю, найдите тот, которого нет в новом ресурсе, и повторите такую покупку в предварительном просмотре: тот же способ оплаты, то же устройство. Переключать рабочий тег можно, когда расхождение объяснено.
Преобразования: Allow, Augment и Exclude
Между данными события и тегом можно поставить преобразование (transformation). Оно запускается после того, как клиент собрал данные события, и меняет то, что увидят выбранные теги. Входящий запрос оно не трогает. Типов три (преобразования):
- Allow («Использовать параметры» в русской документации) оставляет тегам только перечисленные параметры, а остальные отбрасывает, включая те, без которых не работают теги Google.
- Augment («Дополнить данные, относящиеся к событию») меняет значение параметра или добавляет новый.
- Exclude («Исключение параметров») убирает указанные параметры.
По умолчанию они применяются в порядке Allow, Augment, Exclude. Порядок меняют приоритетом: чем больше число у преобразования, тем раньше оно сработает. У каждого есть «Затронутые теги» и «Условия совпадения», и без настройки преобразование действует на все теги и всегда.
Из-за этого умолчания слишком узкий Allow ломает поток данных незаметно. Допустим, для тега, который пишет события в BigQuery, разрешили event_name, page_path и client_id, а затронутые теги выбрать забыли. Allow отрежет поля у всех тегов, и те, кому нужно больше, включая GA4, перестанут срабатывать: преобразование, которое убрало нужные тегу поля, может его остановить. На сайте при этом ошибок нет, просто в отчётах становится меньше событий. Найти такую поломку можно, только если смотреть, какие данные получает каждый тег.
Теперь пример, ради которого преобразования и ставят. Админка сайта добавляет к заказу пометку о скидке, и разработчик школы передаёт её в purchase параметром internal_note: «скидка сотруднику 30%». Ни рекламным кабинетам, ни GA4 эта пометка не нужна. А некоторые серверные теги отправляют получателю дополнительные параметры без всякой настройки, и лишнее убирают как раз преобразованием (отправка данных на сервер). Делаем Exclude с internal_note и в затронутых тегах выбираем рекламные теги и GA4. Приёмка на примере тега Meta выглядит так:
- В предварительном просмотре выберите событие
purchaseи откройте вкладку «Теги». - Нажмите на тег Meta. В сведениях о теге видно, какие преобразования сработали и в каком порядке.
- В блоке «Данные события»
internal_noteбыть не должно. С отметкой «Показать исходные данные» он появится среди исходных параметров, так и задумано. - На вкладке «Запрос» откройте исходящий запрос к Meta:
internal_noteнет и там. Те же два места смотрят у тегов Google Ads и GA4.
Во входящем запросе поле останется, потому что преобразование входящий запрос не переписывает. Раз пометка не нужна ни одному получателю, правильнее убрать её на сайте, а Exclude оставить страховкой, пока разработчик это делает. И помните о журналах: Cloud Run по умолчанию записывает путь и параметры каждого запроса, так что всё, что пришло на сервер, окажется и там.
Согласие
Согласие собирают в веб-контейнере. Баннер передаёт выбор тегу Google, тот добавляет параметры согласия к запросу на сервер, а теги Google в серверном контейнере сами подстраиваются под этот выбор, поэтому режим согласия настраивают только в веб-контейнере (consent mode на сервере). Но это правило про теги Google. Тег Meta, TikTok или собственный HTTP-запрос в серверном контейнере срабатывает по своему триггеру у любого посетителя, пока вы сами не добавите условие на согласие. Такое условие ставят на каждый сторонний тег отдельно и потом проверяют отказом, как в разборе Consent Mode v2 и server-side GTM.
Задание: серверный контейнер для тестового сайта
Возьмите тестовый сайт с формой из урока про GA4 или любой свой.
Выполнено 0 из 6
Если предварительный просмотр пуст, первым делом смотрят адрес в server_container_url и браузер: сайт и просмотр должны быть открыты в одном браузере. Запрос виден, а тег GA4 не сработал - откройте условие триггера, там должно стоять имя клиента, а не его тип. Тег сработал, но у исходящего запроса код ошибки - значит, получатель что-то не принял, и разбираться надо с данными события. Если заявка с ошибкой всё же дошла до сервера, тег на сайте срабатывает по клику, а не по ответу сервера, и чинить это надо в веб-контейнере. В итоге у вас скриншот, по которому другой человек поймёт, что поток работает.
Видео: настройка GA4 через sGTM
Видео на английском.