Skip to main content
The chat widget treats a customer as anonymous until you prove who they are. Pick one of 3 approaches:
  • Display fields: show a name and avatar for an anonymous customer
  • Signature: sign a signed-in customer’s email and identifiers on your server
  • Email verification: ask the customer to verify an email in the widget

Pass display fields

A customer is anonymous until you provide and prove an email. You can still pass display fields on customerDetails in Plain.init. Plain doesn’t treat those fields as proof of who the customer is:

Sign a known customer

Use this when the customer is already signed in to your product and you know their email. The signature covers the email, plus externalId and tenantIdentifier when you send them. externalId is your ID for the customer. tenantIdentifier is { tenantId: 'ten_0123456789' } or { externalId: 'acme' } for their account.
1

Generate a chat secret

Go to Settings → Chat, open the chat app, and click Generate secret. Keep the secret on your server, never in the browser. Clicking Re-generate secret invalidates the current secret, and signatures from the old secret stop verifying.
2

Build the signature on your server

The signature is a Hash-based Message Authentication Code (HMAC). Sign the message with HMAC-SHA256 and your chat secret, then hex-encode the digest.With no externalId and no tenantIdentifier, the message is the email itself:
With either identifier, the message is JSON. Sort the keys alphabetically at every level, and set v to the number 1:
This TypeScript example builds that message and returns the signature. JSON.stringify drops identifiers you leave undefined and keeps the key order shown:
Compare your function to these signatures. Each one uses the secret chat_secret_example. Each block shows the exact message, then its lowercase hex signature. A space or line break in the message changes the signature.Sign ada@example.com with no identifiers:
Sign ada@example.com and externalId user_123:
Sign ada@example.com and tenantIdentifier { externalId: 'acme' }:
Sign ada@example.com and tenantIdentifier { tenantId: 'ten_0123456789' }:
Sign ada@example.com, externalId user_123, and tenantIdentifier { externalId: 'acme' }:
3

Pass the details and signature to the widget

Pass customerDetailsSignature next to customerDetails. The values in customerDetails must match the ones you signed. In this example, fetchCustomerFromBackend calls your own endpoint, which returns { customerDetails, customerDetailsSignature } for the signed-in customer, so the details and the signature come from one place.
Fetch a new payload when the email or the identifiers change. Plain rejects the request when externalId or tenantIdentifier differs from what you signed.
The signature is a bearer credential: anyone who has it can claim that customer.

Verify an unknown email

Set requireAuthentication when the customer isn’t signed in and you want an email before they can chat. This fits a public page where you don’t manage sign-in. You can pair this option with the Require email verification setting in Settings → Chat.
The widget asks for an email address. Plain emails a one-time code. After the customer enters the code, they can start a thread.