Identity & signing
An email typed into a chat box is a claim. An email signed with your widget secret is a fact. Everything the agent will do with a customer's own data depends on which of the two it has.
The problem
A visitor can type any address into a chat widget. If the agent treated that as identification, anyone could ask for anyone’s order history by knowing their email address — which is not a secret.
So Zealoop separates the two. An unverified visitor gets grounded answers from your documentation. A verified visitor also gets their own rows and their own actions. Nothing gated ever runs for the first kind.
How signing works
Your workspace has a widget secret. You compute an HMAC-SHA256 of the customer’s email using that secret, on your server, and pass the result to the widget alongside the address. The backend recomputes the same HMAC and compares in constant time. Matching means your server vouched for this person.
import crypto from "node:crypto";
// Server-side only. This secret never reaches a browser.
const WIDGET_SECRET = process.env.ZEALOOP_WIDGET_SECRET;
export function zealoopSignature(email) {
return crypto
.createHmac("sha256", WIDGET_SECRET)
.update(email)
.digest("hex");
}Render it into the page for the signed-in user, then hand it to the widget:
window.Zea && window.Zea.identify({
email: 'customer@example.com',
signature: 'a3f1…' // computed on your server, above
});Rotating the secret
Configuration → rotate. The old secret stops verifying the moment the new one is issued, so deploy your server-side change first or your signed users briefly fall back to anonymous. They will not see an error; the agent will simply decline anything gated, which is the correct failure direction.
What identity unlocks
- Table lookups. A row is matched by its identity key column — usually the email. A verified visitor reads their row and no other. See Tables.
- Gated actions. Any action marked
requiresIdentityis not even offered to the model for an anonymous visitor, so it cannot be talked into calling it. - Continuity. Conversations attach to a known customer, so your team sees history instead of a stranger.
What it does not unlock
Identity is not authorisation for writes. A verified customer still cannot trigger a refund inside the generation loop — writes are proposed, confirmed, then executed on a later turn. See Actions.
Failure modes
- Wrong or missing signature — the visitor stays anonymous. There is no error toast, by design: an attacker probing signatures learns nothing from the response.
- Signature over the wrong string — the HMAC covers the email exactly as sent. Trailing whitespace or a different case changes the digest.
- Called before load — guard with
window.Zea &&, as in the snippet above, or call it from the widget’s ready callback.
The Inbox marks each conversation’s customer as verified or temporary, which is the quickest way to confirm your integration is actually working in production.