Диагностика отправки
Инструменты для проверки отправки событий — сетевая панель браузера, вопросы к трекеру из консоли, безопасное логирование на бэкенде и разбор трёх состояний доставки.
На этой странице
Эта страница — про инструменты: что открыть, что спросить, что записать в журнал. Если вы уже знаете симптом и ищете причину, начинайте с решения проблем — там дерево «симптом → причина → проверка → исправление».
Порядок диагностики всегда один: сначала убедиться, что запрос вообще ушёл, потом прочитать ответ, и только потом искать событие в отчётах.
Сетевая панель браузера
Откройте инструменты разработчика, вкладку «Сеть», и включите сохранение журнала при переходах (в Chrome — «Preserve log», в Firefox — «Постоянные журналы»). Без этого запросы, которые уходят при закрытии страницы, исчезнут из списка вместе со страницей.
Смотреть нужно три разных запроса:
| Фильтр | Что это | Ожидаемый код |
|---|---|---|
tracker.js или t.js |
сам файл трекера | 200 |
cfg |
запрос настроек сбора | 200 или 304 |
track |
отправка событий | 202 |
Если нет первого — не загрузился скрипт. Если есть первый, но нет третьего — трекер не инициализировался или сбор ещё не разрешён. Запрос настроек уходит только после разрешения сбора, поэтому его отсутствие — тот же признак.
Что смотреть в запросе
| Где | Что проверить |
|---|---|
| Адрес | путь /v1/track и правильный хост приёма |
| Метод | POST; отдельная строка OPTIONS перед ним — это предпроверка |
Authorization |
Bearer и токен, начинающийся на pp_bt_ |
Content-Type |
text/plain — это норма, а не ошибка |
Origin |
ровно тот адрес, который вы указали при выпуске токена |
X-PP-Tracker |
версия трекера; расхождение с ожидаемой означает кэш |
| Тело | объект с массивом batch; имена событий и event_id видны здесь |
Content-Type: text/plain трекер ставит намеренно, чтобы не плодить лишние
предпроверки. Приём не проверяет этот заголовок, поэтому «неправильный тип
содержимого» никогда не бывает причиной отказа.
Что смотреть в ответе
| Где | Что означает |
|---|---|
Код 202 |
батч принят целиком или частично — читайте тело |
Тело {accepted, n, rejected} |
rejected с непустым списком = часть событий отклонена |
Код 4xx или 5xx |
тело {"error":{"code","message","details"}} |
Заголовок Retry-After |
приходит при 429 rate_limited, значение в секундах |
Заголовок Deprecation: true |
ключ передан устаревшим способом — через адрес запроса |
Заголовок Deprecation появляется, только если ключ уехал в параметре адреса.
Это работает лишь для совместимых ключей pp_wk_…; новым токенам
такой способ передачи запрещён.
Вопросы к трекеру из консоли
В режиме подключения скриптом трекер доступен как глобальный объект pp:
typeof window.pp; // 'object' — скрипт загрузился и выполнился
pp.trackerVersion; // версия загруженного трекера
pp.getConsent(); // 'pending' | 'granted' | 'denied' | 'revoked'
pp.getSessionId(); // строка, либо undefined пока сбор не разрешён
Что означают ответы:
| Ответ | Вывод |
|---|---|
typeof window.pp === 'undefined' |
скрипт не загрузился или не выполнился |
pp.getConsent() вернул 'pending' |
сбор выключен, запросов не будет — это правильно |
pp.getConsent() вернул 'denied' или 'revoked' |
сбор отключён и очередь очищена |
pp.getSessionId() вернул undefined |
сбор ещё не разрешён |
pp.trackerVersion не тот, что вы ждёте |
отдаётся закэшированная версия файла |
Дальше — принудительная отправка. Она даёт гарантированно наблюдаемый запрос в сетевой панели, не дожидаясь таймера:
pp.track('debug_probe', { source: 'devtools' });
await pp.flush();
Имя события должно проходить маску ^[a-z0-9_.]{1,128}$ и быть разрешено для
браузерного токена, иначе вы увидите 202 с отказом
credential_event_forbidden — что само по себе полезный результат: значит
транспорт, ключ и origin в порядке, а дело в правах на имя события.
Состояние очереди видно в хранилище браузера:
JSON.parse(localStorage.getItem('pp_buffer_v2') ?? '[]').length;
localStorage.getItem('pp_anon_id');
localStorage.getItem('pp_session');
Непустой буфер, который не уменьшается, означает, что отправка не удаётся и события ждут следующей попытки. Пустой буфер при отсутствии запросов означает, что события вообще не создавались.
При подключении из бандла глобального pp нет — те же вызовы делаются на вашем
экземпляре клиента.
Проверки без кабинета
Обе проверки ниже не требуют авторизации в кабинете и делаются из терминала.
Отвечает ли приём. Проверка живости не требует ключа:
curl -i https://YOUR_ACTIONPULSE_HOST/healthz
Ответ 200 с телом {"status":"ok"} означает, что адрес правильный и сервис
принимает запросы.
Какие виды сбора включены для ключа. Публичный запрос настроек принимает
только безопасный префикс ключа — 8 символов после pp_bt_, без
секретной части:
# Ровно 8 символов между вторым и третьим подчёркиванием токена pp_bt_…
PREFIX=<8-symbol-key-prefix>
curl -s "https://YOUR_ACTIONPULSE_HOST/v1/cfg?key=$PREFIX" | python3 -m json.tool
В ответе видно, включены ли автосбор кликов, разделов, прокрутки и форм, записи сессий и сбор клиентских ошибок. Это отвечает на вопрос «почему автосбор не работает, хотя события идут».
Что логировать на бэкенде
Отправка с сервера диагностируется только по вашим журналам — сетевой панели здесь нет. Минимальный набор, которого достаточно почти всегда:
| Писать | Зачем |
|---|---|
event_id и имя события |
связать свою запись с событием в ActionPulse |
| Код ответа HTTP | отличить отказ от ошибки транспорта |
error.code из тела |
отличить rate_limited от quota_exceeded |
Каждый элемент rejected: индекс и код |
найти, какое именно событие не прошло |
| Номер попытки | увидеть, что повторы работают и не бесконечны |
| Длительность запроса | заметить таймауты до того, как они станут отказами |
const response = await fetch('https://YOUR_ACTIONPULSE_HOST/v1/track', requestInit);
if (response.status !== 202) {
const body = await response.json().catch(() => ({}));
logger.warn('actionpulse rejected request', {
status: response.status,
code: body?.error?.code,
retryAfter: response.headers.get('retry-after'),
eventIds,
});
return;
}
const result = await response.json();
for (const item of result.rejected) {
logger.warn('actionpulse rejected event', {
eventId: eventIds[item.i],
code: item.code,
});
}
Полезные счётчики, если у вас есть метрики: отправленные события, принятые, отклонённые по каждому коду, попытки повторов, текущая длина своей очереди. Рост отклонённых по одному коду сразу показывает, какая именно разметка сломалась после релиза.
Три состояния: не отправили, отказали, не видно
Это главное разделение. Пока не ясно, в каком из трёх состояний вы находитесь, любые дальнейшие действия — угадывание.
| Состояние | Признак | Где проверять |
|---|---|---|
| Не отправили | запроса на /v1/track нет вовсе |
сетевая панель, свой журнал попыток |
| Отправили и отказали | запрос есть, код не 202 либо rejected непустой |
код ответа, error.code, rejected[].code |
| Приняли, но не видно | код 202 и accepted больше нуля |
период отчёта, фильтры, проект, время события |
Не отправили
Проверяйте в таком порядке: разрешён ли сбор (pp.getConsent()), существует ли
трекер (typeof window.pp), доходит ли выполнение до вашего вызова, подставился
ли токен в разметку. На бэкенде — считает ли ваш код попытки отправки вообще.
Отправили и отказали
Читайте error.code для отказа всего запроса и rejected[].code для отказов по
элементам. Расшифровка всех кодов — в
решении проблем. Обратите внимание, что
202 с accepted: 0 — это тоже отказ, просто по элементам.
Приняли, но не видно
Самое коварное состояние: транспорт исправен, а событий в отчёте нет. Проверяйте по этому списку:
- Тот ли проект. Проект определяется криптографически по ключу и не может
быть переопределён заголовком. Ключ от другого проекта отправит события в
другой проект и вернёт при этом честный
202. - Тот ли период. Если
timeбыло вне окна ±48ч, приём заменил его временем получения — событие лежит «сейчас», а вы ищете его в прошлом. Или наоборот. Сравнитеevent_timeиserver_time. - Не прошло ли достаточно времени. Между ответом и появлением события в отчётах проходит несколько секунд — накопленное пишется пакетами.
- Не отфильтровано ли. Активный сегмент, фильтр по свойству или выбранный тип устройства могут исключить именно ваше событие.
- То ли имя.
Order_Paidиorder_paid— разные строки, и первое имя приём вообще не примет. - Не пустые ли свойства. Значения с признаками секрета или персональных
данных заменяются на
[redacted]на сервере. Событие есть, свойство пустое.
Подробнее про время, повторы и дубли — в доставке и повторах. Про границы и квоты — в лимитах.
Что собрать перед обращением в поддержку
- код ответа и тело ответа на
/v1/track— без значения ключа; - префикс ключа: символы до второго подчёркивания;
event_idи имя события, которое не нашлось;- время попытки в UTC;
- origin страницы, если отправка из браузера.