Entwickleranleitung

API zur Besucheridentifizierung

Identifiziere angemeldete Nutzer per Code, damit sie nie nach ihrer E-Mail-Adresse gefragt werden und ihre Unterhaltungen automatisch mit einem Kontakt verknüpft sind.

Wann du das brauchst

Wenn deine Website angemeldete Nutzer hat (SaaS-Apps, Dashboards, Mitgliederbereiche), weißt du bereits, wer sie sind. Mit dem Befehl identify übergibst du ihre E-Mail-Adresse an Sonny, damit sie sie nicht noch einmal eingeben müssen.

  • Angemeldete Nutzer werden gar nicht erst nach ihrer E-Mail-Adresse gefragt
  • Chat-Unterhaltungen werden automatisch mit dem passenden Kontakt verknüpft
  • Name und E-Mail-Adresse des Besuchers erscheinen sofort in deinem Posteingang
  • Mit bestätigter Identität geht der Verlauf über Browser und Geräte hinweg weiter

Geräteübergreifender Verlauf

Bestätigte Besucheridentität

Die einfache E-Mail-Identifizierung ist bequem, aber der Browser kann jede beliebige E-Mail-Adresse behaupten. Die bestätigte Identität ergänzt ein kurzlebiges JWT, das dein Server signiert. Dann kann Sonny den Kontakt des Kunden sicher als Inhaber seines Website-Chatverlaufs verwenden – so erscheinen dieselben Unterhaltungen auch in einem anderen Browser oder auf einem anderen Gerät.

Aus

Die Standardeinstellung. Für bestehende Einbindungen und Besucher ändert sich nichts; der Verlauf bleibt an die Besucher-ID des Browsers gebunden.

Optionale Überprüfung (empfohlen)

Gültige JWTs erhalten einen geräteübergreifenden Verlauf. Besucher ohne JWT nutzen weiterhin den anonymen Chat oder die E-Mail-Identifizierung wie bisher.

Nachweis zur Identifizierung verlangen

Anonymer Chat funktioniert weiterhin, aber identify und Aufrufe mit benutzerdefinierten Attributen erfordern ein gültiges, signiertes JWT.

Der Überprüfungsmodus macht erforderliche Angaben vor dem Chat nicht optional. Wie jeder Modus eine erforderliche E-Mail-Adresse erfüllt, erfährst du unter Erforderliche Angaben vor dem Chat.

1. Signaturgeheimnis erzeugen

Öffne Kanäle → dein Kanal → Live-Chat, such den Bereich Sichere Besucheridentität, wähle einen Modus und erzeuge ein Geheimnis. Der Klartext wird nur einmal angezeigt. Speichere ihn im Secret Manager deines Backends als SONNY_IDENTITY_SECRET. Leg das Signaturgeheimnis niemals in Browser-Code, ein Embed-Snippet, eine öffentliche Umgebungsvariable oder dein Quellcode-Repository.

2. Kurzlebiges JWT im Backend ausstellen

Signiere mit HS256. Sonny verlangt user_id, email, iat und exp. Die user_id muss eine stabile ID aus deiner eigenen Datenbank sein, keine E-Mail-Adresse. Tokens dürfen höchstens 24 Stunden gültig sein; 15 Minuten sind ein guter Standardwert. Uhren dürfen um bis zu 60 Sekunden abweichen.

Du kannst außerdem ein vom Server signiertes traits-Objekt mit vertrauenswürdigem Support-Kontext mitgeben, etwa merchantName, subdomain, plan, platform und role. Trait-Werte müssen Strings, endliche Zahlen, Booleans oder null sein. Sonny speichert sie an der bestätigten Kontaktidentität der jeweiligen Website. Vom Browser übermittelte Attribute bleiben unbestätigt und werden nie zu diesen signierten Traits hochgestuft.

Node.js
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);
}
Ruby
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')
end
Python
import 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")
PHP
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. Nur das JWT an das Widget übergeben

Gib das JWT über einen Endpunkt zurück, der durch die normale Sitzung deiner Anwendung geschützt ist. Ruf identify vor oder nach init auf. Das Widget hält das JWT nur im Arbeitsspeicher: Es wird nie in localStorage, Cookies oder einer URL gespeichert.

JavaScript
// 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 });
});

