Типичная картина. На сайте стоит виджет Битрикс24, в карточке лида есть блок «Сквозная аналитика», отчёты в CRM открываются. А источника у половины заявок нет — или написано «Прочий трафик», что по смыслу то же самое.
Дальше обычно начинают проверять настройки рекламы и метки, хотя дело почти всегда в другом: в том, что именно попадает в трек визита и доезжает ли он до лида. Разберём по шагам, с кодом.
Как это устроено
В сквозной аналитике Битрикс24 три сущности, и путаница между ними и создаёт большинство проблем.
- Визит — посещение сайта. Его записывает виджет, который вы ставите на страницы.
- Трек (
trace) — строка с данными визита: адрес входа, метки, идентификаторы рекламных систем. Это пропуск, по которому портал связывает визит с заявкой. - Лид или сделка — то, что создаётся в CRM. У него есть собственные поля
UTM_SOURCE,UTM_MEDIUMи остальные.
Отчёты строятся по связке визита и лида. Нет трека — связи нет, и в отчёте заявка висит без источника, даже если поля UTM_* у неё заполнены.
Что виджет кладёт в трек
Здесь главная неожиданность. Откройте на своём сайте консоль браузера и выполните:
b24Tracker.guest.getTrace()
Для обычного перехода — например, из поиска — ответ будет примерно такой:
{
"url": "https://example.ru/uslugi/",
"device": { "isMobile": false },
"tags": { "ts": 1794077250, "list": {}, "gclid": null },
"client": { "yaId": 82521196 },
"pages": { "list": [["https://example.ru/uslugi/", 1794077251, "Услуги"]] },
"gid": null,
"previous": { "list": [] }
}
Обратите внимание на tags.list — он пустой. Виджет записывает туда только то, что было в адресе страницы: utm_source, utm_medium, yclid, gclid и прочие метки.
А теперь посчитайте, сколько ваших посетителей приходит с метками. Реклама — да. Всё остальное — нет:
- органика из Яндекса и Google;
- переходы из нейросетей и ассистентов с поиском;
- переходы по ссылкам из соцсетей, мессенджеров и чужих статей;
- прямые заходы и переходы из закладок.
У всех этих визитов трек уходит с пустым tags.list. Реферер виджет в трек не кладёт — хотя браузер его знает. Так и появляется «Прочий трафик» в отчётах.
Три способа принимать заявки — и что с источником в каждом
CRM-формы Битрикс24
Самый простой случай: форма сделана в портале и встроена на сайт кодом вида b24form. Источник подтягивается сам, потому что форма и трекер — части одной системы.
Ограничение тоже понятное: форма выглядит как форма Битрикс24, а не как ваш сайт, и вёрстка настраивается в узких рамках. Если это устраивает — остальная статья вам не нужна.
Свои формы с отправкой на сервер
Как только форма своя, а заявка уходит через crm.lead.add, связь с визитом теряется: портал не знает, что обращение относится к тому самому визиту. Трек нужно взять на странице и передать вместе с заявкой.
На клиенте:
var trace = '';
try {
if (window.b24Tracker && window.b24Tracker.guest && window.b24Tracker.guest.getTrace) {
trace = window.b24Tracker.guest.getTrace();
}
} catch (e) {}
fetch('/api/lead/', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: name, phone: phone, trace: trace })
});
Проверка через try обязательна: виджет грузится асинхронно и может быть ещё не готов, а падение скрипта в этот момент утащит за собой отправку формы.
На сервере трек идёт рядом с полями, а не внутри них. Это частая ошибка: поля TRACE среди полей лида нет, портал ждёт отдельный параметр:
$payload = [
'fields' => [
'TITLE' => 'Заявка с сайта',
'NAME' => $name,
'PHONE' => [['VALUE' => $phone, 'VALUE_TYPE' => 'WORK']],
],
'params' => ['REGISTER_SONET_EVENT' => 'N'],
];
if ($trace !== '') {
$payload['trace'] = $trace;
}
$http = new \Bitrix\Main\Web\HttpClient(['socketTimeout' => 10, 'waitResponse' => true]);
$response = $http->post($webhook, $payload);
Заявка уже создана, а трек появился позже
Бывает, что лид создаётся на стороне — из колл-центра, из чужой CMS, из обработки письма. Привязать визит можно отдельным вызовом:
crm.tracking.trace.add
{
"TRACE": "{\"tags\":{\"list\":{\"utm_source\":\"perplexity.ai\"}}}",
"ENTITIES": [{ "TYPE": "LEAD", "ID": 19610 }]
}
Метод принимает трек строкой и связывает его с объектом CRM. Важное следствие: трек можно собрать самостоятельно — достаточно положить метки в tags.list. Этим мы и воспользуемся дальше.
Как размечать переходы без меток
Теперь к главному. Раз виджет не кладёт реферер в трек, положим его сами — и в поля лида, и в сам трек.
Шаг 1. Запомнить первое касание
Клиент редко оставляет заявку на первом визите: пришёл из поиска, ушёл, вернулся через неделю напрямую. Если брать источник в момент отправки формы, все такие заявки станут прямыми заходами. Поэтому первое касание запоминаем:
var KEY = 'src_first';
var FIELDS = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term'];
function current() {
var params = new URLSearchParams(location.search);
var data = { at: Date.now(), page: location.pathname };
var hasUtm = false;
FIELDS.concat(['yclid', 'gclid', 'ysclid']).forEach(function (f) {
var v = params.get(f);
if (v) { data[f] = v.slice(0, 200); hasUtm = true; }
});
var ref = document.referrer || '';
if (ref && ref.indexOf(location.origin) !== 0) {
data.referrer = ref.slice(0, 300);
}
return (hasUtm || data.referrer) ? data : null;
}
var now = current();
var first = null;
try { first = JSON.parse(localStorage.getItem(KEY) || 'null'); } catch (e) {}
if (now && !first) {
try { localStorage.setItem(KEY, JSON.stringify(now)); } catch (e) {}
first = now;
}
Проверка ref.indexOf(location.origin) !== 0 отсекает переходы внутри сайта: без неё реферером окажется ваша же предыдущая страница.
Обращения к localStorage обёрнуты в try не для красоты: в режиме инкогнито и при запрете хранилища он бросает исключение, и форма перестанет отправляться.
Шаг 2. Вывести источник из реферера
На сервере: если меток нет, берём хост реферера. Нейросети имеет смысл выделить в отдельный канал — это не обычный переход по ссылке и не органика поисковика, а ответ ассистента, где вас порекомендовали. Смешаете с остальным — не увидите, работает ли подготовка сайта к AI-поиску.
function sourceFromReferrer(string $referrer): array
{
$host = mb_strtolower((string)parse_url(trim($referrer), PHP_URL_HOST));
$host = preg_replace('~^www\\.~', '', $host);
if ($host === '') {
return ['direct', 'none'];
}
/* проверяем до поисковиков: gemini живёт на поддомене google.com */
$ai = ['perplexity.ai', 'chatgpt.com', 'chat.openai.com', 'openai.com',
'claude.ai', 'gemini.google.com', 'copilot.microsoft.com',
'you.com', 'phind.com'];
foreach ($ai as $known) {
if ($host === $known || str_ends_with($host, '.'.$known)) {
return [$host, 'ai'];
}
}
$search = ['yandex.ru', 'ya.ru', 'google.com', 'google.ru',
'bing.com', 'duckduckgo.com', 'mail.ru', 'rambler.ru'];
foreach ($search as $known) {
if ($host === $known || str_ends_with($host, '.'.$known)) {
return [$host, 'organic'];
}
}
$social = ['vk.com', 't.me', 'ok.ru', 'dzen.ru', 'vc.ru', 'habr.com'];
foreach ($social as $known) {
if ($host === $known || str_ends_with($host, '.'.$known)) {
return [$host, 'social'];
}
}
return [$host, 'referral'];
}
Порядок проверок важен: gemini.google.com — поддомен google.com, и если сначала проверять поисковики, переходы из Gemini уедут в органику Google.
Шаг 3. Заполнить поля лида
if (empty($fields['UTM_SOURCE'])) {
[$source, $medium] = sourceFromReferrer($referrer);
$fields['UTM_SOURCE'] = $source;
if (empty($fields['UTM_MEDIUM'])) {
$fields['UTM_MEDIUM'] = $medium;
}
}
Шаг 4. Дописать метки в трек
Полей лида мало: отчёты сквозной аналитики строятся по треку. Дописываем метки туда же, своё не затирая:
function traceWithTags(string $trace, array $tags): string
{
$tags = array_filter($tags, static fn($v): bool => trim((string)$v) !== '');
if ($trace === '' || !$tags) {
return $trace;
}
$data = json_decode($trace, true);
if (!is_array($data)) {
return $trace;
}
$list = (array)($data['tags']['list'] ?? []);
foreach ($tags as $key => $value) {
if (trim((string)($list[$key] ?? '')) === '') {
$list[$key] = mb_substr((string)$value, 0, 200);
}
}
$data['tags']['list'] = $list;
$json = json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
return is_string($json) ? $json : $trace;
}
Условие trim(...) === '' нужно, чтобы не перебить настоящие метки рекламы: если человек пришёл по объявлению, в треке уже есть utm_source из адреса, и он точнее любого реферера.
Виджет грузится отложенно — и это ломает трек
Виджет Битрикс24 весит прилично, поэтому его часто подключают отложенно: через пару секунд после загрузки страницы или по первому действию посетителя. Приём правильный, скорость он экономит заметно.
var loaded = false;
function loadWidget() {
if (loaded) { return; }
loaded = true;
var s = document.createElement('script');
s.async = true;
s.src = 'https://portal.bitrix24.ru/upload/crm/site_button/loader_X_xxxx.js?' + (Date.now() / 60000 | 0);
document.body.appendChild(s);
}
['scroll', 'pointerdown', 'keydown', 'touchstart'].forEach(function (e) {
window.addEventListener(e, loadWidget, { once: true, passive: true });
});
window.addEventListener('load', function () { window.setTimeout(loadWidget, 1500); });
Побочный эффект: b24Tracker появляется только после загрузки виджета. Посетитель, который открыл страницу и сразу отправил форму, уйдёт без трека.
Что с этим делать. Если форма простая и заполняется за десять секунд — грузить виджет сразу на страницах с формой, а отложенную загрузку оставить на остальных. Если формы длинные, квиз или калькулятор — отложенная загрузка не мешает, трекер успевает подняться. И в любом случае поля UTM_* у лида заполняются независимо от трека: даже без связи с визитом источник в карточке будет виден.
Как проверить, что всё работает
- Откройте сайт в режиме инкогнито, перейдя по ссылке с меткой:
?utm_source=test&utm_medium=check. - Проскролльте страницу — виджет должен загрузиться.
- В консоли выполните
b24Tracker.guest.getTrace()и убедитесь, что вtags.listпоявились ваши метки. - Отправьте тестовую заявку.
- Откройте лид в портале: в полях должны быть
UTM_SOURCEиUTM_MEDIUM, а в блоке «Сквозная аналитика» — строка с источником, а не «Прочий трафик». - Повторите без меток, перейдя на сайт из поиска. Источник должен определиться по рефереру.
Шестой пункт и есть проверка на то, ради чего всё делалось: с метками работает у всех, без меток — почти ни у кого.
Частые ошибки
Трек передают внутри полей лида. Поля TRACE у лида нет, портал ждёт отдельный параметр рядом с fields. Заявка создастся, ошибки не будет, связи с визитом — тоже.
Берут последнее касание вместо первого. Тогда клиент, который пришёл из рекламы, подумал неделю и вернулся напрямую, будет записан как прямой заход, а реклама останется без заявки. Храните первое касание и передавайте его.
Считают, что виджет закрывает всё. Он закрывает визиты и свои формы. Своя форма, звонок с сайта через стороннюю телефонию, заявка из чужого сервиса — это отдельная работа.
Проверяют только рекламу. Реклама приходит с метками и выглядит нормально. Дыра обнаруживается на органике и на переходах из соцсетей, то есть там, куда смотрят реже.
Зачем это нужно
Пока источник не определяется, сквозная аналитика показывает не картину, а её часть — ту, за которую вы платите рекламой. Выводы из такого отчёта предсказуемые: платные каналы приносят заявки, остальное не приносит ничего.
Простой пример из нашей практики: первая заявка с обновлённого сайта пришла переходом из нейросети, от компании с несколькими сотнями сотрудников. В отчёте она была бы «прочим трафиком» и не повлияла бы ни на одно решение. После разметки стало видно, что канал работает — и в него есть смысл вкладываться дальше. Эту историю целиком — что делали две недели и почему источник у заявки не определился — мы разобрали в отдельном материале на vc.ru.
Если ковыряться в этом некогда, настройку сквозной аналитики мы делаем под ключ: подключаем трекер и формы, разбираем источники, сверяем цифры с Метрикой и показываем, где отчёт врёт и почему.
Экспресс-аудит проверит разметку, счётчики и техническую часть сайта — за минуту, бесплатно и без доступов.
Проверить сайтСтатья была полезна?
Частые вопросы
Почему в карточке лида написано «Прочий трафик»?
Значит трек до лида дошёл, но меток в нём не было. Так происходит со всеми переходами без UTM: из поиска, из соцсетей, из нейросетей, по прямому заходу. Виджет кладёт в трек только то, что было в адресе страницы, а реферер — не кладёт. Лечится тем, что источник выводят из реферера и дописывают в трек самостоятельно.
Нужен ли виджет, если формы свои?
Желательно: без него не будет ни визитов, ни трека, и сквозная аналитика останется без той половины данных, которая про поведение на сайте. Поля UTM у лида можно заполнять и без виджета — источник в карточке будет виден, но связь с визитом не построится.
Можно ли собрать трек вручную, без виджета?
Да. Метод crm.tracking.trace.add принимает строку трека и привязывает её к лиду или сделке; метки передаются в объекте tags.list. Это рабочий путь для заявок, которые создаются вне сайта, — из колл-центра или из чужой системы.
Что делать с переходами из нейросетей?
Выделять в отдельный канал. Ассистенты приходят без меток и по рефереру определяются как обычные переходы по ссылке, из-за чего теряются среди прочего трафика. Отдельный канал показывает, окупается ли подготовка сайта к AI-поиску. Часть ассистентов реферер не передаёт вовсе — такие визиты останутся прямыми заходами, и с этим ничего не сделать.
Почему метки есть в Метрике, но нет в Битрикс24?
Счётчик Метрики срабатывает при загрузке страницы, а трек Битрикс24 собирается виджетом, который часто подключают отложенно. Если заявку отправили раньше, чем виджет загрузился, трека не будет. На страницах с формами виджет стоит грузить сразу.