К содержанию
ActionPulse

Пользователь не склеился

Почему анонимные и авторизованные события расходятся, один человек выглядит двумя, серверные события не связались с браузерными и после выхода данные идут прежнему пользователю.

Кому
Разработчикам, у которых один человек выглядит двумя
Проверено
На этой странице

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

Как устроена склейка

Четыре механизма, и путать их — главный источник ошибочных диагнозов.

Механизм Что делает Когда действует
user_id в самом событии задаёт субъект напрямую сразу, без связок
Связка «анонимный → пользователь» сохраняется вызовом идентификации сразу после успешного ответа
Подстановка на приёме событию только с anon_id дописывается связанный user_id по кэшу связок
Перезапись истории события, собранные до идентификации, привязываются задним числом фоновой задачей

Субъект события — это user_id, если он есть, иначе anon_id. Поэтому самый надёжный способ ничего не склеивать — присылать user_id там, где вы его уже знаете.

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

Решение проблем

Анонимные и авторизованные события не связались

Вероятная причина. Вызов идентификации не дошёл до приёма. Из браузера он отправляется один раз и не повторяется: неудача проглатывается без ошибки в консоли. Поэтому обрыв сети, блокировщик или отказ по правам оставляют связку несозданной, а сбор при этом продолжает работать как обычно.

Как проверить. Во вкладке «Сеть» с включённым сохранением журнала войдите в аккаунт и найдите запрос на /v1/identify. Ожидаемый ответ — 202 с телом {"accepted": 1, "n": 1}. Значимые отказы:

Ответ Что означает
запроса нет вовсе вызов идентификации не выполнился
422 anon_id and user_id are required одно из значений пустое
403 credential_rotation_required ключ выпущен до перехода на новую модель прав
409 privacy_job_active в проекте идёт удаление данных, связки временно не пишутся

Безопасное исправление. Убедитесь, что вызов идентификации выполняется после того, как разрешён сбор: до согласия он ничего не делает, потому что анонимного идентификатора ещё не существует. При ответе 403 credential_rotation_required выпустите новый ключ и замените значение — старый ключ продолжит отправлять события, но операции идентификации ему недоступны. При 409 повторите позже: в details приходит признак retryable.

Если не помогло. Продублируйте связку с бэкенда. У серверного ключа есть отдельная операция связывания, которая ничего не отправляет в аналитику, а только сохраняет связь, и её результат вы видите в коде ответа. Браузерному токену эта операция недоступна намеренно: иначе любой посетитель мог бы привязать чужой идентификатор к своему устройству. См. идентификацию и раздел Ingest.

Один человек в двух браузерах выглядит двумя

Вероятная причина. Так и должно быть, пока человек не авторизовался. Анонимный идентификатор живёт в хранилище одного браузера и одного origin. Два браузера, два устройства, приватное окно, другой поддомен, переход с http на https — во всех этих случаях анонимные идентификаторы разные, и связать их между собой нечем: у ActionPulse нет ни межбраузерного отпечатка, ни кросс-доменных cookie.

Как проверить. Откройте карточку человека и посмотрите блок связанных идентификаторов: при корректной работе у одного user_id перечислено несколько анонимных идентификаторов — по одному на браузер. Если карточек две и у каждой свой user_id, дело не в устройствах, а в самом значении идентификатора — см. следующие разделы.

Безопасное исправление. Ничего исправлять не нужно: как только человек авторизовался в каждом браузере и вызвана идентификация, события несут один и тот же user_id и в отчётах по пользователям он один. Двойным он остаётся только в той части, что была собрана анонимно и до перезаписи истории.

Если не помогло. Проверьте домены. www.example.com и example.com — разные origin, а значит и разные анонимные посетители у одного и того же человека в одном и том же браузере. Один канонический домен для всего трафика — самая дешёвая профилактика.

Идентификатор передан слишком поздно

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

Как проверить. Пройдите путь входа с открытой вкладкой «Сеть» и посмотрите порядок запросов: сколько событий на /v1/track ушло до первого запроса на /v1/identify. Затем посмотрите те же события в списке событий: у них будет только анонимный идентификатор.

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

Если не помогло. Помните про порядок: события, отправленные до согласия, не буферизуются и не досылаются, а перезапись истории привязывает к пользователю только те события, что были приняты. Если вам важна точная атрибуция первого касания, посылайте user_id в самом событии, как только он известен, — это единственный способ, который не зависит ни от связок, ни от фоновой обработки.

Идентификатор менялся