Sicher erneuern, abmelden und rotieren

  • Erneuern: Erneuere das JWT, bevor es abläuft – bei einem 15-Minuten-Token nach etwa 10 Minuten – und ruf dann sonny('identify', { userJwt }) auf. Hör außerdem auf sonny:identity-required als Rückfallebene für abgelaufene Tokens oder einen geänderten Signaturschlüssel.
  • Abmelden: Ruf sonny('reset') auf. Damit wird das JWT aus dem Arbeitsspeicher entfernt, die Widget-Sitzung des Browsers gelöscht und ein neuer anonymer Besucher gestartet.
  • Kontowechsel: Ruf sonny('reset') für Nutzer A auf, bevor du das JWT von Nutzer B abrufst und sonny('identify', { userJwt }) aufrufst. Übernimm nie das Token eines Nutzers in die angemeldete Sitzung eines anderen.
  • Regelmäßige Rotation: Sonny akzeptiert das vorherige Geheimnis noch 24 Stunden lang – genug Zeit, um jede Backend-Instanz zu aktualisieren. Eine weitere reguläre Rotation ist erst nach Ende dieser Überschneidung möglich.
  • Verdacht auf ein geleaktes Geheimnis: Wähle Sofort ersetzen. Beide alten Signaturschlüssel authentifizieren ab sofort keine neuen Requests mehr; verbundene Widgets fordern von der Host-Seite ein frisches JWT an.
  • Überprüfung ausschalten: Sonny verwirft das aktuelle und das vorherige Signaturgeheimnis und trennt bestätigte Widgets. Erzeuge ein neues Geheimnis, bevor du die Überprüfung wieder aktivierst.

Identitätskonflikte werden nicht automatisch zusammengeführt

Verweisen eine stabile Nutzer-ID und eine E-Mail-Adresse auf unterschiedliche Sonny-Kontakte, liefert die Überprüfung einen Konflikt, statt Kundendatensätze stillschweigend zu vereinen. Korrigiere das Token oder führe die Kontakte in Sonny zusammen und versuch es dann erneut.

Ein Chat, der nur über eine frühere, unsignierte E-Mail-Adresse verknüpft wurde, gilt nicht automatisch als bestätigter Verlauf. So kann eine vom Browser übermittelte E-Mail-Adresse nicht die Unterhaltungen eines anderen Kunden freischalten.

Anmeldung im Hilfecenter

Verbinde deinen bestehenden Kunden-Login mit gehosteten Hilfeseiten oder Seiten auf deiner eigenen Domain. Nutze dasselbe Signaturgeheimnis der Website und dasselbe kurzlebige JWT wie beim Widget. Die einfache E-Mail-Identifizierung und die Anmeldung von Sonny-Mitarbeitern gewähren keinen bestätigten Lesezugriff.

  1. Schließ für diesen Kanal zuerst die Einrichtung der bestätigten Besucheridentität oben ab. Aktiviere Optionale Überprüfung oder Nachweis zur Identifizierung verlangen unter Kanäle → dein Kanal → Live-Chat.
  2. Implementiere in deiner App einen authentifizierten Endpunkt, der { "userJwt": "SIGNED_TOKEN" } zurückgibt. Stelle das Token auf deinem Server anhand des angemeldeten Kunden und vertrauenswürdiger Traits aus; übernimm nie einen vom Browser angefragten Tarif oder eine angefragte Rolle.
  3. Wähle unter Kanäle → dein Kanal → Hilfecenter → Zugriff aufs Hilfecenter die Option Bestätigte Kunden und optional eine Kunden-Zielgruppe. Trag die Login-Seite deiner App als Anmelde-URL für Kunden ein und wähle Zugriff speichern.
  4. Führe nach der Anmeldung des Kunden den folgenden Austausch aus und ersetze dabei YOUR_SLUG durch die Adresse deines Hilfecenters. Die Login-URL allein reicht nicht: Deine App muss diesen Austausch abschließen.
JavaScript
// 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);

Setze signIn bei einer eigenen Domain auf https://help.example.com/auth und leite zurück zu / oder /articles/getting-started. Gehostete Rücksprungpfade beginnen mit /help/YOUR_SLUG. Rücksprungziele müssen auf demselben Host bleiben.

