Identify logged-in visitors
Tell the chat widget who your logged-in user is, signed with HMAC-SHA256 so it can be trusted. Works with any backend.
Optional. The widget works without it — this is for products where your visitors are already signed in and you would rather the conversation arrived with a name on it.
Signed, or it doesn't count
Anything a browser can assert, a visitor can edit. So there are two levels of trust, and the difference is the whole design.
With a valid signature
- The conversation is labelled with their name.
- They become a contact the moment they say hello.
- Their email is safe for us to reply to.
- The agent knows who it is talking to and stops asking.
- You can see every conversation they have ever had.
Without one
- We show the name, and treat it as decoration.
- We will not store the email address or send anything to it.
- No contact is created from the claim.
We email visitors when you reply after they have left the page. An unverified address would let anyone on your site have us mail someone who never asked to hear from us.
1. Sign the visitor on your server
Hash the user's id and their email, separated by a newline, with HMAC-SHA256 and your signing secret. Never do this in the browser — the secret would be readable by anyone who views source.
The string to sign is exactly userId + "\n" + email, with an empty string where a user has no email. Both fields, not just the id — otherwise a signature stays valid while the email underneath it is swapped, and the email is the part we can deliver to.
import { createHmac } from "node:crypto";
const userHash = createHmac("sha256", process.env.WHIZ_IDENTITY_SECRET)
.update(`${user.id}\n${user.email ?? ""}`)
.digest("hex");require "openssl"
user_hash = OpenSSL::HMAC.hexdigest(
"SHA256",
ENV.fetch("WHIZ_IDENTITY_SECRET"),
"#{user.id}\n#{user.email}"
)import hashlib, hmac, os
user_hash = hmac.new(
os.environ["WHIZ_IDENTITY_SECRET"].encode(),
f"{user.id}\n{user.email or ''}".encode(),
hashlib.sha256,
).hexdigest()<?php
// Note the argument order: data first, then the key.
$userHash = hash_hmac(
'sha256',
$user->id . "\n" . ($user->email ?? ''),
getenv('WHIZ_IDENTITY_SECRET')
);Your signing secret is in the dashboard under Settings → Embed. Store it the way you would a database password.
2. Pass it to the widget
Render this wherever you already render the embed snippet. The stub means you can call it before the widget has finished loading.
<script>
window.whizChat = window.whizChat || function () {
(window.whizChat.q = window.whizChat.q || []).push(arguments);
};
window.whizChat("identify", {
userId: "usr_1234", // your own id for this person
name: "Jo Kelly", // optional
email: "jo@acme.com", // optional
userHash: "a3f1..." // from step 1
});
</script>Call it on every page, not just after login
We check the signature on every message, so identity travels with the conversation rather than being remembered from an earlier request. Someone who browses anonymously and then signs in keeps the thread they already started.
Clear it on logout
Call whizChat("shutdown") so the next person on a shared computer doesn't inherit the last one's name.
A wrong hash won't break anything
If the signature doesn't match we fall back to treating the visitor as unverified. They keep their conversation; you lose the name. Nothing errors, which is worth knowing because it also means a broken integration is quiet — check a live conversation to be sure.
How to tell it worked
Open the conversation in your dashboard. Under the visitor's name it will say Verified by your site, with their email beside it. If it says Name unverified, the hash didn't match — usually the wrong secret, or signing the id without the email.
Rotating the secret
Rotating takes effect immediately, so every hash your servers are computing with the old value stops matching until you deploy the new one. Visitors show as unverified in the meantime. Nothing breaks, but nothing tells you either.
Free to try
See it on your own product
Create a signing secret, drop in four lines, and your next conversation arrives with a name on it. No card needed to start.
No credit card, no plugins, no developer.
Already set up? Log in
