Центр подготовки к IELTS в Алматы рекламирует в Instagram бесплатный пробный урок. В понедельник человек кликнул по объявлению и оставил заявку на сайте, пиксель Meta записал Lead. В субботу, после пробного урока, он оплатил через Kaspi первый месяц трёхмесячного курса, 45 000 ₸, и менеджер отметил сделку в CRM как «Оплачено» (цифры в уроке условные). Страницу с формой закрыли ещё в понедельник, в CRM пикселя нет, так что об оплате Meta узнает, только если ей сообщит сервер.
Заявка и оплата - разные события
Понедельник: сайт
lead_42
Заявка сохранена; события отправляет браузер
Суббота: CRM
payment_42
45 000 ₸ за первый месяц
Менеджер подтверждает поступление денег
Серверная отправка
Скрипт реагирует на статус «Оплачено»
При повторе ID тот же: payment_42
lead_42 и payment_42 связаны в CRM, но их не склеивают как дубли.
Server-side и S2S: два разных маршрута
Server-side называют две разные схемы, и на первом созвоне с клиентом стоит сразу выяснить, о какой из них речь.
В первой браузер по-прежнему отправляет события, только не прямо в Google и Meta, а на ваш сервер, например в серверный контейнер GTM на поддомене data.example.com. Сервер решает, что и кому переслать. Google описывает такой контейнер как дополнение к веб-контейнеру: он забирает часть работы у страницы и, если его настроить, даёт полный контроль над тем, какие данные уходят третьим сторонам. Но в этой схеме контейнер получает только то, что прислала страница. Субботней оплаты на странице не было, значит, не будет её и на этом сервере.
Во второй событие создаёт ваш backend или CRM, браузер в этом не участвует. Сделка перешла в «Оплачено», скрипт на сервере отправляет Purchase в Meta через Conversions API и purchase в GA4 через Measurement Protocol. Это S2S, server-to-server: запрос идёт с вашего сервера на сервер платформы. Оплату после заявки передают именно так.
Пиксель при этом остаётся на сайте. Meta советует подключать Conversions API вместе с пикселем, а Google пишет, что Measurement Protocol дополняет обычный сбор и работает только при теге на сайте. Страница сообщает о том, что случилось на странице, сервер - о том, что случилось потом. В тесте недели 2 кабинет видел 11 заявок, а о троих, кто дошёл до пробного урока, знал только менеджер. Как раз такие факты и передаёт сервер.
Что сохранить в момент заявки
В субботу сервер знает сумму и номер сделки, но не знает, с какого объявления пришёл человек. Эта связь есть только в понедельник, в браузере. Вот что форма должна записать в заявку вместе с телефоном:
- cookie
_ga: в нём лежитclient_id, по которому GA4 связывает серверное событие с пользователем; - cookies
_fbpи_fbc(параметрыfbpиfbc): Meta принимает их как есть, без хеширования. Если cookie_fbcнет, сохранитеfbclidиз адреса и время, когда он пришёл: из них собираютfbcвидаfb.1.<время в миллисекундах>.<fbclid>; - IP-адрес и user agent браузера: Meta использует их для сопоставления, а для событий сайта user agent обязателен;
- параметр
gclidиз адреса: Google Ads просит сохранять его вместе с заявкой и потом возвращать с данными о продаже. Для новой настройки Google там же советует начинать с расширенного отслеживания конверсий лидов (enhanced conversions for leads), а с 15 июня 2026 года такие загрузки переводит из Google Ads API в Data Manager API. Подробно об этом в офлайн-конверсиях Google Ads; - UTM-метки по общей схеме разметки и номер заявки.
Делается это скрытыми полями формы, которые скрипт заполняет из cookies, адреса страницы и заголовков запроса. Телефон Meta тоже использует для сопоставления, но только в виде хеша SHA-256 и после нормализации: с кодом страны, без плюса, пробелов и скобок. Номер, записанный как 8 701 123 45 67, превращается в 77011234567: восьмёрка в начале - не код страны. Если ничего этого не сохранить, оплату всё равно можно отправить, но рекламной системе будет почти не за что её зацепить.
С GA4 есть оговорка. Событие из Measurement Protocol получит географию и устройство этого визита, только если в нём есть session_id и оно пришло в течение 24 часов после начала сессии. События, которые должны склеиться с браузерными, Google просит доставить в течение 48 часов и предупреждает, что более поздние могут обработаться не так, как ожидается, особенно при атрибуции конверсий. Оплата через пять дней в эти сроки не укладывается, и источник рекламного визита в GA4 ей, скорее всего, не достанется. Канал для такой оплаты надёжнее брать из CRM: UTM-метки лежат в заявке, а заявка связана со сделкой.
Описание события
Прежде чем разработчик напишет скрипт, договоритесь, что считается оплатой и что уходит в событии. Для центра подготовки описание выглядит так:
| Поле | Заявка | Оплата |
|---|---|---|
| ID события | lead_42, создаётся, когда сайт сохранил заявку | payment_42, создаётся, когда сделка перешла в «Оплачено» |
| Время события | понедельник, момент сохранения заявки | суббота, момент подтверждения оплаты, а не момент отправки |
Где случилось (action_source) | website | other: оплата прошла переводом, не на сайте |
| Источник факта | ответ сервера сайта, что заявка записана | статус сделки в CRM, который менеджер ставит только после того, как деньги пришли на счёт |
| Кто отправляет | пиксель Meta и тег GA4 в браузере | скрипт на сервере по смене статуса сделки |
| Повторы | одно событие на сохранённую заявку | при тайм-ауте или временной ошибке, с тем же payment_42, до пяти попыток |
| Сумма | не передаётся | 45 000 ₸ за первый месяц, валюта KZT |
| Связь с рекламой | cookies и метки из браузера | значения, которые форма сохранила в заявке lead_42 |
action_source Meta требует в каждом серверном событии и даёт список значений: для перевода через Kaspi там нет отдельного варианта, и подходит other. Статус от менеджера годится как источник, пока его ставят по факту поступления денег, а не по обещанию клиента. В интернет-магазине с онлайн-оплатой источником служит подтверждение платёжного сервиса, как в S2S-трекинге оплаты.
У заявки и оплаты разные ID, потому что это два факта. Связь между ними хранится в CRM: в сделке записан номер заявки. ID принадлежит факту, а не человеку. Когда тот же ученик заплатит за второй месяц, это будет новое событие с новым номером. Дайте всем событиям клиента один ID, и вторую оплату будет не отличить от повтора первой ни в вашем журнале, ни у получателя, который склеивает дубли по ID.
Время события - момент оплаты, и его передают отдельно от момента отправки, потому что у получателей есть предел давности. Meta принимает event_time не старше семи дней на момент отправки, а если в запросе есть хоть одно более старое событие, отклоняет весь запрос. GA4 разрешает сдвинуть время не больше чем на 72 часа назад; более старое событие он по умолчанию примет, но запишет его на отметку 72 часа назад. Если скрипт упал в субботу и его подняли только в среду, оплата попадёт в GA4 с неверным временем, а ещё через несколько дней её не примет и Meta. Следить за очередью неотправленных событий должен назначенный человек.
Есть и правила атрибуции. По умолчанию Meta засчитывает объявлению события в течение семи дней после клика по ссылке и одного дня после просмотра, а окно по кликам можно сократить до одного дня. Клик был в понедельник, оплата в субботу, через пять дней: в окно по умолчанию она попадает, в однодневное нет. А если бы ученик думал две недели, никакая серверная интеграция не приписала бы эту оплату объявлению. И деталь, на которой спотыкаются при сверке: Ads Manager показывает конверсию в дне показа объявления, то есть понедельником, а в CRM оплата стоит субботой.
Повтор не должен удваивать выручку
Допустим, в субботу скрипт отправил оплату, не дождался ответа и отправил её ещё раз, уже с новым ID. В кабинете окажутся две покупки на 90 000 ₸. Посчитаем на месяце: на кампанию потратили 60 000 ₸, первых оплат было три, по 45 000 ₸ каждая. Настоящий ROAS 135 000 / 60 000 = 2,25. Один такой дубль, и кабинет покажет 180 000 ₸ и ROAS 3, а вы предложите клиенту поднять бюджет по деньгам, которых нет.
Повтор поэтому всегда уходит с тем же payment_42: Meta убирает повторные серверные события с одинаковыми event_name и event_id. Как устроить очередь, повторы и разбор ошибок, подробно разобрано в S2S-трекинге оплаты.
Заявка понедельника и оплата субботы при этом не дубли. Это разные стадии одной сделки, и склеивать их нельзя.
Что проверить до запуска
Ответ «200 OK» от получателя значит только, что запрос принят. Measurement Protocol GA4 не возвращает ошибку даже на неправильно собранное событие, и новые события сначала гоняют через его сервер проверки /debug/mp/collect. В Meta отдельные события видно только в «Тестировании событий»: там же отмечено, какие из них отброшены как дубли. Общие счётчики Events Manager дубли не убирают, а сработала ли склейка на живом трафике, показывают вкладка «Дедупликация событий» и Ads Manager.
Возьмите одну тестовую сделку и проведите через неё пять ситуаций:
- Обычная оплата. Уходит одно событие с правильной суммой, валютой и временем. Тестовые события отправляйте с
test_event_codeиз «Тестирования событий»: Meta их не выбрасывает, поэтому сумму ставьте маленькую, а перед запуском код уберите. - Менеджер ошибся, вернул сделку из «Оплачено» назад и снова перевёл. Событие всё равно одно.
- Сервер получателя недоступен. Скрипт повторяет с тем же ID, а после последней попытки событие оказывается в очереди разбора.
- Возврат. Повторный
Purchaseне уходит. Как отражать возвраты, решите заранее вместе с бухгалтерией: в GA4 для этого есть событиеrefund. - Человек отказался от рекламных cookies. Серверный маршрут выполняет его выбор так же, как браузер.
Пятый пункт легко пропустить: баннер cookies стоит на сайте, а скрипт оплат живёт в CRM и о баннере ничего не знает. Выбор человека сохраняют вместе с заявкой и смотрят на него перед каждой отправкой. Где ещё здесь ломается, разобрано в статье про согласия и серверный GTM, а что вообще можно передавать, в уроке про privacy и cookieless.
Упражнение: описание события для своего проекта
Возьмите тестовый сайт или проект клиента:
Выполнено 0 из 4
Если в заявке нет ни одного идентификатора из браузера, начинать нужно со скрытых полей формы, а не со скрипта отправки. Если оплаты приходят позже окна атрибуции, кабинет их рекламе не припишет, как бы аккуратно ни работал сервер, и это стоит сказать клиенту до начала работ.
Теперь вопрос, который вам зададут. Через месяц клиент видит оплаты в Ads Manager и спрашивает: «Теперь реклама оптимизируется на оплаты?» Что вы ответите?
Нет. Событие оптимизации выбирают в группе объявлений, и появление Purchase в наборе данных его не меняет. Даже если переключить группу на оплаты, при трёх оплатах в месяц она застрянет в обучении. Meta считает группу ограниченной в обучении, если та вряд ли наберёт около 50 событий оптимизации за неделю, и сама советует в таком случае выбрать событие, которое случается чаще. Клиент получил другое: отчёт показывает, какие объявления привели к оплатам в пределах окна атрибуции, и ROAS считается по деньгам, а не по заявкам. К оптимизации на оплаты можно возвращаться, когда их станут десятки в неделю.
Видео: общая схема server-side tracking
Видео на английском и про первую схему, серверный GTM. Как он устроен, показано на примере серверного GTM.