Documentation/Security/Identity verification
Starter plan and above

Identity verification

Tell the agent who your logged-in users are. Your server signs the user with a secret only you hold, and the widget passes the signature on. Sell Whisper AI checks it before trusting the claim, so nobody can pretend to be one of your users.

1. Generate the identity secret

Open your agent, go to Settings, then Security, and click Generate secret under Identity verification. Owners and Admins can reveal or rotate it there later. Store it on your server, for example as SELLWHISPER_IDENTITY_SECRET. Never put it in your website code.

Rotating the secret takes effect straight away: users signed with the old secret are treated as anonymous until your server signs them with the new one.

2. Sign the user on your server

Use either a JWT (HS256), which can carry the email, name and custom attributes, or the user id with its HMAC-SHA256 hash, which needs no JWT library.

Node.js

import jwt from "jsonwebtoken";
import crypto from "node:crypto";

const secret = process.env.SELLWHISPER_IDENTITY_SECRET;

// Option 1: a signed JWT (user id, email, name, expiry, custom attributes)
export function widgetIdentityToken(user) {
  return jwt.sign(
    { user_id: user.id, email: user.email, name: user.name, plan: user.plan },
    secret,
    { algorithm: "HS256", expiresIn: "1h" }
  );
}

// Option 2: the user id and its HMAC-SHA256 hash
export function widgetUserHash(userId) {
  return crypto.createHmac("sha256", secret).update(String(userId)).digest("hex");
}

Python

import hashlib
import hmac
import os
import time

import jwt  # PyJWT

SECRET = os.environ["SELLWHISPER_IDENTITY_SECRET"]


# Option 1: a signed JWT (user id, email, name, expiry, custom attributes)
def widget_identity_token(user):
    return jwt.encode(
        {
            "user_id": str(user.id),
            "email": user.email,
            "name": user.name,
            "plan": user.plan,
            "exp": int(time.time()) + 3600,
        },
        SECRET,
        algorithm="HS256",
    )


# Option 2: the user id and its HMAC-SHA256 hash
def widget_user_hash(user_id):
    return hmac.new(SECRET.encode(), str(user_id).encode(), hashlib.sha256).hexdigest()

3. Call identify on the page

Render the token (or the user id and hash) into the page for the logged-in user and pass it to the widget. It is sent when the conversation starts and with every message.

<script>
  // After the widget embed code. The token comes from your server.
  window.SellWhisperWidget.identify({ token: TOKEN_FROM_YOUR_SERVER });
</script>
window.SellWhisperWidget.identify({
  user_id: USER_ID,
  user_hash: USER_HASH_FROM_YOUR_SERVER,
});

// When the user logs out:
window.SellWhisperWidget.identify(null);

JWT claims

user_idRequired. Your own id for the user (sub is accepted too).
expRequired for a JWT. Expired tokens are ignored.
emailOptional.
nameOptional. The agent can greet the user by it.
any other claimA custom attribute, such as plan or company. Text, numbers and true/false.

What the agent does with it

  • The agent is told the user id, name, email and custom attributes, so your instructions can refer to them (for example, answer differently for users on the pro plan).
  • Custom actions can use {{identity.user_id}},{{identity.email}}, {{identity.name}} and one placeholder per attribute, such as {{identity.plan}}, in the URL, headers, query and body. A missing value is left empty. Form webhooks receive a verified_identity object.
  • The conversation shows a Verified badge and the user details in chat logs.

What it does not do

  • A forged, expired or unsigned claim is ignored. The user simply chats as an anonymous visitor; no error is shown.
  • A verified user is not a store login. Actions that need the user to be logged in to Shopify or another store still ask the store to verify them, because your user id proves who they are in your app, not which store customer they are.