Der Austausch setzt ein sicheres HTTP-only-Cookie und leitet weiter, um das Token aus der URL zu entfernen. Die Lesesitzung läuft zusammen mit dem JWT ab, nach höchstens 24 Stunden. Verwende kurzlebige Tokens und protokolliere die Austausch-URL nicht. Das JWT gehört ausschließlich in diesen einen Anmeldeaustausch, nicht in geteilte Artikel-Links.

Anmeldung und Zugriff testen

  1. Ruf ein privates Hilfecenter im abgemeldeten Zustand auf. Folge dem Anmelde-Button, melde dich in deiner App an und prüfe, ob du auf derselben gehosteten oder eigenen Domain zum Hilfecenter zurückkehrst.
  2. Prüfe je einen erlaubten und einen gesperrten Artikel beim Durchblättern, in der Suche und per direkter URL. Ein Kunde außerhalb der Zielgruppe des Hilfecenters sieht einen Hinweis zum Zugriff; ein gesperrter Artikel liefert „nicht gefunden“.
  3. Nutze Abmelden im Hilfecenter und prüfe, ob private Inhalte verschwinden. Wiederhole den Test mit einem Kunden, der andere Traits hat.

Erneuern und abmelden

Das Widget sendet sein aktuelles JWT automatisch. Erneuere es, wenn Sonny eines anfordert, und ruf sonny('reset') auf, wenn sich dein Kunde abmeldet. Widget-Identität und Hilfecenter-Cookie sind getrennt: Ein Zurücksetzen des Widgets meldet keine gehostete Hilfecenter-Sitzung ab.

Um dich von gehosteten Seiten abzumelden, ruf /help/YOUR_SLUG/auth/logout auf; auf deiner eigenen Domain nutzt du /auth/logout. Bau diese Aktion in den Logout-Ablauf deiner App ein, wenn beide Sitzungen enden sollen. Mit ungültigen oder abgelaufenen Anmeldedaten gilt Besucherzugriff. Ist die Identitätsüberprüfung ausgeschaltet, hat jeder Leser Besucherzugriff.

Ändern sich die Traits eines Kunden, stell ein frisches JWT aus und identifiziere ihn im Widget erneut; wiederhole für gehostete Seiten den Anmeldeaustausch. Bestehende Leser-Cookies behalten die vorherigen signierten Traits bis zum Ablauf. Änderungen an Zielgruppenregeln gelten ab dem nächsten Request.

Zielgruppen erstellen, Zugriff in der Vorschau prüfen und Einschränkungen beheben

E-Mail-Identifizierung ist keine Authentifizierung

Die vom Browser übermittelte E-Mail-Adresse liefert hilfreichen Kontext für den Support, authentifiziert den Besucher aber nicht. Ein Besucher kann auf seiner eigenen Seite JavaScript untersuchen und ausführen – deshalb schalten E-Mail-Adresse, Name und benutzerdefinierte Attribute niemals den Sonny-Verlauf eines anderen Kunden frei. Eine bestätigte Identität erfordert das oben beschriebene, vom Server signierte JWT. Die Berechtigungen für Aktionen in deinem eigenen Produkt gehören in deine angemeldete Anwendung.

Ist die Besucherüberprüfung aktiviert, bedeutet das Badge Bestätigt im Posteingang, dass die Unterhaltung über ein vom Server signiertes JWT verknüpft wurde. Das Badge Nicht bestätigt bedeutet, dass keine vom Server signierte Identität die Unterhaltung authentifiziert hat. Angezeigte Namen oder E-Mail-Adressen sind vom Besucher angegebener Support-Kontext, kein Identitätsnachweis.

Codebeispiele

Der einfachste Aufruf – übergib einfach die E-Mail-Adresse des Nutzers:

JavaScript
// Identify a logged-in user
sonny('identify', {
  email: 'jane@example.com'
});

Übergib auch den Namen, damit Agenten ihn im Posteingang sehen:

JavaScript
// Identify with full name
sonny('identify', {
  email: 'jane@example.com',
  name: 'Jane Smith'
});

Gib bei der Identifizierung hilfreichen Support-Kontext mit, aktualisiere ihn später oder beobachte einen Wert, der sich ändert, während die Seite geöffnet ist:

JavaScript
// 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 });

Vollständiges Beispiel mit dem asynchronen Snippet. Beachte, dass identify auch vor init aufgerufen werden kann – die Identität wird zwischengespeichert und gesendet, sobald das Widget verbunden ist:

HTML
<!-- 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>

