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.

node.js
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:

browser
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

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

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.