Documentation contents
Inbox and e-mail
Knowledge base
Files
Analytics
Account and billing
Identity verification for signed-in users
Updated
If people sign in to your site or app, the widget can recognize them. They then see their conversations on any device, and your team sees one contact instead of several anonymous ones.
Why a signature is needed
The browser cannot be trusted: anyone can call identify with someone else's e-mail. So your server computes userHash, an HMAC-SHA256 signature with the identity key, which the browser never sees.
The identity key
The key is in the chat widget settings, on the User recognition tab. Only owners can see and change it.
- Keep the key on your server only, for example in the
SUPPORT_IDENTITY_SECRETvariable. Never put it in browser code. - When you create a new key, the old one keeps working for 24 hours so you can update your server.

What to sign
The signature covers the string v1:<id>:<e-mail>. The e-mail is trimmed and lower case; a missing part stays empty.
v1:<externalId>:<e-mail, trimmed and lower case>
v1:12345:jonas@example.com id and e-mail
v1:12345: id only
v1::jonas@example.com e-mail only, needs the setting
"My app verifies e-mail addresses"userHash is the HMAC-SHA256 of this string with the identity key, written as 64 hex characters.
Code for your server
Node.js:
// Node.js (Express): your own endpoint, for the signed-in user only
import { createHmac } from 'node:crypto';
app.get('/api/support-hash', requireLogin, (req, res) => {
const user = req.user;
const email = (user.email ?? '').trim().toLowerCase();
const canonical = `v1:${user.id ?? ''}:${email}`;
const userHash = createHmac('sha256', process.env.SUPPORT_IDENTITY_SECRET)
.update(canonical)
.digest('hex');
res.json({ userHash });
});PHP:
<?php
// PHP: mb_strtolower, not strtolower, so Ū and Ž are lowered too
$email = mb_strtolower(trim($user->email ?? ''), 'UTF-8');
$canonical = 'v1:' . ($user->id ?? '') . ':' . $email;
$secret = getenv('SUPPORT_IDENTITY_SECRET');
$userHash = hash_hmac('sha256', $canonical, $secret);Python:
# Python
import hashlib
import hmac
import os
user_id = "" if user.id is None else str(user.id)
email = (user.email or "").strip().lower()
canonical = f"v1:{user_id}:{email}"
secret = os.environ["SUPPORT_IDENTITY_SECRET"].encode()
user_hash = hmac.new(secret, canonical.encode(), hashlib.sha256).hexdigest()Code for the browser
Always pass externalId as a string: a number is ignored.
// In the browser: ask your own server for the hash of the signed-in user
const { userHash } = await fetch('/api/support-hash', {
credentials: 'include',
}).then((r) => r.json());
HrcWidget('identify', {
externalId: String(user.id ?? ''),
email: user.email,
name: user.name,
userHash,
});
// On logout
HrcWidget('reset');You can pass profile fields with identify too, see Visitor profile.
"My app verifies e-mail addresses"
Turn this on only if your app checks that the e-mail belongs to the user (it sends a code or a link). A signed e-mail then joins the same person's e-mails and conversations into one contact across all your chat widgets and mailboxes.
While this setting is off, always pass the user's externalId. A signed e-mail without an id is refused with IDENTITY_INVALID, and the e-mail stays unverified until the person answers one of our e-mails.
Signed-in users only
The "Signed-in users only" mode lets only recognized users write. An anonymous session cannot send messages or change the profile (IDENTITY_REQUIRED).
Check a signature
The settings have a "Check a calculated value" box: enter an id, an e-mail and the value your server computed, and the app tells you whether it matches. The check runs on the server; the key is not sent to the browser. If it does not match, check that the e-mail is lower case and that you use this widget's key.
You see failures on your site too: HrcWidget('on', 'identify-failed', ...) gets the code, never the signature itself.
Sign-out
When the user signs out, call HrcWidget('reset'). The widget forgets the session, and the next person on the same device does not see someone else's conversations.
Did not find the answer? Write to us