UTM-разметка: почему у тебя бардак в аналитике и как это починить
Разбираем типичные ошибки UTM-разметки, даём готовую конвенцию именования и SQL-запрос для очистки данных в ClickHouse.
Открой свой отчёт по каналам. Видишь там google, Google, GOOGLE, google.com и гугл — всё как отдельные источники? Поздравляю, у тебя UTM-ад. И ты теряешь деньги, потому что не понимаешь, какой канал реально работает.
Масштаб проблемы
Я видел аккаунты, где один и тот же канал размазан по 15-20 строкам отчёта из-за разных вариантов написания. Маркетолог запускает кампанию с utm_source=facebook, таргетолог пишет utm_source=Facebook, а агентство вообще ставит utm_source=fb. В итоге в отчёте три строки вместо одной, бюджет «размывается», и ты принимаешь решения на мусорных данных.
Реальный пример. Интернет-магазин тратит 2 млн в месяц на рекламу. Из-за хаотичной UTM-разметки 30% трафика атрибутируется неправильно. Это как выбросить 600 тысяч рублей и не знать куда.
Топ-5 ошибок, которые убивают твою аналитику
1. Разный регистр
UTM-параметры регистрозависимы. utm_source=Google и utm_source=google — это две разные строки в отчёте. Всегда используй нижний регистр.
2. Нет единой конвенции
Один пишет email, другой e-mail, третий newsletter. Без правил каждый будет творить что хочет.
3. Кириллица и пробелы
utm_campaign=весенняя распродажа — это кошмар. Пробелы превращаются в %20, кириллица кодируется в нечитаемую кашу. Только латиница, только дефисы.
4. Отсутствие utm_campaign
Многие ставят только source и medium, забывая campaign. В итоге ты знаешь, что трафик пришёл из Яндекс.Директ, но не знаешь из какой кампании. Бесполезно.
5. UTM на внутренних ссылках
Ставишь UTM на баннер внутри сайта — и перезаписываешь оригинальный источник визита. Человек пришёл из рекламы, кликнул по баннеру на главной, и теперь его источник — internal_banner. Атрибуция сломана.
Конвенция именования: бери и используй
Вот готовый шаблон. Распечатай, повесь на стену, отправь всей команде:
| Параметр | Формат | Пример |
|---|---|---|
utm_source | платформа, lowercase | yandex, google, vk, telegram |
utm_medium | тип трафика | cpc, cpm, email, social, referral |
utm_campaign | YYYYMM_категория_название | 202603_promo_spring-sale |
utm_content | формат или вариант | banner_1200x628, text_v2 |
utm_term | ключевое слово (для поиска) | купить_кроссовки |
Правила:
- Только нижний регистр
- Только латиница
- Разделитель слов — дефис (
-), разделитель сегментов — нижнее подчёркивание (_) - Дата в начале campaign для быстрой сортировки
- Никаких пробелов, кириллицы, спецсимволов
Как выглядит бардак vs порядок
До (хаос):
| utm_source | utm_medium | sessions |
|---|---|---|
| cpc | 1,200 | |
| CPC | 800 | |
| google.com | paid | 350 |
| Гугл | cpc | 150 |
Четыре строки, и ты думаешь, что Google приносит 1,200 визитов. На самом деле — 2,500.
После (порядок):
| utm_source | utm_medium | sessions |
|---|---|---|
| cpc | 2,500 |
Одна строка. Чистая картина. Правильные решения.
SQL: находим и чистим UTM-мусор в ClickHouse
Сначала найдём масштаб бедствия — все вариации одного и того же источника:
-- Находим дубликаты utm_source по нижнему региструSELECT lower(utm_source) AS source_normalized, groupArray(DISTINCT utm_source) AS variants, length(groupArray(DISTINCT utm_source)) AS variant_count, COUNT(*) AS total_sessionsFROM marketing_eventsWHERE utm_source != '' AND event_date >= today() - 90GROUP BY source_normalizedHAVING variant_count > 1ORDER BY total_sessions DESC;Этот запрос покажет, например: google имеет варианты ['Google', 'google', 'GOOGLE', 'google.com'] — 4 варианта, 15,000 сессий с мусорной разметкой.
Теперь создадим маппинг для очистки:
-- Создаём словарь нормализацииCREATE TABLE utm_normalization ( raw_value String, normalized_value String) ENGINE = MergeTree()ORDER BY raw_value;
INSERT INTO utm_normalization VALUES ('Google', 'google'), ('GOOGLE', 'google'), ('google.com', 'google'), ('Facebook', 'facebook'), ('FB', 'facebook'), ('fb', 'facebook'), ('ВКонтакте', 'vk'), ('vkontakte', 'vk');И используем при построении отчётов:
-- Чистый отчёт с нормализованными UTMSELECT coalesce( n.normalized_value, lower(m.utm_source) ) AS source_clean, lower(m.utm_medium) AS medium_clean, COUNT(DISTINCT m.user_id) AS users, countIf(m.event_type = 'purchase') AS purchases, sumIf(m.revenue, m.event_type = 'purchase') AS revenue, round( countIf(m.event_type = 'purchase') / COUNT(DISTINCT m.user_id) * 100, 2 ) AS conversion_rateFROM marketing_events mLEFT JOIN utm_normalization n ON m.utm_source = n.raw_valueWHERE m.event_date >= today() - 30GROUP BY source_clean, medium_cleanORDER BY revenue DESC;Как не допустить этого снова
-
Генератор UTM. Сделай Google-таблицу с выпадающими списками и формулой, которая собирает URL. Никто не вбивает UTM руками.
-
Валидация на входе. Если у тебя свой трекер или посадочные на своей платформе — проверяй UTM при приёме. Отвергай кириллицу, заглавные буквы, пробелы.
-
Еженедельный аудит. Запускай SQL-запрос выше раз в неделю. Новые мусорные варианты появляются постоянно, особенно когда подключаются новые подрядчики.
-
Документация. Одна страница в Notion с правилами разметки. Отправляй каждому новому подрядчику и сотруднику до начала работы.
Итого
UTM-разметка — это не скучная бюрократия. Это фундамент твоей аналитики. Если фундамент кривой, всё остальное — отчёты, дашборды, решения о бюджетах — тоже будет кривым. Потрать один день на наведение порядка, и ты будешь экономить часы каждую неделю.
Нравится контент? Подписывайся на Telegram
SQL-задачки, кейсы из практики и закулисье аналитики.
Похожие статьи
Анализ воронки на чистом SQL: от визита до покупки
Строим полный анализ воронки конверсий в ClickHouse: расчёт CR между шагами, поиск узких мест, когортные воронки.
Яндекс Метрика vs GA4: честное сравнение для тех, кто работает
Сравниваем Метрику и GA4 по 13 критериям: где какая сильнее, когда хватит одной и как работать с двумя без хаоса.
Оконные функции SQL: полное руководство с примерами
Разбираем ROW_NUMBER, RANK, LAG, LEAD и другие оконные функции на практических примерах из маркетинговой аналитики.