- Почему оформление заказа ещё не означает покупку
- Почему покупка терялась на странице после оплаты
- Что изменили: отправляем purchase с сервера
- Шаг 1. Добавляем два свойства заказа
- Шаг 2. Сохраняем ClientID при оформлении
- Шаг 3. Включаем Measurement Protocol
- Шаг 4. Собираем покупку из заказа
- Шаг 5. Вызываем отправку при оплате
- Зачем отмечать успешную отправку
- Как проверили результат
- Какие ограничения остаются
- Что получили после доработки
- Нужна настройка ecommerce для вашего магазина?

В интернет-магазине заказ оплачен, деньги поступили, а в Яндекс.Метрике покупки нет. Знакомая ситуация? С ней я столкнулся при настройке электронной коммерции на одном из сайтов на 1С-Битрикс.
Нужно было учитывать именно оплаченные заказы. Не нажатия на кнопку «Купить», не переходы в корзину и не просто оформление заказа. В этой статье расскажу, почему отправка покупки из браузера оказалась ненадёжной и как я перенёс её на сервер.
Почему оформление заказа ещё не означает покупку
Сначала попробовали использовать официальный модуль Яндекс.Метрики для 1С-Битрикс. Для обычных целей — клика, отправки формы или посещения страницы — можно подобрать стандартную настройку. Но для нашей задачи этого оказалось недостаточно.
Здесь есть важный момент. В изученной версии модуля обработчик ecommerce-покупки был. Он регистрировал purchase при создании нового заказа, без проверки оплаты. Поэтому говорить, что модуль вообще не поддерживает покупки, было бы неправильно. Нам не подходил момент отправки события.
Та же проблема возникала, если отправлять покупку собственным кодом на checkout сразу после оформления заказа. Покупатель может выбрать оплату картой, перейти в банк и ничего не оплатить. Заказ в Битриксе уже есть, но деньги ещё не поступили.
В этой настройке ecommerce-покупкой мы решили считать полную оплату заказа. Для магазина с оплатой при получении или частичными платежами правило нужно выбирать отдельно.

Почему покупка терялась на странице после оплаты
Следующий вариант выглядел логично: дождаться оплаты и отправить purchase, когда покупатель вернётся с эквайринга на сайт.
На итоговой странице проверялся результат платежа и выводилось сообщение, что заказ успешно оплачен. Если Битрикс подтверждал оплату, браузер добавлял данные покупки в dataLayer.
Но в этой схеме было несколько зависимостей. Покупателю нужно вернуться на сайт, дождаться загрузки страницы, получить подтверждённый статус и дать JavaScript-коду выполниться. После этого данные ещё должны дойти до Метрики.
Покупатель может закрыть вкладку сразу после оплаты. Редирект из банка может не завершиться. Страница может открыться раньше, чем обновится статус заказа. Наконец, запросу аналитики могут помешать расширение браузера, настройки приватности или проблемы соединения.
Это возможные причины потерь, а не установленный диагноз для каждого заказа. Но общий недостаток понятен: деньги уже поступили, а учёт покупки всё ещё зависит от браузера покупателя.
Ожидание статуса и повторная загрузка страницы помогали только частично. Если человек вообще не вернулся, выполнять код было негде.

