Блог / Гайды

Как связать CRM, рекламные кабинеты и реальные продажи: архитектура сквозной аналитики

Разбирать сквозную аналитику на уровне «зачем это бизнесу» — одна задача, спроектировать её на уровне «как это реально построить» — совсем другая. Этот материал — для CTO, руководителей разработки и аналитиков, которым нужно не «зачем», а «как»: какие идентификаторы связывают рекламу с продажей, как принимать данные из разных систем, как их сшивать друг с другом и как убедиться, что пайплайн не врёт.

TL;DR

  • Сквозная аналитика — это не дашборд, а конвейер данных: источники → идентификаторы → приём (ingestion) → сопоставление (matching) → единая модель данных → отчётность.
  • Ключевая техническая задача — не визуализация, а identity resolution: сшить разрозненные ID (UTM, click ID, deal_id CRM) в одну цепочку «клик → лид → сделка → оплата».
  • Привязка CRM-заказа к визиту через клиентский идентификатор — это не самодельное решение, а задокументированный способ, который использует и официальная механика офлайн-конверсий Яндекс.Метрики.
  • Расходы на рекламу и события CRM живут по разным правилам ingestion: события — событийно (webhook), расходы — периодическим опросом (задержка в отчётности площадок — норма, а не баг).
  • Без контроля качества (дедупликация, реконсиляция, мониторинг свежести) даже правильно спроектированный пайплайн со временем начинает врать — незаметно и постепенно.

Архитектура целиком: из чего состоит система

Прежде чем говорить про конкретные ID и таблицы, полезно увидеть всю цепочку целиком — она состоит из пяти слоёв, и путаница между ними — частая причина, почему самодельные интеграции превращаются в нечитаемый код через полгода.

Источники → Идентификаторы → Ingestion → Matching → Единая модель данных → Отчётность/BI

  • Источники — рекламные кабинеты (Meta, Google, TikTok, Яндекс Директ), CRM (Bitrix24, amoCRM, собственная), платёжные системы, сайт/лендинг, мессенджеры.
  • Идентификаторы — метки, по которым события из разных источников можно связать друг с другом (разбор ниже).
  • Ingestion — механизм получения данных: webhook, периодический pull через API, ручной импорт файлом.
  • Matching — сопоставление событий из разных источников в одну цепочку по общему идентификатору.
  • Единая модель данных — хранилище, где данные из всех источников лежат в одной согласованной структуре, а не в пяти несовместимых форматах.
  • Отчётность/BI — то, что видит бизнес: дашборд, отчёт, AI-агент, отвечающий на вопросы по этим данным.

Ошибка, которую часто допускают при самостоятельном проектировании, — начинать сразу с дашборда, оставляя два первых слоя («идентификаторы» и «matching») неявными, на честном слове «как-нибудь сопоставим по имени и телефону». На практике именно эти два слоя определяют, будет ли система вообще давать верные цифры.

Идентификаторы: что на самом деле связывает рекламу с продажей

В основе всей архитектуры — набор идентификаторов разного уровня надёжности. Их стоит явно разделять, а не считать взаимозаменяемыми.

UTM-метки (utm_source, utm_campaign, utm_content и так далее) — самый простой и самый ненадёжный слой: это просто параметры ссылки, которые ничего не гарантируют сами по себе. Метка может потеряться при редиректе, не долететь до формы, быть скопирована вручную с ошибкой. Полезны как читаемый человеком разрез («какая кампания»), но не как единственный ключ для сопоставления записей.

Click ID платформы (gclid у Google, yclid у Яндекс Директа, fbclid/ctwa_clid у Meta) — гораздо надёжнее: это токен, который сама рекламная платформа выдаёт в момент клика и позже принимает обратно через свой API конверсий, чтобы засчитать событие именно этому объявлению. Для рекламы Click to WhatsApp ctwa_clid — единственный способ получить ad-level атрибуцию, и он доступен только через официальный WhatsApp Cloud API, а не через неофициальные способы подключения номера.

Клиентский идентификатор веб-аналитики (ClientID у Яндекс.Метрики, аналогичные cookie-based ID у GA4) — присваивается браузеру при первом визите на сайт. Именно через него системы веб-аналитики привязывают офлайн-конверсию из CRM обратно к конкретному визиту — это задокументированный основной механизм связки CRM-заказа с рекламой в самой Метрике, а не обходной приём.

Внутренний идентификатор сделки (deal_id/lead_id CRM) — точка, где заканчивается «рекламная» часть цепочки и начинается «продуктовая»: это то, что CRM использует сама для себя и что нужно явно связать с одним из идентификаторов выше в момент создания сделки, иначе связь потеряется навсегда.

Хешированные персональные данные (телефон, email — через SHA-256) — идентификатор последней инстанции для вероятностного матчинга, когда детерминированной связки (click ID или UTM) нет: например, клиент позвонил, а не написал, или ссылка потеряла метку. Менее точен, но лучше полного отсутствия атрибуции.