Вероятная причина. У одного анонимного идентификатора может быть только одна связка, и новая запись её перезаписывает: побеждает последняя. Если на одном устройстве последовательно вошли два человека без сброса, связка укажет на второго — и события первого, отправленные позже под тем же анонимным идентификатором, попадут ко второму. Второй источник — само значение user_id поменялось на стороне вашего приложения: человек сменил адрес почты, а он использовался как идентификатор.

Как проверить. В карточке человека посмотрите, не появился ли один и тот же анонимный идентификатор у двух разных людей в разные периоды. В списке событий проверьте user_id двух событий, которые вы считаете принадлежащими одному человеку: значения сравниваются точно, как есть. User-42, user-42 и " user-42" — три разных человека.

Безопасное исправление. Приведите идентификатор к одной форме на бэкенде до отправки и используйте неизменяемое внутреннее значение — первичный ключ или UUID. Уже собранные события переписать нельзя, поэтому исправление действует только на новые: рассчитывайте, что история до исправления останется разделённой.

Если не помогло. Проверьте, не пишете ли вы связки из двух окружений в один проект. Тестовый стенд с ключом рабочего проекта создаёт связки настоящих анонимных идентификаторов с тестовыми пользователями, и заметно это становится только на разошедшихся числах.

События с бэкенда не связались с браузерными

Вероятная причина. У серверного события обычно нет anon_id, поэтому связывать его нечем, кроме user_id. Достаточно расхождения в один символ — число против строки, префикс, регистр — и в отчётах это два разных человека. Второй вариант: user_id в серверном событии отсутствует, а anon_id взят «наугад» — тогда серверное событие остаётся анонимным навсегда.

Как проверить. Найдите в списке событий одно браузерное и одно серверное событие одного человека и сравните значения user_id посимвольно. Полезная проверка: постройте отчёт по уникальным пользователям за день по браузерному событию и по серверному — расхождение в разы обычно и означает разные формы идентификатора.

Безопасное исправление. Договоритесь об одной канонической форме user_id и используйте её в обоих местах. Если вам нужна одна сессия для браузерных и серверных событий, передайте на бэкенд текущий идентификатор сессии из браузера — приём не умеет сшивать сессии по догадке.

Если не помогло. Есть тонкость с подстановкой. Событию, у которого есть только anon_id, приём дописывает связанный user_id по кэшу связок, а не по долговременному хранилищу: запись в кэше живёт 7 дней и продлевается при каждой новой идентификации. Если человек не входил дольше этого срока, его анонимные события снова пойдут анонимными — до следующей идентификации. Практический вывод тот же: где user_id известен, присылайте его в событии.

После выхода события продолжают идти на прежнего пользователя

Вероятная причина. При выходе не вызывается сброс. Тогда сохраняются сразу две вещи: последний известный user_id в браузере и связка «этот анонимный идентификатор — этот пользователь» на сервере. Даже если браузерное значение очистить, события того же анонимного идентификатора будут по-прежнему приписываться прежнему человеку.

Как проверить. Выйдите из аккаунта и посмотрите хранилище браузера: ключа pp_user_id быть не должно, а значение pp_anon_id должно измениться. Если анонимный идентификатор остался прежним, сброс не выполнен.

Безопасное исправление. Вызывайте сброс в обработчике выхода:

pp.reset();

Сброс удаляет pp_user_id, pp_anon_id и pp_session и сразу выдаёт новый анонимный идентификатор. Новый идентификатор нужен именно для того, чтобы разорвать существующую связку: сама связка на сервере остаётся, но к ней больше никто не обращается.

Если не помогло. Помните, что сброс делает и чего не делает:

  • он не отменяет связку на сервере и не удаляет историю — это смена субъекта дальнейшего сбора;
  • он не выбрасывает события, уже лежащие в очереди отправки: они уйдут с теми идентификаторами, с которыми были созданы;
  • он ничего не делает, пока сбор не разрешён согласием.

Удаление данных конкретного человека — отдельная необратимая процедура, а не следствие выхода из аккаунта. См. приватность.

Что проверить

  1. Запрос на /v1/identify уходит при входе и получает 202.
  2. В хранилище браузера после входа есть pp_anon_id, pp_user_id и pp_session, и pp_user_id совпадает с идентификатором из вашей базы.
  3. После выхода pp_user_id пропал, а pp_anon_id изменился.
  4. Значение user_id в браузерном и серверном событии одного человека совпадает посимвольно.
  5. В карточке человека у одного user_id перечислены все ожидаемые анонимные идентификаторы.
  6. Длина идентификаторов не превышает 256 байт — при превышении элемент отклоняется с кодом invalid_actor, и это видно в ответе, а не в отчётах.

Если склейка настроена правильно, а числа всё равно расходятся, проверьте доставку и повторы: дубли и потери выглядят похоже на проблему идентификации, но лечатся иначе.