Посібник для розробників
API ідентифікації відвідувачів
Програмно ідентифікуйте користувачів, які ввійшли в обліковий запис, щоб вони ніколи не бачили запиту ел. пошти, а їхні розмови автоматично пов’язувалися з контактом.
Коли це використовувати
Якщо на вашому сайті користувачі входять в обліковий запис (SaaS-застосунки, дашборди, портали для учасників), ви вже знаєте, хто вони. Використовуйте команду identify, щоб передати їхню адресу ел. пошти в Sonny, і їм не доведеться вводити її знову.
- Повністю пропускайте запит ел. пошти для користувачів, які ввійшли
- Автоматично пов’язуйте розмови в чаті з карткою контакту
- Одразу бачте ім’я та адресу ел. пошти відвідувача у вхідних
- Продовжуйте історію в різних браузерах і на різних пристроях завдяки верифікованій ідентифікації
Безперервність на різних пристроях
Верифікована ідентифікація відвідувача
Базова ідентифікація за ел. поштою зручна, але браузер може вказати будь-яку адресу. Верифікована ідентифікація додає короткочасний JWT, підписаний вашим сервером. Тоді Sonny може безпечно вважати контакт клієнта власником його історії чату на сайті, тож ті самі розмови з’являться в іншому браузері чи на іншому пристрої.
Вимкнено
Режим за замовчуванням. Для наявних вбудовувань і відвідувачів нічого не змінюється; історія й надалі прив’язана до ID відвідувача в браузері.
Необов’язкова перевірка (рекомендовано)
Дійсні JWT дають доступ до історії на різних пристроях. Для відвідувачів без JWT усе працює як раніше — анонімно або з ідентифікацією за ел. поштою.
Вимагати підтвердження для ідентифікації
Анонімний чат і далі працює, але виклики identify та передавання користувацьких атрибутів вимагають дійсного підписаного JWT.
Режим перевірки не робить обов’язкові поля перед чатом необов’язковими. Як кожен режим задовольняє вимогу обов’язкової адреси ел. пошти, дивіться в розділі обов’язкові дані перед чатом.
1. Згенеруйте секрет для підпису
Відкрийте Канали → ваш канал → Онлайн-чат, знайдіть Захищена ідентифікація відвідувачів, виберіть режим і згенеруйте секрет. Відкритий текст секрету показується лише один раз. Збережіть його в менеджері секретів вашого бекенду як SONNY_IDENTITY_SECRET. Ніколи не розміщуйте секрет для підпису в коді браузера, фрагменті коду для вбудовування, публічній змінній середовища чи у вашому репозиторії вихідного коду.
2. Випустіть короткочасний JWT на своєму бекенді
Підписуйте за алгоритмом HS256. Sonny вимагає user_id, email, iat та exp. user_id має бути стабільним ID з вашої власної бази даних, а не адресою ел. пошти. Термін дії токена — не більше 24 годин; 15 хвилин — гарне значення за замовчуванням. Розбіжність годинників може сягати 60 секунд.
Ви також можете додати підписаний на сервері об’єкт traits з довіреним контекстом для підтримки, як-от merchantName, subdomain, plan, platform і role. Значення атрибутів мають бути рядками, скінченними числами, булевими значеннями або null. Sonny зберігає їх у верифікованій ідентифікації контакту в межах сайту. Атрибути, передані браузером, залишаються неверифікованими й ніколи не потрапляють до цих підписаних атрибутів.
import { SignJWT } from 'jose';
export async function createSonnyIdentityToken(user) {
const secret = new TextEncoder().encode(process.env.SONNY_IDENTITY_SECRET);
return new SignJWT({
user_id: String(user.id),
email: user.email,
traits: {
merchantName: user.merchant.name,
subdomain: user.merchant.subdomain,
plan: user.merchant.plan,
platform: user.merchant.platform,
role: user.role
}
})
.setProtectedHeader({ alg: 'HS256' })
.setIssuedAt()
.setExpirationTime('15m')
.sign(secret);
}require 'jwt'
def sonny_identity_token(user)
now = Time.now.to_i
payload = {
user_id: user.id.to_s,
email: user.email,
traits: {
merchantName: user.merchant.name,
subdomain: user.merchant.subdomain,
plan: user.merchant.plan,
platform: user.merchant.platform,
role: user.role
},
iat: now,
exp: now + 15 * 60
}
JWT.encode(payload, ENV.fetch('SONNY_IDENTITY_SECRET'), 'HS256')
endimport os
from datetime import datetime, timedelta, timezone
import jwt
def sonny_identity_token(user):
now = datetime.now(timezone.utc)
return jwt.encode({
"user_id": str(user.id),
"email": user.email,
"traits": {
"merchantName": user.merchant.name,
"subdomain": user.merchant.subdomain,
"plan": user.merchant.plan,
"platform": user.merchant.platform,
"role": user.role,
},
"iat": now,
"exp": now + timedelta(minutes=15),
}, os.environ["SONNY_IDENTITY_SECRET"], algorithm="HS256")use Firebase\JWT\JWT;
function sonnyIdentityToken($user): string {
$now = time();
return JWT::encode([
'user_id' => (string) $user->id,
'email' => $user->email,
'traits' => [
'merchantName' => $user->merchant->name,
'subdomain' => $user->merchant->subdomain,
'plan' => $user->merchant->plan,
'platform' => $user->merchant->platform,
'role' => $user->role,
],
'iat' => $now,
'exp' => $now + (15 * 60),
], $_ENV['SONNY_IDENTITY_SECRET'], 'HS256');
}3. Передавайте у віджет лише JWT
Повертайте JWT з ендпоінта, захищеного звичайним сеансом вашого застосунку. Викликайте identify до або після init. Віджет зберігає JWT лише в пам’яті: його ніколи не буде збережено в localStorage, cookie чи URL.
// Fetch a short-lived JWT from your authenticated backend.
// Your signing secret never reaches this code.
const { userJwt } = await fetch('/api/sonny-identity').then((res) => res.json());
sonny('identify', { userJwt });
sonny('init', { siteId: 'YOUR_SITE_ID' });
// Sonny asks for a fresh token after expiry or an emergency key change.
window.addEventListener('sonny:identity-required', async () => {
const { userJwt } = await fetch('/api/sonny-identity').then((res) => res.json());
sonny('identify', { userJwt });
});Безпечне оновлення, вихід і ротація
- Оновлення: оновлюйте JWT до завершення терміну дії — приблизно через 10 хвилин для 15-хвилинного токена, — а потім викликайте
sonny('identify', { userJwt }). Також відстежуйте подіюsonny:identity-requiredяк запасний варіант на випадок завершення терміну дії або зміни ключа підпису. - Вихід: викличте
sonny('reset'). Це видаляє JWT з пам’яті, очищає сеанс віджета в браузері й починає новий анонімний сеанс відвідувача. - Зміна облікового запису: викличте
sonny('reset')для користувача A, перш ніж отримувати JWT користувача B і викликатиsonny('identify', { userJwt }). Ніколи не переносьте токен одного користувача в сеанс іншого. - Планова ротація: Sonny приймає попередній секрет протягом 24 годин, щоб ви встигли оновити всі екземпляри бекенду. Наступну планову ротацію заблоковано, доки цей перехідний період не завершиться.
- Підозра на витік секрету: виберіть Замінити негайно. Обидва старі ключі підпису одразу перестають автентифікувати нові запити; підключені віджети запитують у сторінки свіжий JWT.
- Вимкнення перевірки: Sonny видаляє поточний і попередній секрети для підпису та від’єднує верифіковані віджети. Перш ніж знову ввімкнути перевірку, згенеруйте новий секрет.
Конфлікти особи не об’єднуються автоматично
Якщо стабільний ID користувача й адреса ел. пошти вказують на різні контакти в Sonny, перевірка повертає конфлікт, а не мовчки об’єднує записи клієнтів. Виправте токен або об’єднайте контакти в Sonny, а потім повторіть спробу.
Чат, пов’язаний лише через раніше передану непідписану адресу ел. пошти, не вважається автоматично верифікованою історією. Так адреса, передана браузером, не може відкрити доступ до розмов іншого клієнта.
Вхід у довідковий центр
Підключіть наявний вхід для клієнтів до сторінок довідки, розміщених у Sonny або на власному домені. Використовуйте той самий секрет для підпису сайту й короткочасний JWT, що й для віджета. Базова ідентифікація за ел. поштою та вхід співробітників у Sonny не дають доступу верифікованого читача.
- Спершу виконайте налаштування верифікованої ідентифікації відвідувача вище для цього каналу. Увімкніть «Необов’язкова перевірка» або «Вимагати підтвердження для ідентифікації» в розділі Канали → ваш канал → Онлайн-чат.
- Створіть у своєму застосунку автентифікований ендпоінт, який повертає
{ "userJwt": "SIGNED_TOKEN" }. Випускайте токен на своєму сервері на основі даних клієнта, що ввійшов, і довірених атрибутів; ніколи не приймайте з браузера запитаний тариф чи роль. - У розділі Канали → ваш канал → Довідковий центр → Доступ до довідкового центру виберіть «Верифіковані клієнти» й, за потреби, аудиторію клієнтів. Укажіть сторінку входу вашого застосунку в полі «URL входу для клієнтів» і виберіть «Зберегти доступ».
- Після того як клієнт увійде, виконайте наведений нижче обмін, замінивши YOUR_SLUG на адресу довідкового центру. Однієї URL-адреси входу недостатньо: ваш застосунок має завершити цей обмін.
// Run after your application authenticates the customer.
// This endpoint must use the server's session and trusted customer traits.
const response = await fetch('/api/sonny-identity');
if (!response.ok) throw new Error('Unable to sign in to the help center');
const { userJwt } = await response.json();
const signIn = new URL('https://www.usesonny.com/help/YOUR_SLUG/auth');
signIn.searchParams.set('token', userJwt);
signIn.searchParams.set('return', '/help/YOUR_SLUG');
window.location.assign(signIn);Для власного домену задайте для signIn https://help.example.com/auth і повертайте на / або /articles/getting-started. Шляхи повернення для сторінок, розміщених у Sonny, починаються з /help/YOUR_SLUG. Адреси повернення мають бути на тому самому хості.
Обмін встановлює захищений cookie з прапорцем HTTP-only і виконує переспрямування, щоб прибрати токен з URL. Сеанс читача завершується разом із JWT — не пізніше ніж через 24 години. Використовуйте короткочасні токени й не записуйте URL обміну в журнали. JWT призначений лише для цього одного обміну під час входу, а не для посилань на статті, якими діляться.
Перевірте вхід і доступ
- Відкрийте приватний центр, не ввійшовши в обліковий запис. Натисніть кнопку входу, увійдіть у свій застосунок і переконайтеся, що повертаєтеся до довідкового центру на тому самому домені — у Sonny чи власному.
- Перевірте одну дозволену й одну заборонену статтю під час перегляду, у пошуку та за прямою URL-адресою. Клієнт поза аудиторією центру бачить повідомлення про обмеження доступу; заборонена стаття повертає «не знайдено».
- Скористайтеся кнопкою «Вийти» в довідковому центрі й переконайтеся, що приватний вміст зник. Повторіть для клієнта з іншими атрибутами.
Оновлення та вихід
Віджет автоматично надсилає свій поточний JWT. Оновлюйте його, коли Sonny запитує новий, і викликайте sonny('reset'), коли клієнт виходить з облікового запису. Особа у віджеті й cookie довідкового центру — окремі речі: скидання віджета не завершує сеанс у довідковому центрі, розміщеному в Sonny.
Щоб вийти зі сторінок, розміщених у Sonny, перейдіть на /help/YOUR_SLUG/auth/logout; на власному домені використовуйте /auth/logout. Додайте цю дію до процесу виходу у вашому застосунку, якщо потрібно завершувати обидва сеанси. Недійсні або прострочені облікові дані дають лише доступ відвідувача. Якщо перевірку ідентифікації вимкнено, кожен читач має доступ відвідувача.
Коли атрибути клієнта змінюються, випустіть свіжий JWT і знову викличте identify у віджеті; для сторінок, розміщених у Sonny, повторіть обмін під час входу. Наявні cookie читачів зберігають попередні підписані атрибути до завершення терміну дії. Зміни правил аудиторій застосовуються з наступного запиту.
Створюйте аудиторії, перевіряйте доступ і розв’язуйте проблеми з обмеженнямиІдентифікація за ел. поштою — це не автентифікація
Адреса ел. пошти, яку передає браузер, покращує контекст для підтримки, але не автентифікує відвідувача. Відвідувач може переглядати й запускати JavaScript на власній сторінці, тож адреса ел. пошти, ім’я та користувацькі атрибути ніколи не відкривають доступ до історії іншого клієнта в Sonny. Для верифікованої ідентифікації потрібен JWT із підписом на сервері, описаний вище. Авторизацію дій у вашому продукті залишайте всередині вашого застосунку, де користувач увійшов в обліковий запис.
Коли перевірку відвідувачів увімкнено, позначка Підтверджено у вхідних означає, що розмову пов’язано за допомогою JWT із підписом на сервері. Позначка Не підтверджено означає, що розмову не автентифіковано жодною підписаною на сервері особою. Будь-яке показане ім’я чи адреса ел. пошти — це контекст для підтримки, наданий відвідувачем, а не доказ особи.
Приклади коду
Найпростіший виклик — просто передайте адресу ел. пошти користувача:
// Identify a logged-in user
sonny('identify', {
email: 'jane@example.com'
});Передайте також ім’я користувача, щоб агенти бачили його у вхідних:
// Identify with full name
sonny('identify', {
email: 'jane@example.com',
name: 'Jane Smith'
});Додайте корисний контекст для підтримки під час ідентифікації, оновіть його пізніше або відстежуйте значення, що змінюється, поки сторінка відкрита:
// Identify with support context
sonny('identify', {
email: 'jane@example.com',
name: 'Jane Smith',
attributes: {
plan: 'starter',
seats: 5,
trial: true
}
});
// Update only the values that changed
sonny('setAttributes', {
plan: 'growth',
seats: 8,
trial: null // Clears this property
});
// Keep a changing value in sync (checks every 10 seconds)
sonny('watchAttributes', () => ({
monthly_usage: window.currentUsage
}), { interval: 10000 });Повний приклад з асинхронним фрагментом коду. Зверніть увагу: identify можна викликати до init — дані особи стають у чергу й надсилаються, щойно віджет підключиться:
<!-- Sonny widget snippet -->
<script>
(function(w,d,s,o,f,js,fjs){
w['Sonny']=o;w[o]=w[o]||function(){
(w[o].q=w[o].q||[]).push(arguments)};
js=d.createElement(s);fjs=d.getElementsByTagName(s)[0];
js.id=o;js.src=f;js.async=1;fjs.parentNode.insertBefore(js,fjs);
})(window,document,'script','sonny','https://www.usesonny.com/widget.js');
// Identify before init — identity is queued and sent on connect
sonny('identify', {
email: 'jane@example.com',
name: 'Jane Smith'
});
sonny('init', { siteId: 'YOUR_SITE_ID' });
</script>Викликайте reset, коли користувач виходить з облікового запису, щоб очистити його дані й почати новий сеанс:
// Reset on logout — clears identity and starts a fresh session
sonny('reset');Як це працює
- 01
Віджет завантажується й підключається
Віджет підключається до Sonny й під час приєднання надсилає збережені дані особи.
- 02
Дані особи надсилаються на сервер
Sonny шукає контакт із цією адресою ел. пошти у вашому робочому просторі й створює його, якщо такого ще немає.
- 03
Розмови пов’язуються
Усі непов’язані розмови в сеансі відвідувача в поточному браузері пов’язуються з ідентифікованим контактом. Ідентифікація не об’єднує історію між браузерами чи пристроями.
- 04
Запит ел. пошти пропускається
Оскільки відвідувача вже ідентифіковано, запит ел. пошти у віджеті не показується — користувача ніщо не відволікає.
Правила для користувацьких атрибутів
- Максимум атрибутів за один виклик: 50.
- Значення може бути рядком, числом, булевим значенням або null. Максимальна довжина рядка (у символах): 1000. Передайте null або порожній рядок, щоб очистити збережене значення.
- Ключі мають починатися з літери й містити лише літери, цифри та символи підкреслення; максимальна довжина — 64 символи.
- Ці ключі зарезервовано, тому вони ігноруються:
email, name, id, phone, createdAt, updatedAt.
Довідник API
sonny('identify', { email, name?, attributes? })- Ідентифікує поточного відвідувача. Задає адресу ел. пошти й необов’язкове ім’я, пропускає запит ел. пошти та надсилає дані особи на сервер. Можна викликати до або після init.
emailstringАдреса ел. пошти відвідувачаnamestring?Відображуване ім’я відвідувачаattributesobject?Користувацькі атрибути, які потрібно додати до контакту (правила для ключів і значень дивіться в посібнику з налаштування віджета)
sonny('identify', { userJwt, name?, attributes? })- Безпечно ідентифікує поточного клієнта, який увійшов в обліковий запис, за JWT, згенерованим на сервері. Токен зберігається лише в пам’яті й надсилається тільки в автентифікованих запитах або даних сокета.
userJwtstringСвіжий JWT (HS256), випущений вашим автентифікованим бекендомnamestring?Відображуване ім’я відвідувачаattributesobject?Користувацькі атрибути, які потрібно додати до верифікованого контакту
sonny('setAttributes', { ... })- Оновлює користувацькі атрибути ідентифікованого відвідувача. Надсилаються лише змінені значення. Якщо відвідувача ще не ідентифіковано, оновлення чекають і надсилаються після виклику identify.
attributesobjectПари «ключ-значення», які потрібно задати. Передайте null як значення, щоб очистити атрибут.
sonny('watchAttributes', getter, { interval? })- Викликає вашу функцію-гетер за таймером і автоматично синхронізує змінені атрибути. Корисно, коли такі значення, як тариф чи обсяг використання, змінюються, поки сторінка відкрита.
getterfunctionФункція, що повертає поточний об’єкт атрибутівintervalnumber?Як часто перевіряти, у мілісекундах. За замовчуванням 10000, мінімум 2000.
sonny('reset')- Очищає ID віджета, адресу ел. пошти, ім’я та локальну історію розмов у поточному браузері, а потім починає новий сеанс відвідувача. Контакт і його збережені властивості в Sonny не видаляються. Викликайте під час виходу з облікового запису.
Потрібна допомога?
Перегляньте посібник із налаштування віджета або зв’яжіться з нашою командою.
Пов’язані посібники
- Налаштування віджета
Встановіть віджет онлайн-чату Sonny на свій сайт за допомогою одного тегу script.
- Персоналізація віджета
Узгодьте віджет зі своїм брендом: кольори, логотипи, повідомлення й поведінка.
- Контакти
Як у Sonny створюються контакти, як ними керувати, позначати тегами й об’єднувати.
- Історія чату
Як віджет запам’ятовує відвідувачів, що повертаються, і знову завантажує попередні повідомлення.