What it does
- Links a signed-in visitor’s chat to the contact with the same External ID, creating the contact when none exists.
- Accepts a JWT signed with HS256, whose
expclaim, when present, is at most 24 hours ahead (include one, so the token stops working), or a legacy HMAC-SHA256 user hash. - Updates the contact’s email, name, phone, custom attributes and Stripe customer IDs from signed JWT fields.
- Passes public attributes, up to 1,000 characters of JSON, to the agent as context.
- Gives actions such as Stripe billing the verified customer, so they act only on that person’s records. A Twilio action scoped to the customer uses the verified number too; one set to any number does not.
What you need
- Standard and up. If the workspace loses that plan access, visitors can still chat anonymously, but the agent stops loading their verified contact details. See plans.
- A workspace admin to turn verification on, copy the secrets and rotate them.
- A server that already authenticates your users and can sign a token.
- The website widget installed; see the website widget.
Set it up
1
Open Identity
Open Channels → Install → Website widget → Set up identity verification.
You can also open Settings → Identity. Choose Turn on identity
verification the first time.
2
Copy the secrets
The Identity verification card shows two secrets, one for each method: a
Token secret for JWTs and a User hash secret for user hashes. Store
them on your server as
CENTILLION_TOKEN_SECRET and
CENTILLION_USER_HASH_SECRET.3
Pick a signing method
Under Set it up, choose Token (JWT) or User hash (legacy). The
page shows the server code and the website code for that method.
4
Sign and identify
After login, sign a JWT on your server, or generate the user hash if you
chose the legacy method, then pass it to the widget with
identify or
centillionUserConfig, as below.5
Choose what the agent may read
Under What the agent may read, select the contact attributes the agent
may use in its answers.
Verification used to have one shared secret, often kept in
CENTILLION_IDENTITY_SECRET. That secret no longer verifies either kind of
signature. Copy the Token secret for JWTs or the User hash secret for
user hashes from Settings → Identity, and update your server.Use it every day
Method 1: JWT, recommended
After authenticating the user with your existing login system, sign a token on your server. Derive the user ID from that authenticated session.user_id or sub is required. Use a stable string identifier. Numeric
user_id values are also accepted and converted to strings. If both are
present, sub takes precedence. phone is an alias for phonenumber and takes
precedence, including when set to null.
Expiration is optional, but use a short-lived token and refresh it while the
website session remains valid. When supplied, exp must be no more than 24
hours away. Expired tokens, future nbf claims, wrong signatures and algorithms
other than HS256 do not authenticate the visitor. Verification allows one minute
of clock skew. JWTs are signed, not encrypted, so keep passwords and other
secrets out of them.
Identify after login
Return the token from your authenticated backend endpoint, then pass it to the widget. The endpoint below is part of your website and uses your website session.window.centillion("identify", ...) is also supported.
Identify before the script loads
Set the configuration before your normal embed snippet:window.centillionSettings remains supported. If both configurations are set,
centillionUserConfig takes precedence. Provide a fresh token on each page load.
If login can finish before the script loads, define this command queue first:
Sign out
Call this when your website signs the user out:logout and shutdown
commands remain supported.
Contact updates and privacy
JWT fields are private contact data. They are available to configured actions, including billing actions, and are not automatically added to the AI context. In Settings → Identity → What the agent may read, you can explicitly expose selected contact attributes. Billing identifiers remain private.
Omitted fields keep their current values. Pass
null to clear a field. For
custom attributes, {"plan": null} deletes only plan; custom_attributes: null clears defined custom attributes while preserving billing IDs.
stripe_accounts: null or [] clears the billing mapping. Email and phone
values already held by another contact are not reassigned. Attributes are
defined under Contacts, Manage attributes.
token, or inside
user_metadata. Their combined JSON must fit within 1,000 characters. Oversized
or malformed metadata is ignored without discarding a valid identity.
Method 2: user hash, legacy
For existing integrations, generate an HMAC-SHA256 of the exact user ID on your server, keyed with the User hash secret. Prefer JWTs for new integrations because they support expiration and contact updates.centillionUserConfig. User hashes verify only the ID.
They match a contact by External ID, creating an empty contact when none
exists. Maintain contact details through Contacts or your CRM integration.
Each secret only checks its own kind of signature. A user hash made with the
Token secret is refused, and so is a token signed with the User hash secret.
Shopify sign-in
For the Shopify theme embed, open Channels → Shopify and choose Prepare customer sign-in. Shopify signs the customer’s store identity and the embed refreshes its short-lived token automatically. This preserves existing identity secrets. Typing an email in chat does not sign a shopper in.Website events
The current embed also supports event listeners throughwindow.Centillion.addEventListener or
window.centillion.addEventListener. These share the same listener registry. A
sign-out or visitor change clears the conversation and stops events from its
pending replies. Runtime display options do not verify a customer’s identity.
Connecting website and WhatsApp support
Use one stable customer ID as the Contact’s External ID, and store the customer’s phone number on that same Contact. A signed website identity uses that customer ID. When a WhatsApp conversation becomes a Helpdesk ticket, the sender’s phone number can reuse the existing Contact, preserving its External ID and linking the customer’s tickets across channels. Phone matching uses an international number including its country code. If multiple Contacts already have that number, correct the duplicate records before linking the conversation. Helpdesk does not choose one or merge them. An anonymous website session stays separate until it has a verified identity. Sharing a Contact lets support staff see related tickets in Customer history when a person takes over from the helpdesk inbox. It does not copy previous website transcripts into a new WhatsApp AI conversation.Rotating the secrets
Rotate secrets replaces both at once: signatures made with the old ones stop working, and visitors chat anonymously until your server signs with the new ones. Turn off deletes them.Limits and good to know
- JWTs must use HS256, and
exp, when present, can be at most 24 hours away. Verification allows one minute of clock skew. - Public attributes outside the token fit within 1,000 characters of JSON and are visible to the agent.
- Billing identifiers are never exposed to the agent.
- The old shared
CENTILLION_IDENTITY_SECRETno longer verifies anything. - Rotating replaces both secrets at once; until your server signs with the new ones, visitors chat anonymously.
Questions
Should I use a JWT or a user hash?
A JWT for anything new. It supports expiration and updates the contact’s details. User hashes verify only the ID and are kept for existing integrations.Does the agent see everything in the token?
No. JWT fields are private contact data, available to configured actions. The agent reads only the attributes you select under What the agent may read, plus public attributes passed outside the token.What happens when a visitor isn’t signed in?
They chat anonymously. Actions that need a verified customer, such as Stripe billing, refuse anonymous visitors.What happens when my site signs the user out?
Callwindow.Centillion("resetUser"). It clears the widget identity, public
metadata and conversation.
Can a customer prove who they are by typing their email?
No. Only a signature made on your server verifies a visitor. Typing an email in chat, on the website or in Shopify, does not sign anyone in.What happens if I rotate the secrets?
Both secrets change at once. Signatures made with the old ones stop working, and visitors chat anonymously until your server signs with the new ones.Try it
Turn on identity verification, sign one test user on your server, and open the widget: the conversation should appear on that user’s contact.Start free
Start on the Free plan, or take a seven-day trial of a paid plan. Your agent is live on your site in an afternoon.
Book a demo
Fifteen minutes with the team, on your own use case.
Related
What Centillion is
How the agent, its knowledge and its channels fit together.
Stripe billing
Show signed-in customers their invoices and subscriptions in chat.
Website widget
Install the chat widget the identity is passed to.