UTM-метки пропадают после редиректа — это ещё не диагноз. ИИ-агент может собрать разрешённые URL, CSV и инструкции, сравнить каждый переход с ожидаемыми параметрами и отметить первое расхождение. Проверяйте отдельно адрес, первый запрос счётчика, данные, которые отправляет форма (payload), и фактически сохранённую запись CRM: один слой не доказывает результат в другом. Человек уточняет отсутствующие бизнес-условия и решает вопросы по исключениям; вручную перепроверять каждую строку не нужно.
Выполненный ниже локальный пример использует Python 3.14 http.server.ThreadingHTTPServer с обработчиком на основе BaseHTTPRequestHandler. Это учебный стенд, а не аудит сайта, производственная настройка или проверка модели.
Сначала локализуйте слой
Запишите четыре наблюдения, а для диагностики CRM добавьте пятое — связанную с тестовой отправкой запись. Конечный URL сам по себе не показывает, что получил счётчик или сохранила CRM.
| Слой | Что записать | На какой вопрос отвечает |
|---|---|---|
| Исходная ссылка | Полный URL и ожидаемые utm_source, utm_medium, utm_campaign |
Были ли нужные значения до перехода? |
| Переходы и конечный URL | URL каждого запроса, статус, Location, следующий URL и конечный адрес |
На каком переходе адрес изменился? |
| Первый hit | Первый запрос счётчика и видимые в нём значения | Какие параметры дошли до первого запроса аналитики? |
| Форма | Точные UTM-поля в данных отправленной тестовой формы | Что форма передала дальше? |
| CRM | ID связанной записи и фактически сохранённые UTM-поля | Что действительно осталось в записи CRM? |
Архивный материал Яндекса о проблемах с UTM опубликован 5 февраля 2018 года и помечен как архивный. Материал Яндекса о проблемах с UTM-метками В нём среди возможных случаев описаны редирект на страницу без установленного счётчика и редирект, при котором UTM отбрасываются. Материал Яндекса о проблемах с UTM-метками Это исторические примеры для проверки, а не исчерпывающий перечень причин и не инструкция, которая гарантированно подходит любому сайту.
Документация Яндекс Метрики описывает сервис как инструмент веб-аналитики, который помогает получать наглядные отчёты и записи действий посетителей, отслеживать источники трафика и оценивать эффективность онлайн- и офлайн-рекламы. Документация Яндекс Метрики Справка об отчёте «Метки UTM» говорит, что он содержит статистику по UTM-меткам, если они используются в ссылках на сайт. Справка об отчёте «Метки UTM»
В справке о проблемах с источниками среди возможных случаев названа страница входа, на которой не установлен код счётчика. Справка Яндекс Метрики о проблемах с источниками Там же описан вариант, когда JavaScript выполняется до кода счётчика и перенаправляет пользователя внутри сайта. Справка Яндекс Метрики о проблемах с источниками Справка предлагает обнаруживать такой случай по редиректу, происходящему на сайте. Справка Яндекс Метрики о проблемах с источниками
Исчезновение UTM из адресной строки не означает автоматически, что потерялась атрибуция. Сверьте ожидаемые правила сайта с тем, что видно в первом запросе счётчика, данных формы и связанной записи CRM. В локальном сценарии /clean адрес очищается после записи параметров в учебный hit, а значения остаются в учебной форме. Это результат только нашего стенда: он не доказывает, что так же работает Метрика, форма или CRM на реальном сайте.
Снимите цепочку
Один переход в цепочке — это hop. Для каждого hop запишите URL запроса, статус ответа, заголовок Location и следующий URL. В ответе 3xx заголовок Location указывает URL, на который перенаправляется страница. Документация MDN о заголовке Location
Сравнивайте UTM в URL запроса и в следующем адресе. Наличие параметров в исходной ссылке ещё не показывает, что они сохранились после редиректа.
В выполненном локальном стенде self.path обрабатывается через urlsplit(self.path), а затем код стенда задаёт целевой адрес. В документации Python BaseHTTPRequestHandler.path описан как путь запроса, который включает query-компонент, если он есть. Документация Python о BaseHTTPRequestHandler.path В ветке keep обработчик добавляет query к целевому адресу; в ветке drop на втором переходе задаёт /landing без параметров. Поэтому в этом локальном прогоне первое расхождение возникает из-за выбранного обработчиком целевого адреса, а не из-за универсального свойства статуса 302 или 307.
В стенде send_header() задаёт значение Location. В документации Python сказано, что send_header() добавляет заголовок во внутренний буфер. Документация Python о send_header() и end_headers() Метод end_headers() завершает заголовки ответа пустой строкой и отправляет буфер. Документация Python о send_header() и end_headers() Само решение о том, включать ли query в Location, принимает обработчик, когда формирует целевой адрес.
http.server здесь нужен только для локальной учебной диагностики. Документация Python не рекомендует этот модуль для production и отмечает, что он реализует только базовые проверки безопасности. Документация Python о send_header() и end_headers() Не переносите код или логику настройки на nginx, Apache либо другой сервер без документации именно этой системы.
Для локального стенда с адресом http://127.0.0.1:8000 команды проходят HTTP-цепочки и сохраняют заголовки и трассировочный вывод:
curl -sS -L -v -D keep.headers -o /dev/null 'http://127.0.0.1:8000/keep/start?utm_source=demo&utm_medium=cpc&utm_campaign=lesson' 2>keep.trace
curl -sS -L -v -D drop.headers -o /dev/null 'http://127.0.0.1:8000/drop/start?utm_source=demo&utm_medium=cpc&utm_campaign=lesson' 2>drop.trace
Для своего сайта используйте только разрешённые URL. HTTP-журнал фиксируйте отдельно от браузерной проверки JavaScript: в локальном примере переход /js-loss исследовали в браузере, а не выводили из строки HTTP-журнала.
Заполненные цепочки выполненного локального прогона:
| Сценарий | Hop | URL запроса | Статус | Location |
Следующий URL | UTM в запросе / следующем URL |
|---|---|---|---|---|---|---|
keep |
0 | /keep/start?utm_source=demo&utm_medium=cpc&utm_campaign=lesson |
302 | /keep/middle?utm_source=demo&utm_medium=cpc&utm_campaign=lesson |
/keep/middle?utm_source=demo&utm_medium=cpc&utm_campaign=lesson |
да / да |
keep |
1 | /keep/middle?utm_source=demo&utm_medium=cpc&utm_campaign=lesson |
307 | /landing?utm_source=demo&utm_medium=cpc&utm_campaign=lesson |
/landing?utm_source=demo&utm_medium=cpc&utm_campaign=lesson |
да / да |
keep |
2 | /landing?utm_source=demo&utm_medium=cpc&utm_campaign=lesson |
200 | — | — | да / — |
drop |
0 | /drop/start?utm_source=demo&utm_medium=cpc&utm_campaign=lesson |
302 | /drop/middle?utm_source=demo&utm_medium=cpc&utm_campaign=lesson |
/drop/middle?utm_source=demo&utm_medium=cpc&utm_campaign=lesson |
да / да |
drop |
1 | /drop/middle?utm_source=demo&utm_medium=cpc&utm_campaign=lesson |
302 | /landing |
/landing |
да / нет |
drop |
2 | /landing |
200 | — | — | нет / — |
В drop первое расхождение — переход /drop/middle → /landing: UTM есть в URL запроса, но отсутствуют в Location. В keep параметры сохранены в обоих переходах и в конечном адресе.
Полный http-hops.csv из выполненного стенда:
case,hop,request_url,status,location,utm_present
keep,0,/keep/start?utm_source=demo&utm_medium=cpc&utm_campaign=lesson,302,/keep/middle?utm_source=demo&utm_medium=cpc&utm_campaign=lesson,True
keep,1,/keep/middle?utm_source=demo&utm_medium=cpc&utm_campaign=lesson,307,/landing?utm_source=demo&utm_medium=cpc&utm_campaign=lesson,True
keep,2,/landing?utm_source=demo&utm_medium=cpc&utm_campaign=lesson,200,,True
drop,0,/drop/start?utm_source=demo&utm_medium=cpc&utm_campaign=lesson,302,/drop/middle?utm_source=demo&utm_medium=cpc&utm_campaign=lesson,True
drop,1,/drop/middle?utm_source=demo&utm_medium=cpc&utm_campaign=lesson,302,/landing,True
drop,2,/landing,200,,False
js-loss,0,/js-loss?utm_source=demo&utm_medium=cpc&utm_campaign=lesson,200,,True
clean,0,/clean?utm_source=demo&utm_medium=cpc&utm_campaign=lesson,200,,True
form-loss,0,/form-loss?utm_source=demo&utm_medium=cpc&utm_campaign=lesson,200,,True
В http-hops.csv поле utm_present показывает наличие UTM в URL запроса этой строки. Сравнивайте его с Location и следующим URL, а не используйте отдельно как доказательство сохранения параметров после перехода.
Проверьте браузер и заявку
Для реального сайта проводите тест в тестовой среде или с заранее согласованным разрешением. В браузере включите сохранение журнала Network, например Preserve log. Запишите переходы, конечный URL и первый реальный запрос счётчика. Фиксируйте только значения, видимые в запросе; неизвестные поля не восстанавливайте по догадке.
Результаты локальной браузерной проверки:
| Сценарий | Конечный URL | utm_source в первом локальном hit |
utm_source в учебной форме |
|---|---|---|---|
/js-loss |
/landing |
пусто | пусто |
/clean |
/clean |
demo |
demo |
/form-loss |
/form-loss?utm_source=demo&utm_medium=cpc&utm_campaign=lesson |
demo |
пусто |
Полный browser-results.csv:
scenario,final_url,first_hit_utm_source,form_utm_source
/js-loss,/landing,,
/clean,/clean,demo,demo
/form-loss,/form-loss?utm_source=demo&utm_medium=cpc&utm_campaign=lesson,demo,
В стенде /hit — учебная точка, а не Метрика; /form — имитация формы, а не CRM. Внешних запросов аналитики и реальных заявок не было. В /js-loss браузерный сценарий приводит к /landing до локального hit. В /clean параметры есть в hit и форме, хотя адрес очищен. В /form-loss параметры видны в конечном URL и hit, но отсутствуют в учебной форме. Это результаты локального примера, а не доказательство работы интеграции на реальном сайте.
Чтобы проверить реальную заявку, пройдите весь путь от ссылки до связанной записи CRM:
- Создайте
test_id. Запишите ожидаемыеutm_source,utm_medium,utm_campaign, исходный URL, дату и время с часовым поясом, тестовую среду и выбранную цель. Не отправляйте персональные данные и не создавайте рабочий заказ или оплату. - Откройте ссылку с включённым
Preserve log. Сохраните HTTP- и JavaScript-переходы, конечный URL и первый реальный запрос счётчика. Запишите только поля, которые видны в запросе. - С разрешения отправьте одну маркированную тестовую форму. Зафиксируйте endpoint, время, статус, точные UTM-поля в данных запроса формы, ответ и ID заявки или
correlation_id, если он выдан. HTTP 200 сам по себе не доказывает появление записи в CRM. - По тому же техническому ID найдите разрешённую запись CRM через доступный read-only API, экспорт или интерфейс. Запишите
record_id,created_atи фактически сохранённые UTM-поля. Связь с формой подтверждайте техническим ID, а не похожим именем или близким временем. - Если UTM есть в данных запроса формы, но отсутствуют в связанной записи CRM, проверьте обработку формы, интеграцию и сопоставление полей. Запросите разрешённый серверный лог этой отправки; без него не назначайте конкретную систему виновной. Если параметры отсутствуют уже в запросе формы, проверяйте заполнение формы. Если расхождение появилось раньше — проверяйте соответствующий HTTP- или JavaScript-переход.
- Если нет доступа, ID, лога или связанной записи, отметьте слой CRM как «не проверен». Не утверждайте, что CRM сохранила или потеряла значения без подтверждения.
- После исправления повторите сценарий с новым
test_idи теми же ожидаемыми UTM. Сравните все слои, а тестовую запись обработайте по заранее согласованным правилам тестовой среды.
Копируемый шаблон журнала для реального теста:
test_id,started_at,expected_utm,final_url,first_hit_observed,form_payload_utm,submission_id,crm_record_id,crm_saved_utm,evidence,status,next_observation
заполнить,заполнить,source=...;medium=...;campaign=...,не проверено,не проверено,не проверено,не проверено,не проверено,не проверено,ссылки на разрешённые наблюдения,не проверено,указать недостающее свидетельство или следующий шаг
В этом заполненном шаблоне нет данных реальной CRM: фактические значения нужно внести по наблюдениям. Названия полей реальной формы и CRM сопоставляйте с документацией установленной интеграции; неизвестные значения отмечайте как непроверенные.
Сбор разрешённых журналов, отбор строк и сверку с ожидаемыми параметрами можно поручить ИИ-агенту по заданным правилам. Агент должен указать точный переход или поле первого расхождения и отметить, каких данных не хватает. Человек уточняет отсутствующие бизнес-факты и решает вопросы по исключениям; ручная вычитка каждой строки не требуется.
Запрос аналитическому помощнику
Это заготовка для анализа разрешённых данных. Запрос не выполнялся моделью и не является результатом проверки ИИ.
Ты — аналитический помощник. Найди, на каком слое и переходе UTM перестают передаваться. Не делай вывод о потере атрибуции только по конечному URL.
Входные данные:
1. Исходные размеченные URL, дата и время теста, ожидаемые значения utm_source, utm_medium и utm_campaign.
2. Журнал HTTP-переходов: test_id, hop, request_url, status, location, следующий URL, конечный URL и наблюдаемые UTM.
3. Браузерные наблюдения: переходы, конечный URL и первый реальный запрос счётчика с видимыми полями.
4. Разрешённая тестовая отправка формы: endpoint, время, статус, фактические UTM в данных запроса формы и ответ, submission_id или correlation_id.
5. Если доступно разрешённое свидетельство CRM: технический ID связи с отправкой, record_id, created_at и фактически сохранённые UTM-поля.
6. Правила сайта: какие значения и в каких слоях должны сохраниться, когда разрешена очистка URL и какие исключения допустимы.
Правила анализа:
- Разделяй исходную ссылку, каждый HTTP-запрос, статус и Location, следующий и конечный URL, первый запрос счётчика, данные запроса формы и связанную запись CRM.
- Для каждой строки HTTP-журнала сравнивай UTM в URL запроса и следующем URL. Укажи первый hop, где ожидаемые параметры исчезают, либо отметь, что в HTTP-цепочке расхождения не найдено.
- Не делай вывод о JavaScript по одной HTTP-трассе. Используй для этого только переданные браузерные наблюдения.
- Не называй локальный /hit Метрикой, а локальный /form — CRM. Не выдавай локальные результаты за доказательство работающей интеграции.
- Исчезновение UTM из адреса после подтверждённой фиксации не объявляй потерей автоматически. Сверь, сохранены ли значения в слоях, которые требуются по правилам сайта.
- Считай запись CRM проверенной только при наличии разрешённого свидетельства о фактически сохранённой записи и технической связи с тестовой отправкой. Не угадывай связь по похожему имени или времени.
- Если данные запроса формы содержат UTM, а связанная запись CRM их не содержит, укажи участок обработки формы, интеграции или сопоставления полей как область дальнейшей проверки. Запроси разрешённый серверный лог отправки; не назначай конкретную систему виновной без свидетельства.
- Если UTM отсутствуют уже в данных запроса формы, укажи участок заполнения формы. Если потеря произошла раньше, укажи соответствующий HTTP- или JavaScript-переход.
- Если нет ожидаемых значений, правил сайта, доступа, ID, лога или связанной записи, напиши «не проверено» и перечисли, какого свидетельства не хватает. Не восстанавливай неизвестные значения.
- Не предлагай универсальную конфигурацию nginx, Apache или другого сервера. Подготовь для разработчика наблюдаемые URL, hop и фактическое расхождение.
Для каждого сценария выведи:
1. test_id, исходный URL и ожидаемые UTM.
2. Краткую цепочку: request_url → status → Location → следующий URL.
3. Первый hop, где результат расходится с ожиданием, либо отметку, что расхождения в HTTP-цепочке нет.
4. Отдельные статусы проверки: URL, браузер/JavaScript, первый запрос счётчика, данные запроса формы и связанная запись CRM. Для непроверенных слоёв укажи нужное свидетельство.
5. Вывод: потеря в URL/HTTP, JavaScript-переход, заполнение формы, обработка/интеграция CRM, нормальная очистка по правилам сайта или недостаточно данных.
6. Точное сообщение разработчику с воспроизводимым URL, проблемным переходом или полем и приложенными наблюдениями.
7. Проверки для повторного прогона после исправления с новым test_id и теми же ожидаемыми параметрами.
Не объединяй выводы по разным слоям. Если свидетельств недостаточно, обозначь неопределённость и не выдавай предположение за установленную причину.
Исправление и повтор
Передайте задачу ответственному за слой, где зафиксировано первое расхождение. Для HTTP-перехода приложите исходный URL, hop, статус и Location. Для JavaScript — браузерный сценарий, конечный URL и наблюдение первого запроса счётчика. Для формы — ожидаемые и фактические значения в данных запроса. Для CRM — ID отправки, ID связанной записи и сохранённые поля либо отметку, что слой не проверен.
После исправления повторите все пять сценариев локального стенда и сохраните новый результат:
| Сценарий | Что перепроверить |
|---|---|
keep |
Ожидаемые параметры в каждом запросе, каждом Location и конечном URL. |
drop |
Переход /drop/middle → /landing; сверить, должны ли метки сохраняться на этом шаге или уже быть зафиксированы в нужном слое. |
js-loss |
В браузере проверить JavaScript-переход, первый запрос счётчика и конечный URL; HTTP-журнала для этого сценария недостаточно. |
clean |
Проверить, что адрес очищается после нужной фиксации, а значения остаются в требуемых слоях. |
form-loss |
Сопоставить первый запрос счётчика, данные разрешённой тестовой формы и связанную запись CRM; не приписывать расхождение HTTP-переходу, если его там нет. |
На реальном сайте повторите проверяемый путь с новым test_id и теми же ожидаемыми параметрами. Сравните исходный URL, переходы, первый запрос счётчика, данные формы и связанную запись CRM. Если слой недоступен, оставьте его непроверенным и укажите, какого свидетельства не хватает.
Для диагностики качества исходных данных пригодится материал «Почему данные врут тихо», а для сверки общей таблицы метрик — «Анализ маркетинговых данных с нейросетью».
Учебный пример
Это выполненный локальный прогон с синтетическими данными: не клиентский кейс, не полевой тест и не проверка качества модели. В журнале 9 HTTP-запросов по пяти сценариям. keep прошёл со статусами 302, 307, 200; drop — 302, 302, 200. Параметры пропали на /drop/middle → /landing. В отдельном браузерном прогоне /js-loss не передал utm_source в первый локальный hit; /clean сохранил demo в локальном hit и учебной форме после очистки адреса; /form-loss сохранил demo в локальном hit, но не в учебной форме. Внешних запросов аналитики не было.
Скачать архив с исходными URL, локальными HTTP-редиректами, CSV переходов, ожидаемыми параметрами, заполненным отчётом и отдельной инструкцией браузерной проверки JavaScript. Отдельные файлы: http-hops.csv, browser-results.csv, cases.csv.
Полный cases.csv:
case,start,expected_loss
keep,/keep/start,none
drop,/drop/start,second_redirect
js-loss,/js-loss,client_navigation_before_first_hit
clean,/clean,none_after_first_hit_url_clean
form-loss,/form-loss,form_payload_only
Проверенный результат локального прогона:
| Проверка | Результат |
|---|---|
HTTP-цепочки keep |
302 → 307 → 200; query сохранён |
HTTP-цепочки drop |
302 → 302 → 200; потеря на /drop/middle → /landing |
/js-loss |
Первый локальный hit не содержит utm_source; конечный URL — /landing |
/clean |
Конечный URL — /clean; первый hit и учебная форма содержат demo |
/form-loss |
Первый hit содержит demo, учебная форма — нет |
| Внешние запросы аналитики | 0 |
Чек-лист повторной проверки
- Сохранить
test_id, исходный URL, дату и время с часовым поясом, тестовую среду и ожидаемые UTM. - Записать каждый HTTP hop: URL запроса, статус,
Location, следующий URL и конечный адрес. - Проверить JavaScript отдельно в браузере с сохранённым журналом Network.
- Зафиксировать первый реальный запрос счётчика и только значения, видимые в нём.
- С разрешения отправить одну тестовую форму без персональных данных, заказа и оплаты; сохранить данные запроса, статус и ID отправки.
- Найти связанную разрешённую запись CRM по техническому ID и записать фактически сохранённые поля.
- Если нет доступа, ID, лога или связанной записи, отметить слой как «не проверен» и указать нужное свидетельство.
- Считать исчезновение из адреса нормальным только после подтверждения сохранения значений в требуемых слоях.
- После исправления повторить сценарий с новым
test_idи теми же ожидаемыми UTM. - Передать разработчику точный hop или поле, где наблюдаемое значение отличается от ожидаемого.

