Dilshat Rakhimov
Июль 2026 · 10 мин чтения
Симптом, который приводит к этому разбору, звучит одинаково в любом лидогенерационном проекте: в Google Ads видно лиды - заявки идут, CPL приемлемый, - но целевого действия, которое приносит деньги, платформа не видит вовсе. В кредитном продукте это выдача займа, в подписке - оплата, в e-commerce - выкуп. Ноль в колонке выручки при живом потоке лидов почти всегда означает одно: порвана цепочка gclid между кликом, редирект-трекером, лендингом и серверной конверсией.
Разберём это на воронке кредитного PWA-агрегатора: пользователь приходит по Google Ads, оставляет заявку, а выдача (деньги) фиксируется позже - постбэком от кредитора на бэкенд, без участия браузера. Между кликом и лендингом стоит редирект-трекер (класс инструментов вроде Keitaro/Binom). Именно в этой связке gclid и терялся.

Что такое цепочка gclid и где она рвётся
gclid (Google Click Identifier) - это токен, который Google Ads с включённым авто-тегированием дописывает к финальному URL объявления. Вся атрибуция Google построена на нём: без gclid в сессии Google Ads не понимает, что этот визит - от его клика, а серверная конверсия, случившаяся через два дня, не привязывается к кампании.
Теперь наложим редирект-трекер. Финальный URL объявления ведёт не на лендинг, а на трекер: https://track.example/<token>. Трекер отдаёт 302 и уводит пользователя на лендинг: https://app.example/?clickid=<subid>. И вот здесь ловушка: на редиректе трекер прокидывает свой clickid, но не прокидывает gclid. В результате:
Лендинг открывается без gclid. Дальше по цепочке всё выглядит нормально: заявка создаётся, clickid трекера едет в бэкенд, лиды считаются. Но GA4-сессия не помечена как Google Ads / paid, потому что в URL не было gclid. Когда приходит выдача - серверное событие purchase - привязать его к клику Google уже нечем. Лиды есть (их держит clickid трекера), выдач нет (для них нужен gclid, а он умер на 302).
Второй, тихий баг: gclid писали, но не читали
Даже там, где gclid удавалось поймать на сабмите, вскрылась вторая проблема - уже не в трекере, а в бэкенде. При сохранении заявки gclid записывался в БД, но функция, которая потом доставала заявку для отправки конверсии, этот gclid не читала. Классический скрытый пробел: колонка есть, значение пишется, но на этапе отправки purchase его никто не подставляет. Наружу это выглядело точно так же - «выдачи не атрибутируются», - хотя данные в базе лежали. Такие баги не видны в дашбордах: их находят, только пройдя путь значения от захвата до отправки поле за полем.
Как замкнуть цепочку
Починка - это не один тумблер, а восстановление сквозного пути gclid от клика до денежного события.
1. Прокинуть gclid через редирект-трекера. В offer/flow URL трекера добавляется gclid, чтобы он пережил 302 вместе с clickid:
{gclid} - валидный макрос источника Google Ads внутри трекера. Тест-клик после правки должен показать на лендинге оба параметра. Важная деталь про комплаенс: parallel tracking ограничивает только tracking template, но не Final URL-редирект. Поэтому вести финальный URL на трекер (на поддомене того же корневого домена, что и лендинг) - допустимо, атрибуция не ломается.
2. Захватить gclid и client_id на лендинге и сохранить вместе с заявкой. Параллельно снимается _ga (GA4 client_id) - он понадобится, чтобы серверный purchase попал в ту же сессию.
3. На выдаче отправить server-side purchase в GA4 через Measurement Protocol: событие purchase с value (наша комиссия), transaction_id = pb_<id>, client_id из cookie _ga, плюс gclid и хешированные email/телефон для Enhanced Conversions. Выдача приходит постбэком, без браузера - поэтому фронтовый GTM её не поймает, нужен серверный хит.
4. Импортировать purchase в Google Ads. purchase делается Key event в GA4 и импортируется в Google Ads (GA4 → Ads import). Дальше кампании оптимизируются на выдачу, а не на дешёвый лид. Одно правило: не задваивать - либо GA4 → Ads import, либо прямой upload в Ads API, но не оба сразу, иначе конверсии удвоятся.
Дедуп по всей цепочке держится на transaction_id = pb_<id>.
Подводные камни при деплое
Теория выше - ровная. На реальном сервере всплыли вынужденные отклонения, которые полезно знать заранее.
_ga пришлось читать серверно, а не на фронте. На боксе лежал только собранный dist, исходников фронта не было - пересобрать и добавить фронтовый захват client_id невозможно. Решение: cookie _ga едет с same-origin POST-запросом заявки, и бэкенд читает client_id прямо из req.headers.cookie. Ребилд фронта не потребовался.
Measurement Protocol - напрямую в Google, а не через sGTM. Интуитивно хочется пустить серверный хит через свой server-side GTM. Но сток-контейнер sGTM с GA4-клиентом отдаёт 400 на /mp/collect - GA4-клиент слушает /g/collect, а не MP-эндпоинт. А для чистого server-to-server хита у sGTM и нет first-party-выгоды (нет браузера, нет блокировщиков). Поэтому purchase уходит прямо на https://www.google-analytics.com/mp/collect (ответ 204 = принято).
Cloudflare Bot Fight Mode режет server-to-server POST. Если домен проксирован через Cloudflare, Bot Fight Mode может рубить серверные POST-запросы к /mp/collect. Нужен WAF-skip для этого пути (или вести MP мимо прокси).
Захват client_id не стопроцентный - и это нормально. На живых сабмитах _ga ловится примерно у 90-92%; пропуски - адблокеры, режущие GA-cookie. Это ожидаемый уровень, а не повод чинить.
Главный вывод
«Лиды есть, конверсий/выручки нет» в Google Ads - это почти никогда не про алгоритм и почти всегда про порванную цепочку click id. Проследите gclid от объявления через все редиректы до лендинга и дальше до серверного денежного события - буквально глазами, поле за полем, тест-кликом. Точка разрыва обычно одна: 302 редирект-трекера, забытое чтение поля в бэкенде, или отсутствие серверного purchase-хита на моменте выдачи.
И более общий принцип: атрибуция не закончена в момент, когда клик размечен - она закончена, когда денежное событие донесло click id обратно. Пока purchase не несёт gclid (и его аналоги в других каналах), Google оптимизируется на самый дешёвый лид, а не на платящего клиента, - и делает это ровно так хорошо, как вы его об этом попросили.
Частые вопросы
В Google Ads есть лиды, но нет выручки. В чем обычно причина?
В разорванной цепочке `gclid`. Чаще всего ее рвет редирект-трекер в середине пути: click ID теряется до того, как его кто-то сохранит.
`gclid` есть в базе — значит, цепочка работает?
Не обязательно. Второй баг в этом кейсе был именно таким: `gclid` записывался и никогда не читался. Колонка заполнена, а при отправке конверсии ее никто не использует.
Как восстановить цепочку?
Отправлять конверсию с сервера, приложив сохраненный `gclid`: Measurement Protocol на стороне GA4 и Enhanced Conversions на стороне Google Ads. И помните: ответ 200 от API не значит, что конверсия атрибутировалась к клику, — смотрите диагностику импорта.
