Identity Verification
Prove that a signed-in visitor really is the user they claim to be — sign user IDs on your server, pass the hash to Yaplet.identify(), and rotate the secret when you need to.
Why identify() Needs a Signature
The widget has to work on pages where nobody is signed in, so any browser can obtain a visitor session for a public widget. That makes an unsigned user ID a claim rather than a fact: without a signature, anyone could call Yaplet.identify("user-4821") from their own browser, land in your inbox looking exactly like that customer, and be handed their details by an agent or by the AI.
Identity verification closes that hole. Your server signs the user ID with a secret only you and Yaplet hold, and Yaplet checks the signature before it writes anything onto the visitor.
Yaplet.identify() is rejected outright without a valid hash. Nothing is saved — not even a partial identity — because an agent looking at the inbox cannot tell a verified visitor from an unverified one. If you ship identify() without this, every signed-in user stays anonymous.Where to Find the Identity Secret
In your Yaplet dashboard, go to Brand → Chat widget, open the Install tab, and scroll past the embed snippet to Identity verification. Press Show identity secret to load it — it is only fetched from the server when you ask for it, and even then it arrives partly hidden. The eye icon beside the value reveals the whole secret, and the clipboard icon next to it copies it.
Each chat widget has its own secret, and you need the Brands permission to see it.
Set It Up in Two Steps
Sign the user ID on your server
Compute an HMAC-SHA256 of the user's ID, keyed with the identity secret, and return the hex digest to your front end together with the user's profile.
import crypto from "crypto";
const userHash = crypto.createHmac("sha256", process.env.YAPLET_IDENTITY_SECRET).update(String(user.id)).digest("hex");
USER_HASH=$(printf '%s' "$USER_ID" | openssl dgst -sha256 -hmac "$YAPLET_IDENTITY_SECRET" | sed 's/^.* //')
<?php
$userHash = hash_hmac(
'sha256',
(string) $user->id,
getenv('YAPLET_IDENTITY_SECRET')
);
import hashlib, hmac, os
user_hash = hmac.new(
os.environ["YAPLET_IDENTITY_SECRET"].encode(),
str(user.id).encode(),
hashlib.sha256,
).hexdigest()
Pass the hash to identify()
Give the hash to Yaplet.identify() as its third argument, alongside the user ID and the profile:
Yaplet.identify(
user.id,
{
name: user.name,
email: user.email,
},
userHash,
);
What Happens When Verification Fails
A rejected call is visible, but only to a developer looking in the right place:
- The request is refused and nothing is written to the visitor record.
- The SDK prints an error to the browser console, starting with
[Yaplet] identify() was rejected, followed by the reason. - The affected people appear in your inbox as anonymous visitors.
- There is no warning in the dashboard. The browser console is the only signal you get, so check it while integrating.
Two other refusals are worth recognising. The widget named in your visitor token has to belong to the same organisation as the visitor record — if it does not, the call is refused with "Visitor does not belong to this widget", which is what stops a token minted against one organisation's widget from writing an identity onto another organisation's visitor. And if we cannot look up the visitor or the widget at all, you get "Could not verify identity right now" instead; that is a temporary fault on our side, not a broken integration.
Rotating the Secret
Once the secret is loaded, a Rotate secret button appears below it, behind a confirmation dialog.
identify() call fails — with your signed-in users showing up as anonymous — until the new secret is deployed to your backend. There is no overlap period, so rotate at a quiet moment and deploy the new value straight away.Rotate if the secret has been exposed: committed to a repository, pasted into a ticket, or shipped in front-end code.
What Else identify() Can Carry
The profile object is more than a name and an email:
- Recognised fields are stored on the visitor: name, email, phone, plan and value. Anything else you send is kept as custom data and shown in the inbox's visitor panel.
- Repeat calls merge. Calling
identify()again enriches the stored custom data rather than replacing it. - Custom attributes reach your API tools as placeholders named
custom_<key>— up to 50 of them, each cut to 512 characters. Nested objects and arrays are skipped, because there is no sensible way to put them in a URL or a header. - Values are truncated, not rejected, if they are unreasonably long, so a legitimate call never fails on length alone.
identify() can do anything.