Skip to content

Signed visitor identity

If your visitors are already logged in on your site, you can prove their identity so the agent sees a Verified badge and the conversation carries a stable external_user_id — which also lets the visitor resume the conversation from another device.

  1. Generate a signing secret in Settings → Web chat.
  2. On your backend, sign a short identity token.
  3. Pass it to the loader via data-identity.

The token is base64url(json).hmac, where the HMAC-SHA256 covers the exact base64url payload string (never the re-encoded JSON):

Node.js
import crypto from 'node:crypto';
function signIdentity(secret, payload) {
const b64 = Buffer.from(JSON.stringify(payload)).toString('base64url');
const sig = crypto.createHmac('sha256', secret).update(b64).digest('hex');
return `${b64}.${sig}`;
}
const token = signIdentity(process.env.ROSETTA_IDENTITY_SECRET, {
external_user_id: user.id,
name: user.name,
email: user.email,
// Optional: your own record id + free-form business context. Trusted because
// the token is signed on your server — safe to drive entitlement logic on.
external_reference: user.crmContactId,
metadata: { plan: user.plan, account_value: user.mrr, crm_url: user.crmUrl },
});
// PHP
function sign_identity(string $secret, array $payload): string
{
$b64 = rtrim(strtr(base64_encode(json_encode($payload)), '+/', '-_'), '=');
$sig = hash_hmac('sha256', $b64, $secret);
return $b64.'.'.$sig;
}
<script
src="https://widget.rosettachat.app/widget.js"
data-site="wgt_your_public_site_key"
data-identity="<token>"
async
></script>

The payload carries external_user_id (required — the stable identifier), plus optional name and email shown to the agent.

Two optional signed fields let you carry your system’s own data onto the conversation:

  • external_reference — a single id from your system (a CRM contact id, an order number). Indexed, so you can filter conversations by it later.
  • metadata — a flat JSON object of business context (plan tier, account value, a link back to the record). Must stay under ~4 KB; oversized objects are dropped while the rest of the identity still applies.

Because both are inside the signed token, they cannot be forged by the browser — so it is safe to build entitlement or routing logic on them.

Every signed conversation is readable from your server over the API Reference using a personal access token with the support:conversations:read ability. Filter by the same identifiers you signed in:

GET /api/v1/automation/workspaces/{workspace}/support/conversations?external_reference=order-1234
GET /api/v1/automation/workspaces/{workspace}/support/conversations?external_user_id=user-42
GET /api/v1/automation/workspaces/{workspace}/support/conversations/{conversation}/messages

Each conversation returns its external_user_id, external_reference, metadata, captured contact, and rating — so you can reconcile a chat with the matching record in your user or CRM system. The same fields also arrive push-side on the conversation.created webhook.