Расхождение начинается не в отчёте
Финансовый отчёт CRM показывает 8,4 млн рублей за месяц, а в GA4 — 7,7 млн. Маркетинг видит недополученную атрибуцию, финансы — потерянные заказы, разработчики проверяют purchase на странице благодарности. Но проблема редко в одном теге: системы могут честно считать разные факты.
GA4 фиксирует отправку события, CRM — подтверждённую оплату, бухгалтерия — возврат датой проведения операции. Пока команды не договорились, какой заказ и в какой момент считать выручкой, сверка будет спором двух калькуляторов. Диагностируйте расхождение не по месячному итогу, а от строки заказа к строке: transaction_id в GA4 и order_id в CRM отделяют потерю событий от различий учёта.
Почему одинаковая продажа даёт разные суммы
CRM может создать заказ, затем менять его статус на «оплачен», «отгружен», «возвращён». GA4 видит только отправленные сайтом или приложением события. Если purchase ушёл при нажатии «Оплатить», а банк отклонил платёж, GA4 покажет покупку без денег в CRM.
Обратная ситуация: оплата прошла по ссылке из письма, через менеджера, кассу или повторный сценарий без открытия страницы подтверждения. CRM запишет деньги, но браузер не отправит purchase; для GA4 сигнала о заказе не было.
Различается и состав суммы. В value GA4 могут передавать доставку, скидку или налог, а CRM — оплаченные товары без НДС. В подписках CRM способна записать годовой счёт при выставлении, а GA4 получить событие после первого платежа. Продажная CRM, шлюз, ERP и бухгалтерия также хранят разные статусы и даты. Выгрузка выставленных счетов не сравнима с purchase без фильтра: сначала назовите систему, отвечающую на вопрос «сколько денег реально получено за период?».
Один заказ проходит через три времени
У покупки есть минимум три даты: event time — отправка события в GA4, processing time — его обработка платформой, payment time — успешная оплата или иной выбранный бизнес-момент в CRM. Смешивать их в календарном фильтре нельзя.
Покупатель оплатил заказ в 23:58 по Москве, сервер получил подтверждение в 00:03, браузер открыл страницу успеха в 00:05. При часовом поясе GA4 UTC и CRM Europe/Moscow заказ попадёт в разные даты. За месяц эффект обычно сглаживается, но на границах периода, в ежедневных отчётах и во время акций создаёт шум.
События могут доставляться с задержкой: клиент закрыл вкладку, приложение работало офлайн, серверный контейнер повторил отправку после ошибки. Сверяйте период, для которого обе системы закрыли загрузку; длина буфера зависит от платежного процесса и способа отправки. В правилах зафиксируйте часовой пояс, границы суток и дату признания выручки: «заказы за март» без этого почти гарантируют спор в апреле.
Сверка начинается с пары идентификаторов
Первый файл — таблица, где одна строка описывает один order_id и содержит значения, влияющие на признание выручки. Без стабильного transaction_id сопоставление по сумме, email или времени платежа годится лишь для гипотезы: два клиента могут купить одинаковый товар на одинаковую сумму.
| transaction_id / order_id | GA4: события и сумма | CRM: статус и сумма | Класс расхождения | Что проверить |
|---|---|---|---|---|
| A-10482 | 1 / 12 500 RUB | paid / 12 500 RUB | совпадение | оставить в контрольной выборке |
| A-10483 | нет | paid / 8 900 RUB | пропуск GA4 | путь оплаты, блокировщики, серверную отправку |
| A-10484 | 2 / 15 000 RUB | paid / 7 500 RUB | дубль GA4 | повтор purchase, перезагрузку страницы |
| A-10485 | 1 / 120 USD | paid / 10 800 RUB | валюта или курс | код валюты и правило конвертации |
| A-10486 | 1 / 6 000 RUB | refunded / 6 000 RUB | возврат | событие возврата и дату возврата |
Добавьте event_timestamp, время платежа, валюту, стоимость товаров, скидку, доставку, налог, идентификатор платежа и статус возврата. Не скрывайте пустые поля: отсутствие transaction_id в GA4, заказа в CRM или валюты уже классифицирует проблему.
Проверяйте в обе стороны: найдите в GA4 все оплаченные order_id CRM — это пропуски аналитики; затем найдите в CRM все purchase GA4 — это дубли, тестовые покупки, события до оплаты и ошибочные идентификаторы. Односторонняя сверка видит только половину расхождений.
Правило выручки меняет результат сильнее тега
До проверки кода выберите модель. Для e-commerce обычно сравнивают успешно оплаченные заказы по дате оплаты за вычетом возвратов по дате возврата. Тогда GA4 должна получать purchase после подтверждения оплаты и отдельный возврат с тем же transaction_id. Без возвратов её выручка отражает первоначальные заказы, а не чистую выручку.
Для оценки оформления GA4 может считать подтверждённые клиентом заказы, а CRM — созданные заявки. Это полезно для воронки оплаты, но не для денежной выручки. В подписках и B2B CRM признаёт оплату счёта, а GA4 — продуктовую или веб-конверсию; между фактами проходят дни, иногда событие сайта не происходит вовсе.
Пример: за неделю CRM получила 100 000 рублей по оплаченным заказам; в сумме 8 000 рублей доставки, 12 000 рублей налога и 5 000 рублей возвратов, проведённых в ту же неделю. Если GA4 передала только товары до налога и доставки и не передала возвраты, она покажет 85 000 рублей. Это не обязательно потеря: CRM считает 100 000 − 5 000 = 95 000 рублей чистых поступлений, а GA4 — товарную стоимость до доплат. Сначала приведите состав суммы к одному правилу.
Для валют выберите одну валюту сверки, источник курса, момент конвертации и округление. Сравнивать value=120 и currency=USD с рублёвой CRM-суммой без этих правил нельзя. При платеже в валюте клиента и возврате в другой день курсовая разница не обязана быть багом.
Пять проверок до правки интеграции
Не переписывайте purchase, пока не классифицированы строки: серверное событие при сохранённом браузерном способно удвоить проблему.
- Проверьте уникальность. Группируйте GA4 по
transaction_id: для завершённого заказа ожидается одинpurchase, если нет частичной оплаты. Дубли дают перезагрузка, два контейнера, повтор после тайм-аута и отсутствие дедупликации браузера и сервера. - Найдите пропуски в обе стороны. Посчитайте оплаченные
order_idCRM без GA4 иtransaction_idGA4 без CRM. Проверьте тестовые домены, внутренние и ручные платежи, оплату без возврата на сайт, фильтры выгрузки. - Разложите сумму. Сопоставьте товары, скидки, доставку, налоги, чаевые и комиссии.
valueдолжно следовать письменному правилу, а не реализации конкретной страницы. - Сверьте валюту и округление. Сначала сравнивайте коды валют. Копейка или цент могут появиться при округлении строк; расхождение в сотни раз обычно означает неверную валюту или минорные единицы.
- Проверьте возвраты и даты. Уточните отмену до списания, частичные возвраты, chargeback и дату отражения возврата. Для GA4 нужен согласованный способ передать корректировку.
Не сводите объяснимый остаток к нулю любой ценой: его могут составлять задержки, платежи вне сайта и разница даты заказа и денег. Цель — объяснимая, а не косметически нулевая разница.
SQL превращает спор в классы причин
Для регулярной сверки используйте полный внешний join GA4 BigQuery и витрины CRM. Имена таблиц иллюстративны, поля нужно сопоставить со своей схемой.
WITH ga4_orders AS (
SELECT
ecommerce.transaction_id AS order_id,
COUNT(*) AS purchase_events,
SUM(ecommerce.purchase_revenue) AS ga4_revenue,
ANY_VALUE(currency) AS ga4_currency,
MIN(TIMESTAMP_MICROS(event_timestamp)) AS first_event_time
FROM `ga4_export.events_*`
WHERE event_name = 'purchase'
AND ecommerce.transaction_id IS NOT NULL
GROUP BY 1
),
crm_orders AS (
SELECT
order_id,
COUNT(*) AS crm_rows,
SUM(paid_amount) AS crm_revenue,
ANY_VALUE(currency_code) AS crm_currency,
MIN(paid_at) AS payment_time
FROM `crm_mart.orders`
WHERE payment_status = 'paid'
GROUP BY 1
)
SELECT
COALESCE(g.order_id, c.order_id) AS order_id,
g.purchase_events, c.crm_rows,
g.ga4_revenue, c.crm_revenue,
g.ga4_currency, c.crm_currency,
g.first_event_time, c.payment_time,
CASE
WHEN c.order_id IS NULL THEN 'есть в GA4, нет в CRM'
WHEN g.order_id IS NULL THEN 'есть в CRM, нет в GA4'
WHEN g.purchase_events > 1 THEN 'дубль purchase в GA4'
WHEN g.ga4_currency <> c.crm_currency THEN 'разная валюта'
WHEN ABS(g.ga4_revenue - c.crm_revenue) > 0.01 THEN 'разная сумма'
ELSE 'совпадение'
END AS discrepancy_class
FROM ga4_orders g
FULL OUTER JOIN crm_orders c USING (order_id);
Запрос не определяет налоги и возвраты, но делает расхождение наблюдаемым. ABS(... ) > 0.01 применим только после единой валюты и состава суммы; доставку, лежащую отдельно в CRM, добавьте в расчёт или исключите с обеих сторон.
Храните классы по датам в отдельной витрине: после релиза checkout, смены провайдера или server-side отправки будет видно рост конкретного типа проблем. Не смешивайте диагностику транзакций с оценкой рекламных каналов: до выравнивания транзакций спор об атрибуции преждевременен. Связь раннего действия и удержания анализируйте отдельно, например через дерево диагностики роста активации и падения retention.
Единое определение защищает от новых расхождений
Починка не переживёт релиз без общего словаря. Маркетингу нужен источник кампаний, финансам — признанная выручка, продукту — реакция пользователя; один отчёт не обязан отвечать на все вопросы, но названия не должны скрывать различия.
Зафиксируйте шаблон:
- Показатель: «чистая оплаченная выручка» или точное название вместо универсальных «продаж».
- Событие признания: успешный платёж, создание заказа, отгрузка или иной момент.
- Единица сверки:
order_id, при частичных оплатах — такжеpayment_id. - Состав суммы: товары, скидки, доставка, налоги, комиссии, сертификаты, возвраты.
- Время: часовой пояс, граница суток, задержка загрузки, дата возврата.
- Владелец правила: человек или команда, подтверждающие изменение схемы до релиза.
Документ определяет, какое значение верно при расхождении полей. При смене правила пересчитывайте историю или отмечайте разрыв на графике: склеивать два определения в одном месяце опаснее, чем показать изменение методики.
При росте бизнеса исчезают случайные совпадения
На малом объёме можно вручную проверить десяток заказов. При нескольких витринах, регионах, валютах, промокодах и способах оплаты суммы могут случайно сойтись при разном наборе заказов, поэтому месячной выручки недостаточно.
Нужны два слоя: операционный ежедневно считает долю CRM-заказов без GA4, GA4-транзакций без CRM, дубли и суммы по классам; управленческий периодически подтверждает неизменность правил после релизов checkout, CRM и платежных сценариев. Инженер отвечает за доставку, аналитик — за витрину, бизнес-владелец — за определение выручки.
Server-side трекинг снижает зависимость от браузера, но добавляет двойную отправку, ретраи и ошибки маппинга товаров. Важнее способа передачи дедупликация по transaction_id и журнал отправок.
Сначала докажите одну строку заказа
Возьмите период с закрытыми данными, соедините оплаченные заказы с purchase по идентификатору и разложите остаток на дубли, пропуски, время, валюты, состав суммы и возвраты. Тогда месячная разница станет перечнем проверяемых причин.
В ближайшем рабочем цикле согласуйте определение выручки, владельцев полей и закрепите SQL-проверку в регулярном процессе. Отчёты не обязаны совпадать идеально, но разница должна быть объяснима до того, как на ней строят бюджет, план продаж или оценку канала.