Передача атрибутов пользователя в Нотифлоу через JS
Атрибуты пользователя — это поля, которые вы пишете в Нотифлоу о текущем посетителе: email, имя, тариф, дата регистрации, любые кастомные поля. Передаются одной строкой nw('identify', 'user_42', { email: 'ivan@example.com', plan: 'growth' }). Без идентификации виджет работает с анонимом, и вы не можете построить триггеры по тарифу или сегменту.
Зачем передавать атрибуты пользователя в виджет?
Анонимный пользователь — это «посетитель с IP 1.2.3.4 и cookie X». По нему можно сегментировать только поведение на сайте. Идентифицированный пользователь — это «Иван, тариф Growth, зарегистрирован 6 месяцев назад, последняя оплата была в марте». По нему можно:
- запускать чек-лист онбординга только тем, у кого
signed_up_at< 7 дней - показывать апсейл-попап только пользователям тарифа Free
- маршрутизировать чат — клиенты с тарифом Enterprise идут на старшего менеджера
- персонализировать сообщения бота: «Анна, у вас закончился триал»
Стандартные атрибуты Нотифлоу
Часть полей платформа понимает по соглашению — их видно в карточке контакта в кабинете без дополнительной настройки.
| Поле | Тип | Назначение |
|---|---|---|
external_id |
string | Ваш ID пользователя (первичный) |
email |
string | Email для дедупликации |
name |
string | Имя для приветствий |
phone |
string | Телефон в международном формате |
plan |
string | Тариф: free, growth, pro, enterprise |
signed_up_at |
ISO 8601 | Дата регистрации в вашем продукте |
created_at |
ISO 8601 | Дата создания контакта в Нотифлоу |
external_id — главное поле. По нему происходит дедупликация: если на одном устройстве сначала был аноним, а потом залогинился user_42, обе сессии склеятся в одну карточку.
Кастомные атрибуты: где использовать
Все, что важно для сегментации и не вошло в стандартный список, передавайте как кастомные поля. Примеры из реальных проектов:
mrr_band— корзина MRR:0-50,50-200,200-1000,1000+last_invoice_overdue_days— просрочка по счету, для триггера «оплати до отключения»trial_ends_at— дата конца триала, для проактивного попапа за 3 дняindustry— отрасль клиента, для подбора кейсов в чатеteam_size— размер команды, для маршрутизации на нужного аккаунта
В кабинете кастомные поля автоматически появляются в фильтрах сегментов после первого получения с этим именем.
Как передать атрибуты при загрузке страницы?
Базовый сценарий — пользователь зашел на залогиненную страницу, сервер отрендерил HTML с его данными.
<script>
nw('init', { apiKey: 'YOUR_API_KEY_UUID' });
nw('identify', 'user_42', {
email: 'anna@example.com',
name: 'Анна Петрова',
plan: 'growth',
signed_up_at: '2025-11-12',
mrr_band: '50-200',
trial_ends_at: null
});
</script>
identify нужно вызывать после init, но это можно делать в любой момент — SDK буферизует команды до загрузки widget.js.
Если данные пользователя приходят асинхронно (из API после рендера) — вызовите identify в коллбэке, не блокируйте рендер страницы ожиданием.
Как обновить атрибуты после логина (SPA, React, Vue)?
В одностраничных приложениях рендер происходит без перезагрузки. После логина или изменения профиля атрибуты надо обновить отдельным вызовом.
React-хук:
import { useEffect } from 'react';
function useНотифлоуIdentity(user) {
useEffect(() => {
if (!user || !window.nw) return;
window.nw('identify', user.id, {
email: user.email,
name: user.fullName,
plan: user.subscription.plan,
mrr_band: bandFor(user.subscription.mrr)
});
}, [user?.id, user?.subscription?.plan]);
}
Vue 3 composable:
import { watch } from 'vue';
export function useНотифлоуIdentity(userRef) {
watch(userRef, (user) => {
if (!user || !window.nw) return;
window.nw('identify', user.id, {
email: user.email,
plan: user.plan
});
}, { immediate: true });
}
При логауте вызывайте nw('reset') — это очищает локальное состояние и переводит чат в анонимный режим. Без reset следующий пользователь на этом устройстве унаследует чат предыдущего.
Серверная идентификация: защита от подмены
По умолчанию identify идет со страницы — любой посетитель может открыть DevTools и вызвать nw('identify', 'admin_1', { plan: 'enterprise' }), выдав себя за другого. Для триггеров и маршрутизации это иногда некритично (попап не повредит), но на бизнес-атрибуты, пришедшие с фронта без проверки, рассчитывать опасно.
Жесткое решение — серверный upsert через REST API. Вместо вызова identify из браузера передавайте бизнес-атрибуты с бэкенда:
curl -X POST https://cp.notiflow.ru/api/v1/contacts \
-H "X-Api-Key: YOUR_API_KEY_UUID" \
-H "Content-Type: application/json" \
-d '{
"external_id": "user_42",
"email": "anna@example.com",
"attributes": {"plan": "growth", "mrr_band": "50-200"}
}'
PHP-пример в Laravel-шаблоне:
$client = new GuzzleHttp\Client();
$client->post('https://cp.notiflow.ru/api/v1/contacts', [
'headers' => ['X-Api-Key' => config('services.notiflow.api_key')],
'json' => [
'external_id' => (string) $user->id,
'email' => $user->email,
'attributes' => [
'plan' => $user->plan,
'mrr_band' => $user->mrr_band,
],
],
]);
В браузер при этом отдается только nw('identify', userId, { email }) без бизнес-атрибутов. Подмена в DevTools меняет максимум email на странице, но реальный plan уже лежит в базе Нотифлоу и не перезаписывается с фронта. Для отправки разовых событий с сервера используйте POST /v1/events — описано в API-ключах.
Использование атрибутов в сегментах и триггерах
После того как атрибут пришел в систему, его видно в:
- карточке контакта (в кабинете)
- сегментах: «plan = free И signed_up_at > 7 дней назад»
- условиях запуска виджетов: показать попап только если
mrr_band = '0-50' - маршрутизации чата: тариф Enterprise → оператор «Senior CSM»
- переменных в текстах: «Привет, {{ name }}, ваш триал заканчивается {{ trial_ends_at }}»
Изменения сегментов после прихода нового атрибута пересчитываются в фоне за 1-2 минуты на проектах до 100k контактов.
Частые ошибки и как их отлаживать
identify вызывается до init. Атрибуты не теряются, но в Network видны как ожидающие. Лечится порядком: сначала init, потом identify.
Передается объект, а не примитив для external_id. SDK ругается warning'ом в консоли. external_id всегда строка.
Атрибут plan приходит то как 'growth', то как 'Growth', то как 'GROW'. Сегменты ломаются. Заведите словарь нормализации на бэкенде — приводите к одному регистру и набору значений.
Дата как строка '12.04.2025' вместо ISO. Нотифлоу не парсит локальный формат, фильтры по дате не работают. Используйте 2025-04-12T00:00:00Z.
Чтобы посмотреть, что реально пришло — откройте DevTools Network, найдите запросы к cp.notiflow.ru/api/widgets/identify, в payload будет финальный набор атрибутов. В кабинете в карточке контакта внизу — журнал изменений с timestamp.
Часто задаваемые вопросы
Какие атрибуты обязательные?
Технически — никаких. Но без external_id или email Нотифлоу не сможет склеить анонимные сессии в одного человека, и каждое посещение будет отдельным контактом. Минимум — external_id (ваш ID) и email.
Можно ли передавать чувствительные данные?
Не передавайте через атрибуты пароли, токены, паспортные данные, номера карт. Атрибуты идут через браузер и видны в Network. Email и имя — допустимо. Бизнес-данные (plan, mrr_band) — допустимо.
Как обновить атрибут после логина?
Вызовите nw('identify', userId, { новые_атрибуты }) повторно. SDK отправит обновление, в кабинете в карточке контакта появится новая запись. В SPA удобно вешать вызов на изменение store user — через хук или watcher.
Как защитить бизнес-атрибуты от подмены?
Не передавайте plan, mrr_band и подобные через nw('identify', ...) из браузера — там их можно подменить через DevTools. Делайте upsert контакта серверным вызовом POST /v1/contacts с X-Api-Key. Со страницы передавайте только email и external_id.
Где посмотреть, какие атрибуты пришли?
Два места: DevTools Network (запросы к cp.notiflow.ru/api/widgets/identify) и в кабинете в карточке контакта — внизу есть таблица «Атрибуты» с историей изменений и timestamp.
Передайте первые атрибуты за 5 минут — зарегистрируйтесь в Нотифлоу и добавьте nw('identify', ...) в шаблон залогиненной страницы. Дальше — статьи про API-ключи и настройку вебхуков. Полный обзор JS SDK — на странице платформы.