Правило простое: чем выше идентификатор в этом списке, тем он менее надёжен, но более универсален; чем ниже — тем точнее, но у́же по охвату. Хорошая архитектура использует связку сверху вниз: сначала пробует детерминированный click ID, и только если его нет — откатывается к вероятностному сопоставлению.

Ingestion: как данные вообще попадают в систему

Здесь чаще всего допускают вторую системную ошибку — пытаются принимать все источники одним и тем же способом. На практике у разных типов данных принципиально разная природа поступления.

События CRM (webhook, событийно). Смена статуса сделки, создание лида, факт оплаты — это дискретные события, которые должны долетать до пайплайна в момент, когда они произошли. Правильный способ — webhook от CRM в момент изменения записи, а не периодический опрос «а не изменилось ли что-то». Опрос добавляет задержку и лишнюю нагрузку на CRM без выгоды в точности.

Расходы и клики рекламных кабинетов (периодический pull через API аналитика рекламных данных). Здесь webhook почти никогда не подходит — большинство рекламных платформ просто не уведомляют о новых показах/кликах в реальном времени, а расходы за текущие сутки нередко пересчитываются и уточняются в течение 24–48 часов после списания. Правильная модель — регулярный (обычно ежедневный) pull через API кабинета, причём с повторным запросом за последние несколько дней, а не только за «вчера», чтобы подтянуть уточнённые цифры задним числом.

Данные оплат. Зависит от платёжной системы: у части есть webhook на успешную транзакцию, у части (типичный пример — локальные способы оплаты вроде Kaspi Pay без прямого эквайринга в CRM) — только выгрузка операций, которую нужно сверять с сделками по расписанию, а не в реальном времени.

Идемпотентность приёма — обязательное требование, а не опция. Webhook может продублироваться (повторная доставка при таймауте), а периодический pull может дважды забрать одну и ту же запись на границе временного окна. Каждое входящее событие должно иметь уникальный идентификатор, по которому повторная запись безопасно перезаписывает (upsert), а не дублирует существующую.

Matching: как сшить разрозненные ID в одну цепочку

Matching — это слой, который превращает набор разрозненных записей («клик по объявлению», «лид в CRM», «оплата») в одну цепочку событий одного и того же клиента. Здесь работают два принципиально разных подхода.

Детерминированный матчинг — сопоставление по точному общему ключу: click ID, переданный в поле сделки при её создании, или ClientID, привязанный к визиту. Даёт стопроцентную уверенность в связке, но требует, чтобы идентификатор физически дошёл до момента создания записи в CRM — то есть чтобы никто не потерял его по дороге (форма без скрытого поля под UTM, менеджер, вручную создающий сделку без привязки к источнику, и так далее).

Вероятностный матчинг — сопоставление по косвенным признакам: телефон, email, время обращения плюс единственная активная в этот момент кампания. Не даёт стопроцентной гарантии, но покрывает случаи, где детерминированного ключа нет вообще — например, звонок по номеру без call-tracking или переход по неофициальному подключению мессенджера, где рекламная платформа не передаёт click ID в принципе.

Окно атрибуции — отдельный параметр, который нужно зафиксировать явно: сколько времени между кликом и конверсией засчитывать как связанные события (типичные значения — 1, 7 или 28 дней). Без явного окна разные части системы (рекламный кабинет, CRM-отчёт, дашборд) могут считать одну и ту же воронку по-разному и давать несовпадающие цифры — не потому что где-то ошибка, а потому что у окон атрибуции разное значение по умолчанию. Сам выбор модели распределения заслуги между несколькими касаниями (first click, last click, линейная и другие) — тема отдельного разбора на конкретном числовом примере в статье «Модели атрибуции: какую выбрать бизнесу».

Единая модель данных

Итог слоёв matching и ingestion должен лечь в структуру, где данные разной природы можно объединять по общим измерениям (дата, канал, кампания) без ручных сверок каждый раз. На практике для сквозной аналитики достаточно четырёх сущностей:

  • Расходы (spend) — дата, канал, кампания/объявление, сумма расхода, число показов и кликов — из рекламных API.
  • Лиды (leads) — дата, канал/кампания (через сопоставленный идентификатор), исходный контакт — из CRM/сайта/мессенджера.
  • Сделки и статусы (deals) — история смены стадий воронки для каждого лида — из CRM.
  • Оплаты (payments) — сумма, валюта, дата, привязка к сделке — из CRM или платёжной системы.

Эти четыре таблицы объединяются через цепочку идентификаторов из раздела выше: campaign_id/click_id → lead_id → deal_id → payment_id. Для отчётности их обычно агрегируют в одну плоскую таблицу «по дням и каналам» — не потому что нормализованная модель хуже, а потому что для дашборда и для вопросов вида «сколько принёс канал X за период Y» плоская агрегированная витрина читается быстрее и проще, чем джойн из четырёх таблиц на каждый запрос. У нас в Cheat Code эта агрегация считается ежедневно кроном в единую таблицу, из которой уже строится и дашборд, и ответы AI-агента на произвольные вопросы.