Что изменили: отправляем purchase с сервера
Я перенёс отправку покупки в обработчик изменения оплаченности заказа в 1С-Битрикс. Теперь данные передаются через Measurement Protocol — механизм серверных запросов Яндекс.Метрики.
Последовательность получилась такой:
- При оформлении заказа сохраняем ClientID Метрики в свойство заказа.
- Платёжный модуль получает подтверждение банка и устанавливает оплату в Битриксе.
- Срабатывает событие
OnSaleOrderPaid. - Обработчик берёт ClientID, сумму, валюту и товары из заказа.
- Сервер отправляет ecommerce-событие
purchaseв Метрику. - После подтверждённого приёма запроса отмечаем результат отправки в заказе.
Счётчик на сайте продолжает работать: собирать визиты, источники переходов и другие действия. На сервер перенесли именно событие покупки.
Отдельно нужно проверить уведомления банка. Если оплата устанавливается только при открытии итоговой страницы, одной замены аналитики недостаточно. Битрикс должен узнавать об оплате независимо от возвращения покупателя. В нашем случае этот сценарий проверили.
Шаг 1. Добавляем два свойства заказа
В административной части Битрикса создали служебные свойства:
| Код свойства | Тип | Для чего нужно |
|---|---|---|
YM_CLIENT_ID | Строка | Сохранить идентификатор посетителя Метрики |
YM_PURCHASE_SENT | Да/Нет | Отметить, что запрос покупки принят Метрикой |
Оба свойства необязательные. Если в магазине несколько типов плательщиков, свойства нужно добавить для каждого используемого типа.
ClientID сохраняем строкой: переводить длинный идентификатор в число не требуется. Второе свойство хранит Y или N. Это техническая отметка в Битриксе, отдельную цель для неё в Метрике создавать не нужно.
Шаг 2. Сохраняем ClientID при оформлении
В нашем варианте ClientID берётся из cookie _ym_uid и записывается перед первым сохранением заказа:
\Bitrix\Main\EventManager::getInstance()->addEventHandler(
'sale',
'OnSaleOrderBeforeSaved',
static function (\Bitrix\Main\Event $event) {
$order = $event->getParameter('ENTITY');
$clientId = $_COOKIE['_ym_uid'] ?? '';
if ($order->getId() || !is_string($clientId) || $clientId === '') {
return;
}
foreach ($order->getPropertyCollection() as $property) {
if ($property->getField('CODE') === 'YM_CLIENT_ID') {
$property->setValue($clientId);
break;
}
}
}
);Битрикс сохранит свойство вместе с заказом. Вызывать $order->save() внутри этого обработчика не нужно.
К моменту оформления cookie уже должна существовать. Если Метрика заблокирована с первого посещения или её запуск зависит от ещё не полученного согласия, ClientID может отсутствовать. Серверная отправка не создаёт задним числом потерянную историю посетителя.
Хранить ClientID только в сессии недостаточно. Уведомление банка приходит отдельным запросом, без браузерной сессии покупателя. Поэтому идентификатор должен оставаться в самом заказе.
Шаг 3. Включаем Measurement Protocol
В настройках нужного счётчика включаем Measurement Protocol и получаем его секретный токен. Токен хранится на сервере, в настройках интеграции. Передавать его в JavaScript страницы не нужно.
Для ecommerce-покупки не нужен отдельный ID JavaScript-цели. Мы передаём pa=purchase, а не вызываем reachGoal. Не стоит также путать этот способ с отдельным импортом офлайн-конверсий или заказов из CRM: это разные механизмы Метрики.
Ниже — основные фрагменты логики. Это не готовый модуль для установки: подключение класса, обработка ошибок и сохранение служебного флага зависят от реализации сайта.
Шаг 4. Собираем покупку из заказа
В отдельном PHP-классе сделали метод sendPurchase($orderId). Он загружает заказ, проверяет оплату и читает YM_CLIENT_ID. Основные параметры запроса выглядят так:
$data = [
'tid' => $counterId,
'ms' => $token,
'cid' => $clientId,
't' => 'event',
'pa' => 'purchase',
'ti' => 'Заказ№' . $order->getField('ACCOUNT_NUMBER'),
'tr' => $order->getPrice(),
'cu' => $order->getCurrency(),
'dl' => $siteUrl,
];$siteUrl — настроенный адрес магазина. Реальные адреса, идентификаторы счётчика и данные клиента в примерах не публикую. Формат ti нужно выбрать один раз и использовать одинаково во всех источниках покупки.
Товары берём из сохранённой корзины заказа:
$i = 1;
foreach ($order->getBasket() as $item) {
$data['pr' . $i . 'id'] = $item->getProductId();
$data['pr' . $i . 'nm'] = $item->getField('NAME');
$data['pr' . $i . 'pr'] = $item->getPrice();
$data['pr' . $i . 'qt'] = $item->getQuantity();
$i++;
}Так в отчёт попадает состав оформленного заказа с его ценами. Текущая цена в каталоге могла уже измениться. При необходимости дополнительно передаются категории, бренды и купоны.
Затем PHP-клиент делает POST-запрос на адрес приёма Measurement Protocol. Массив параметров преобразуется в тело запроса:
http_build_query($data, '', '&', PHP_QUERY_RFC3986)Шаг 5. Вызываем отправку при оплате
Начало обработчика выглядит так:
\Bitrix\Main\EventManager::getInstance()->addEventHandler(
'sale',
'OnSaleOrderPaid',
static function (\Bitrix\Main\Event $event) {
$order = $event->getParameter('ENTITY');
if (!$order->isPaid()) {
return;
}
// Здесь проверяем YM_PURCHASE_SENT.
// Если значение Y, повторно покупку не отправляем.
$result = FrhtMetrica::sendPurchase($order->getId());
// Сохраняем результат в YM_PURCHASE_SENT.
// Обрабатываем исключения, чтобы не прерывать оплату.
}
);Это сокращённый фрагмент обработчика. Метод класса подключается заранее, а проверка и запись флага находятся в полном коде интеграции.
OnSaleOrderPaid связан с изменением оплаченности. Обычное редактирование комментария или адреса доставки само по себе отправку не запускает. Проверка isPaid() нужна потому, что изменение может происходить и в обратную сторону — при снятии оплаты.
Способ установки оплаты при этом может быть разным: уведомление банка, оплата из личного кабинета или ручная отметка администратора. В последнем случае важно, чтобы сотрудник действительно подтверждал полученные деньги. Отдельного знания о банковской операции у Метрики нет.
Зачем отмечать успешную отправку
Если снять оплату и поставить её повторно, событие сработает ещё раз. Поэтому перед запросом проверяем свойство YM_PURCHASE_SENT.
После ответа HTTP 200 и успешного завершения HTTP-запроса записываем Y. Если подтверждения приёма нет — N и сведения об ошибке в журнал. Служебное значение обновляем без повторного сохранения всего заказа внутри события оплаты.
Флаг помогает пропускать повторные последовательные отправки, но не является полной защитой от дублей. Два параллельных запроса требуют блокировки. А тайм-аут не доказывает, что Яндекс не получил данные: иногда теряется только ответ. В такой ситуации перед повтором нужна проверка.
На этом этапе оставили прямую отправку из обработчика, без cron. У решения есть цена: пока Метрика отвечает, обработка текущего запроса ждёт. Поэтому задали сетевые тайм-ауты. Если магазину потребуются автоматические повторы и независимость от скорости внешнего сервиса, следующим шагом будет очередь отправок.
Как проверили результат
Сначала отправили покупку по ID с закрытой тестовой страницы. Сервер вернул HTTP 200 и ответ <!-- OK -->.
Но останавливаться на этом нельзя. Ответ API подтверждает приём запроса; результат нужно проверить в отчёте. В нашем случае тестовый заказ на 10 рублей появился в отчёте «Содержимое заказов» с товаром и суммой покупки.
Для проверки собственной интеграции я бы прошёл такую последовательность:
- Оформить заказ и проверить заполнение
YM_CLIENT_ID. - Убедиться, что покупка не отправляется до оплаты.
- Оплатить заказ, не возвращаясь на итоговую страницу сайта.
- Проверить оплату в Битриксе и результат серверного запроса.
- Найти покупку в Метрике по её ID, сумме и составу товаров.
- Проверить сохранение
YM_PURCHASE_SENTи пропуск уже отправленного заказа.
Перед тестом нужно отключить прежние источники purchase: собственный код на checkout, код на странице результата и регистрацию покупки при создании заказа в модуле. Иначе один заказ может попасть в аналитику несколько раз.
Для серии тестов лучше использовать отдельный счётчик. Небольшая сумма в рабочем счётчике тоже меняет число покупок и конверсию. В отчётах также стоит сравнивать одинаковые периоды, сегменты и режим учёта роботов.
Какие ограничения остаются
Серверная отправка убирает зависимость от возврата на итоговую страницу, но сама по себе не гарантирует учёт каждой оплаты.
Поздняя оплата. Для дополнения существующего визита через Measurement Protocol действует окно 12 часов после его завершения. При отсутствии подходящего визита может потребоваться сначала создать новый запросом pageview. Это отдельная логика: она не восстанавливает автоматически прежний рекламный источник. Для других сценариев рассматривают импорт офлайн-данных.
Поэтому оплата из личного кабинета через несколько дней действительно вызовет обработчик Битрикса, но попадание покупки в нужный визит нужно обеспечить отдельно. Обещать, что любая поздняя оплата автоматически учтётся правильно, нельзя.
Нет ClientID. Если идентификатор не сохранился, нашему методу нечем связать заказ с посетителем. Такие случаи нужно отслеживать, а не подставлять случайное значение.
Возвраты и отмены. Переданный purchase отражает факт покупки по выбранному правилу. Последующее удаление заказа в Битриксе не отменяет событие в Метрике. Учёт возвратов и итоговой выручки требует отдельного решения.
Что получили после доработки
Отправка ecommerce-покупки теперь запускается по факту оплаты в Битриксе. Покупателю не нужно ждать выполнения аналитики на странице «Спасибо за заказ». В заказе остаются ClientID и отметка о принятом запросе, а саму отправку можно проверить по журналу и отчёту Метрики.
Тест подтвердил, что серверный запрос передаёт покупку с товарами и суммой. Процент восстановленных конверсий я здесь не привожу: для него нужна отдельная сверка оплаченных заказов и данных аналитики за период.
Нужна настройка ecommerce для вашего магазина?
Если оплаченные заказы расходятся со статистикой Яндекс.Метрики, можно начать с проверки текущей настройки. Посмотрю, где отправляется purchase, как сайт получает подтверждение банка, сохраняется ли ClientID и нет ли нескольких источников одной покупки.
Помогу настроить серверную отправку конверсий для интернет-магазина на 1С-Битрикс, проверить результат и разобрать нестандартные сценарии оплаты.
Можно обсудить задачу и получить консультацию или обратиться по техническому сопровождению сайта.
Материал подготовлен по практической доработке интернет-магазина. Технические ограничения сверены с документацией на 28 октября 2026 года.
Полезные материалы: Measurement Protocol, параметры серверных запросов, событие оплаты заказа в Битриксе.
27.10.2026
Семен Голиков.
Время на чтение: 7 мин



Как продлить домен на Timeweb и сэкономить
Переход 1С-Битрикс на PHP 8.2 и MySQL 8 в 2026 году
Как перенести видео с Youtube на Rutube или Vkontakte
Проблема регистрации ботов на сайте
Подключаем Jivo Chat на сайт