Перейти к основному содержимому

Пример: корзина и аналитика

Задача: отправить одно событие GA4 после подтверждённого добавления товара. Клик «Купить», открытие PDP, отказ и timeout с неизвестным исходом не подтверждают корзину.

Этот пример — код analytics adapter магазина. Он не добавляет метод в ShopStory SDK, не вызывает реальный Cart API и не отправляет события, пока вы не подключите свой sendEvent. Для проверки формата достаточно Node.js 22+; доступ к SDK и клиентские данные не нужны.

Запустить на синтетических данных​

Скачайте Web starter и откройте его каталог. Файл confirmed-cart.mjs содержит полный reporter.

check-analytics.mjs
import { createConfirmedCartReporter } from './confirmed-cart.mjs';

const events = [];
const report = createConfirmedCartReporter((name, payload) => {
events.push({ name, payload });
});

const receipt = {
status: 'confirmed',
operationId: 'cart-operation-1',
feedProductId: '0001001',
unitPriceMinor: 129900,
quantity: 2,
currency: 'RUB',
};

await report({ status: 'unknown' }, { hasConsent: true });
await report({ status: 'rejected' }, { hasConsent: true });
await report(receipt, { hasConsent: false });
await report(receipt, { hasConsent: true });
await report(receipt, { hasConsent: true });

console.log(JSON.stringify(events, null, 2));

Сохраните код рядом с confirmed-cart.mjs и выполните:

node check-analytics.mjs

Ожидается ровно одно событие:

[
{
"name": "add_to_cart",
"payload": {
"currency": "RUB",
"value": 2598,
"items": [{ "item_id": "0001001", "price": 1299, "quantity": 2 }]
}
}
]

Это проверяет момент отправки, формат и локальную дедупликацию. Получение события системой аналитики проверяется отдельно.

Откуда берётся receipt​

receipt — нормализованный ответ commerce-кода магазина, а не формат ShopStory. Его значения берутся из подтверждённого результата Cart API, а не из product action или снимка каталога player.

Поле примераЗначение
statusconfirmed — магазин подтвердил добавление; rejected — отказ; unknown — исход ещё не выяснен
operationIdСтабильная идентичность одной cart operation; повторная доставка использует тот же ID
feedProductIdСтроковый товарный или SKU ID, согласованный для E-commerce
unitPriceMinorПодтверждённая цена единицы в копейках после скидок, приведённая к базису GA4
quantityЧисло добавленных единиц; пример рассчитан на целое положительное количество
currencyВ этом примере только RUB

Расчёт выполняется в целых копейках, затем переводится в рубли для GA4: 129900 × 2 / 100 = 2598. Некорректные ID, количество, валюта и переполнение числа отклоняются. Для другой валюты, весового товара или отдельного распределения скидок адаптируйте схему по подтверждённым условиям магазина.

В value не включайте доставку и налог. Приведение цены магазина к этому базису выполняется до создания receipt; reporter не вычисляет налог и не меняет условия Cart API.

Подключить к интеграции​

Создайте reporter один раз в integration owner. Передайте существующий analytics dispatcher магазина, например (name, payload) => gtag('event', name, payload). Используйте принятый consent flow; пример по умолчанию ничего не отправляет.

ПлатформаГде вызывать reporter или эквивалентный analytics-код
Web short flowВ ветке подтверждённого результата Cart API; назначьте одного отправителя в целевую систему, чтобы SDK и клиентский callback не дублировали событие
Native iOSВ commerce-коде приложения после успешной cart operation. Delegate SDK не имеет completion
Flutter на iOSПосле подтверждения cart operation; ShopStoryProductActionSucceeded возвращается отдельно для lifecycle adapter
Переход на PDPCart event не отправляется; переход при необходимости учитывается своим событием

Функция sendEvent принимает имя и очищенный payload. Успешное завершение reporter означает вызов dispatcher, а не доставку GA4. Схема value, currency и items соответствует GA4 add_to_cart.

Повторы и неизвестный результат​

Reporter подавляет повтор одного operationId, включая параллельные вызовы, пока живёт этот экземпляр. Он не хранит состояние между перезагрузками и не гарантирует exactly-once доставку в стороннюю аналитику.

Идемпотентность самой cart operation обеспечивает backend магазина. Reporter не повторяет запросы корзины. При timeout сначала выясните состояние операции; после подтверждения можно передать тот же receipt. Если dispatcher вызвал исключение, сначала проверьте исход отправки, прежде чем повторять аналитику.

Для заказа используйте отдельное событие purchase с согласованным transaction_id. Cart operation ID и Buy intent не заменяют ID заказа.

Приёмка разработчиком и аналитиком​

СценарийОжидаемый результат
Один подтверждённый receiptОдин вызов dispatcher с правильным товаром, количеством и суммой
Тот же receipt повторно или параллельноВторой вызов dispatcher отсутствует
unknown, rejected, открытие PDPadd_to_cart отсутствует
Consent запрещён или не переданDispatcher не вызывается
Другая подтверждённая operationНовое событие; прежний ID не переиспользуется для нового действия
Ошибка данныхОшибка интеграции; неверный payload не отправляется

После локальной проверки выполните тест с согласованным проектом: подтверждение Cart API → вызов dispatcher → исходящий запрос → запись в отчёте. Тестовые события должны быть отделены от production-периода и данных покупателей.

Связанные разделы: смысл метрик, Web tracking, Mobile tracking, диагностика.