Важный принцип проектирования — не терять сырые данные ради удобной агрегированной витрины. Сырые события (raw layer) стоит хранить отдельно и не перезаписывать: если позже выяснится ошибка в логике агрегации, витрину можно пересчитать заново из сырых данных — а вот восстановить сырые события из уже агрегированной таблицы, как правило, невозможно.

Контроль качества данных

Работающий пайплайн и корректный пайплайн — не одно и то же: данные могут исправно течь и при этом постепенно расходиться с реальностью. Минимальный набор проверок:

  • Дедупликация по event_id. Каждое событие (клик, лид, статус, оплата) должно иметь уникальный идентификатор, по которому повторная обработка не создаёт вторую запись — иначе задвоение накапливается незаметно, особенно при повторных webhook-доставках.
  • Реконсиляция (сверка агрегатов). Периодически (например, раз в сутки) сравнивать итоговые суммы в пайплайне с исходными системами: сумма расходов в дашборде должна совпадать с суммой в кабинете рекламодателя, число оплаченных сделок — с CRM. Расхождение — сигнал, что где-то в цепочке ingestion/matching есть пропуск.
  • Мониторинг свежести данных (freshness). Отдельный алерт на случай, если ожидаемое обновление (например, вчерашние расходы) не пришло вовремя — без этого пайплайн может молча стоять несколько дней, и первым, кто это заметит, окажется не инженер, а бизнес, удивлённый пустым отчётом.
  • Обработка late-arriving данных. Часть событий (уточнённые расходы, поздно подтверждённые оплаты) приходит с задержкой в несколько дней — пайплайн должен уметь пересчитывать уже закрытые периоды, а не просто дописывать новые дни поверх.
  • Контроль дрейфа схемы. Рекламные API и CRM время от времени меняют формат ответа (переименование поля, новый обязательный параметр) — без валидации входящих данных такое изменение тихо ломает часть пайплайна, и это обнаруживается постфактум, по жалобе на неверные цифры.

Без этого слоя даже безупречно спроектированная на бумаге архитектура через несколько месяцев в проде начинает расходиться с реальностью — не из-за ошибки в дизайне, а потому что источники данных сами меняются со временем, а контроля за этими изменениями никто не поставил.

Итог

Сквозная аналитика на уровне архитектуры — это не про выбор BI-инструмента для дашборда, а про пять слоёв, которые должны быть спроектированы осознанно: идентификаторы для связки записей, разделение ingestion на событийный и периодический потоки, matching с явным окном атрибуции, единая модель данных, которая не теряет сырые события, и контроль качества, который ловит расхождения раньше, чем их заметит бизнес. Дашборд — это последний, самый заметный слой, но большая часть реальной инженерной работы и большая часть возможных ошибок находятся в трёх слоях до него.

Частые вопросы

Webhook или периодический опрос API — что использовать для приёма данных из CRM?

Для событий CRM (смена статуса сделки, оплата) — webhook: событие приходит сразу, без задержки и без лишней нагрузки на CRM опросами. Периодический pull имеет смысл как страховка на случай пропущенных webhook'ов (сверка раз в сутки) и обязателен для расходов на рекламу — большинство рекламных API просто не поддерживают push-уведомления о новых кликах.

Что делать, если у канала в принципе нет click ID — например, звонок или офлайн-визит?

Переходить на вероятностный матчинг: по номеру телефона (если он попал в CRM и связан с конкретным объявлением через call-tracking) или по времени и источнику, если активна одна кампания за раз. Это менее точно, чем детерминированное сопоставление по click ID, но лучше, чем полное отсутствие атрибуции.

Нужна ли отдельная база данных для сквозной аналитики или достаточно таблиц внутри CRM?

Для одного канала и небольшого объёма данных можно обойтись отчётами внутри CRM. Как только источников становится больше двух-трёх и нужно объединять данные разной природы (расходы, лиды, сделки, оплаты) в одной модели — отдельное хранилище, пусть даже простое, почти всегда быстрее и надёжнее, чем растягивать под эту задачу саму CRM.

Как часто нужно обновлять данные о расходах на рекламу?

Раз в сутки обычно достаточно для большинства бизнесов — большинство рекламных кабинетов сами досчитывают точные цифры расхода и атрибуции с задержкой до 24–48 часов, поэтому более частое обновление часто просто гоняет предварительные, ещё не финализированные данные.

Что делать, если один лид пришёл через два разных канала (несколько касаний)?

Выбрать модель атрибуции заранее, а не постфактум: last click (вся ценность — последнему касанию), first click (первому) или линейная (распределяется поровну). Для большинства малых и средних воронок практичнее last click — она проще в реализации и достаточно точна, если между касаниями нет долгого разрыва.

Похожие статьи

Гайды

Сквозная аналитика: что это и как работает в 2026

Гайды

Почему вы сливаете рекламный бюджет: 7 дыр в аналитике

Гайды

Как отследить, откуда пришёл клиент в WhatsApp: гайд по сквозной аналитике

Ко всем статьям →