Ruf reset auf, wenn sich der Nutzer abmeldet, um seine Identität zu löschen und eine neue Sitzung zu starten:

JavaScript
// Reset on logout — clears identity and starts a fresh session
sonny('reset');

So funktioniert es

  1. 01

    Das Widget lädt und verbindet sich

    Das Widget verbindet sich mit Sonny und sendet dabei eine gespeicherte Identität gleich mit.

  2. 02

    Die Identität wird an den Server gesendet

    Sonny sucht in deinem Arbeitsbereich nach einem Kontakt mit dieser E-Mail-Adresse und legt einen an, falls es noch keinen gibt.

  3. 03

    Unterhaltungen werden verknüpft

    Alle noch nicht verknüpften Unterhaltungen aus der Besuchersitzung des aktuellen Browsers werden mit dem identifizierten Kontakt verknüpft. Die Identifizierung führt keinen Verlauf aus verschiedenen Browsern oder Geräten zusammen.

  4. 04

    Die E-Mail-Abfrage entfällt

    Da der Besucher bereits identifiziert ist, wird die E-Mail-Abfrage im Widget unterdrückt – keine Unterbrechung für den Nutzer.

Regeln für benutzerdefinierte Attribute

  • Sende höchstens 50 Attribute pro Aufruf.
  • Ein Wert kann ein String, eine Zahl, ein Boolean oder null sein. Strings sind auf 1000 Zeichen begrenzt. Übergib null oder einen leeren String, um einen gespeicherten Wert zu löschen.
  • Schlüssel müssen mit einem Buchstaben beginnen, dürfen nur Buchstaben, Ziffern und Unterstriche enthalten und höchstens 64 Zeichen lang sein.
  • Diese Schlüssel sind reserviert und werden ignoriert: email, name, id, phone, createdAt, updatedAt.

API-Referenz

sonny('identify', { email, name?, attributes? })
Identifiziert den aktuellen Besucher. Setzt die E-Mail-Adresse und optional den Namen, überspringt die E-Mail-Abfrage und sendet die Identität an den Server. Kann vor oder nach init aufgerufen werden.
  • emailstringE-Mail-Adresse des Besuchers
  • namestring?Anzeigename des Besuchers
  • attributesobject?Benutzerdefinierte Attribute, die dem Kontakt zugeordnet werden (Regeln für Schlüssel und Werte findest du in der Anleitung zur Widget-Einrichtung)
sonny('identify', { userJwt, name?, attributes? })
Identifiziert den aktuell angemeldeten Kunden sicher über ein serverseitig erzeugtes JWT. Das Token bleibt im Arbeitsspeicher und wird nur in authentifizierten Request- oder Socket-Payloads gesendet.
  • userJwtstringEin frisches HS256-JWT, ausgestellt von deinem authentifizierten Backend
  • namestring?Anzeigename des Besuchers
  • attributesobject?Benutzerdefinierte Attribute, die dem bestätigten Kontakt zugeordnet werden
sonny('setAttributes', { ... })
Aktualisiert benutzerdefinierte Attribute des identifizierten Besuchers. Es werden nur geänderte Werte gesendet. Ist der Besucher noch nicht identifiziert, warten die Änderungen und werden nach identify gesendet.
  • attributesobjectSchlüssel-Wert-Paare, die gesetzt werden. Übergib null als Wert, um ein Attribut zu löschen.
sonny('watchAttributes', getter, { interval? })
Ruft deine Getter-Funktion in regelmäßigen Abständen auf und synchronisiert geänderte Attribute automatisch. Praktisch, wenn sich Werte wie Tarif oder Nutzung ändern, während die Seite geöffnet ist.
  • getterfunctionEine Funktion, die das aktuelle Attribut-Objekt zurückgibt
  • intervalnumber?Prüfintervall in Millisekunden. Standard 10000, Minimum 2000.
sonny('reset')
Löscht Widget-ID, E-Mail-Adresse, Namen und lokalen Unterhaltungsverlauf im aktuellen Browser und startet dann eine neue Besuchersitzung. Der Kontakt und seine gespeicherten Eigenschaften in Sonny bleiben erhalten. Nutze das beim Abmelden.

Brauchst du Hilfe?

Sieh dir die Anleitung zur Widget-Einrichtung an oder melde dich bei unserem Team.

Verwandte Anleitungen