Идентификация пользователей
Как ActionPulse отличает посетителей: анонимный идентификатор и где он хранится, вызов identify, сброс при выходе, границы сессии, ограничения на user_id.
На этой странице
У события всегда есть субъект: либо анонимный посетитель, либо конкретный пользователь. Эта страница — про то, как один превращается в другого и что при этом происходит с уже собранными данными.
Анонимный идентификатор
anon_id — случайный UUID, который трекер создаёт для посетителя браузера при
первом собранном событии. Он ничего не знает о человеке: это метка устройства и
браузера, а не личности.
Где он лежит и сколько живёт:
| Что | Значение |
|---|---|
| Хранилище | localStorage, ключ pp_anon_id |
| Срок жизни | без срока — пока хранилище не очистят |
| Переживает перезагрузку страницы | да |
| Переживает закрытие браузера | да |
| Область действия | один origin: схема, домен и порт |
| Резервный cookie | нет |
Практические следствия, о которых чаще всего забывают:
- Cookie не используется вовсе. Трекер работает только с
localStorageи дополнительно удаляет одноимённые cookie, если они остались от старых версий. ЕслиlocalStorageв браузере недоступен — заблокирован настройками или режимом приватного просмотра, — идентификатор существует только в памяти страницы, и каждая загрузка страницы будет новым посетителем. www.example.comиexample.com— разные origin, а значит и разные анонимные посетители. То же касается поддоменов и перехода сhttpнаhttps. Один домен для всего трафика — самая дешёвая профилактика двоящихся посетителей.- До получения согласия идентификатора нет. Если сбор требует согласия,
трекер не создаёт
anon_id, не пишет в хранилище и не отправляет запросы, пока согласие не получено. Подробнее — в статье про согласие.
Рядом с pp_anon_id трекер хранит pp_user_id — последний известный
user_id, pp_session — текущую сессию, и pp_buffer_v2 — очередь событий,
которые ещё не удалось отправить. Больше трекер в хранилище ничего не пишет; в
частности, браузерный токен там не лежит.
identify: связать события с человеком
Вызывайте identify, как только узнали, кто перед вами: после входа, после
успешной регистрации и один раз при загрузке приложения, если сессия уже
открыта.
pp.identify('YOUR_USER_ID', { plan: 'pro' });
Что происходит по этому вызову:
- Трекер запоминает
user_idи сохраняет его вlocalStorage. Все последующие события уходят уже с этимuser_id. - Трекер отправляет
POST /v1/identifyс телом{"anon_id": …, "user_id": …, "traits": {…}}. Оба идентификатора обязательны. - Приём сохраняет связку «этот анонимный идентификатор — этот пользователь» и
создаёт событие с именем
identify, свойствами которого становятся переданныеtraits. Успешный ответ —202с телом{"accepted": 1, "n": 1}.
Что происходит с ранее собранными событиями
Ничего не теряется, но происходит это в два разных момента:
- Последующие события связываются с
user_idсразу. - История — события, собранные до
identifyпод анонимным идентификатором, — привязывается к пользователю задним числом фоновой задачей. Это не мгновенная операция: сразу после первогоidentifyотчёты поuser_idмогут показывать меньше событий, чем их было собрано под анонимным идентификатором.
Повторный identify
Трекер помнит user_id между перезагрузками сам, поэтому вызывать identify
на каждой странице не нужно: каждый вызов создаёт ещё одно событие identify.
Вызывайте его тогда, когда личность меняется — вход, регистрация, смена
аккаунта.
traits подчиняются тем же ограничениям, что и свойства событий: до
64 ключей, ключ до 64 байт, значение до
8 КБ. Если ограничение нарушено, связка всё равно сохранится, а
вот событие identify будет отклонено — при этом ответ останется
202. Держите traits небольшими: это атрибуты пользователя, а
не выгрузка его профиля.
Выход из аккаунта: reset
При выходе вызывайте reset():
pp.reset();
reset() удаляет pp_user_id, pp_anon_id и pp_session и сразу выдаёт
новый анонимный идентификатор. Дальше устройство считается новым посетителем.
Что важно понимать:
- Без
reset()следующий пользователь на том же устройстве продолжит историю предыдущего. Причём не только из-за сохранённогоuser_id: связка «анонимный идентификатор — пользователь» уже существует на сервере, поэтому события старогоanon_idбудут по-прежнему приписываться прежнему человеку. Новый анонимный идентификатор нужен именно для того, чтобы разорвать эту связь. reset()не отменяет связку на сервере и не удаляет данные. Это смена субъекта дальнейшего сбора, а не удаление истории. Удаление данных пользователя — отдельная операция, см. приватность.reset()не выбрасывает события, которые уже лежат в очереди отправки: они уйдут с теми идентификаторами, с которыми были созданы. Отдельный вызовclearQueue()очищает только очередь и не трогает идентификаторы.reset()ничего не делает, пока сбор не разрешён согласием.
На бэкенде понятия «сброс» нет: там вы каждый раз явно указываете, чьё событие отправляете.
Сессия
Сессия — непрерывный отрезок активности одного посетителя. Трекер ведёт её сам
и передаёт в поле session_id.
| Свойство сессии | Поведение |
|---|---|
| Идентификатор | UUID, хранится в localStorage под ключом pp_session |
| Продление | при каждом собранном событии |
| Завершение | 30 минут без событий |
| Переход между страницами | сессия продолжается |
| Перезагрузка и закрытие вкладки | сессия продолжается, если уложились в 30 минут |
reset() |
сессия завершается принудительно |
Сессия не заканчивается ни в полночь, ни при закрытии браузера — только по
бездействию. Обратное тоже верно: человек, вернувшийся через час, начнёт новую
сессию с тем же anon_id.
Текущий идентификатор сессии можно прочитать: pp.getSessionId(). До того как
сбор разрешён, метод возвращает undefined — идентификатор ещё не создан.
На приёме session_id необязателен и ничем не проверяется, кроме длины: он
обрезается до 256 байт. Если вы отправляете события с бэкенда и
хотите видеть их в одной сессии с браузерными, передайте туда значение
getSessionId() сами — приём не умеет сшивать сессии по догадке.
Ограничения идентификаторов
| Ограничение | Значение |
|---|---|
Длина user_id и anon_id |
до 256 байт |
| Нулевой байт внутри | запрещён |
| Обязательность | нужен хотя бы один из двух |
Длина считается в байтах, а не в символах: строка из русских букв в UTF-8
занимает по два байта на букву. Слишком длинный идентификатор или идентификатор
с нулевым байтом — отказ элемента с кодом invalid_actor, отсутствие обоих —
missing_actor.
Значения сравниваются точно, как есть. User-42 и user-42 — два разных
человека, а " user-42" с пробелом — третий. Приводите идентификатор к
одной форме на бэкенде до отправки.
Что нельзя использовать как user_id
Годится: первичный ключ пользователя из вашей базы, UUID, внутренний непубличный номер аккаунта.
Не годится: e-mail, телефон, номер документа, логин, который человек может поменять.
Три причины, и все три практические:
- Идентификатор не редактируется PII-фильтрами. Приём вырезает
распознанные секреты и персональные данные из свойств события, а также из
urlиreferrer— но не изuser_id. То, что вы положили в идентификатор, сохранится как есть и будет видно в списке событий, в профилях, в выгрузках и в ссылках, которыми делятся коллеги. - Такие значения меняются. Человек сменил почту — и с точки зрения аналитики это два разных человека с разорванной историей. Сшить их обратно будет уже нечем.
- Ответственность за персональные данные. Чем меньше персональных данных уехало в аналитику, тем меньше объём обязательств по их защите и удалению.
Что проверить
- Откройте вкладку «Сеть» и войдите в аккаунт. Должен уйти запрос на
/v1/identifyс кодом202. - В
localStorageпоявилисьpp_anon_id,pp_user_idиpp_session. Значениеpp_user_idсовпадает с идентификатором из вашей базы. - Выйдите из аккаунта.
pp_user_idпропал,pp_anon_idизменился. - В списке событий проекта найдите событие
identifyи убедитесь, что его свойства — это ожидаемыеtraitsбез лишнего. - Отправьте одно серверное событие для того же пользователя и проверьте в профиле, что браузерные и серверные события собрались под одним человеком.
Если что-то из этого не сходится, дальше — почему события попали не к тому пользователю.