Docs

User Identification

Identifying users connects anonymous chat sessions with real user profiles.

How it works

When you call Respondo.identify(), the provided fields are attached to the conversation. All fields are optional — pass only the ones you have. For example, you can send just userId without email or name. Support agents see this data in the conversation details panel.

Parameters#

PropertyTypeRequiredDescription
emailstringoptionalUser's email address
namestringoptionalDisplay name
userIdstringoptionalYour internal user or display ID — shown as-is in dashboard
userHashstringoptionalHMAC-SHA256 signature for identity verification
metadataobjectoptionalKey-value pairs of custom fields (plan, company, etc.)
propertiesobjectoptionalCustom contact properties defined in Agent Settings. Keys must match property definitions. Values are stored with cp_ prefix and are filterable in the Inbox.
Example: Single Page Appjavascript
// After successful login
async function onLogin(user) {
  await authenticateUser(user);

  Respondo.identify({
    email: user.email,
    name: user.fullName,
    userId: user.id,
    metadata: {
      plan: user.subscription.plan,
      company: user.company.name,
      role: user.role,
      signedUp: user.createdAt
    },
    properties: {                        // custom contact properties
      account_type: user.accountType,    // must match keys from Agent Settings
      industry: user.industry,
      contract_tier: user.tier
    }
  });
}
Call identify() after init(). If you call it before the widget is initialized, identity data will be ignored.

Anonymous Visitors#

If you don't call identify(), the widget automatically assigns a persistent visitor ID stored in localStorage. In the dashboard, the conversation appears as Visitor XXXXXXXX (first 8 chars of the UUID).

ModeDashboard displayHMAC required
No identify()Visitor a1b2c3d4No
identify({ email, name })Name + email shownNo (but anyone can spoof)
identify({ userId })userId shown as-isNo (unspoofable only with HMAC)
identify({ userId, userHash })Verified user identityYes — cryptographically verified
The visitor ID persists across sessions on the same browser. It is never sent to Respondo as an authenticated identity — it's only used for anonymous conversation continuity.

userId-only Identification (no email or name)#

If your platform doesn't have user emails or names — for example, you only have an internal display ID — you can pass just userId. No other fields are needed. The dashboard will show the userId as-is in conversation details.

userId + metadata (without email or name)javascript
// Your platform only has a display ID — that's enough
Respondo.identify({
  userId: user.displayId,      // e.g. "USR-4821" — shown in dashboard
  metadata: {                  // optional extra context
    plan: 'premium',
    region: 'eu-west'
  }
});
// No email or name needed — the widget works with just userId
To prevent spoofing of the userId, pair it with userHash (see Identity Verification below). Without HMAC, anyone can pass any userId from the browser console.

Google Tag Manager / deferred identify()#

When embedding via GTM, user data may not be available at page load. Two approaches:

Option A: localStorageKey (zero JS needed)javascript
// If your platform already writes the user ID to localStorage:
Respondo.init({
  agentId: 'YOUR_AGENT_ID',
  localStorageKey: 'myapp_user_id'  // reads localStorage.getItem('myapp_user_id') automatically
});
// No identify() call needed — the widget picks up the userId on its own
Option B: deferred identify() via dataLayerjavascript
// 1. Init widget immediately (GTM tag)
Respondo.init({ agentId: 'YOUR_AGENT_ID' });

// 2. Later, when user data appears (e.g. from dataLayer or your app):
var waitForUser = setInterval(function() {
  var uid = localStorage.getItem('myapp_user_id');
  if (uid && window.Respondo && typeof window.Respondo.identify === 'function') {
    clearInterval(waitForUser);
    Respondo.identify({ userId: uid });
  }
}, 500);
localStorageKey is only used if no userId is already set via identify(). Explicit identify() calls always take precedence.

Identity Verification (HMAC)#

Without verification, anyone could impersonate a user by passing a fake userId or email. Identity Verification uses HMAC-SHA256 to cryptographically prove the user's identity was set by your server, not by client-side code.

How it works#

  1. Enable Identity Verification in your channel settings — you'll get a secret key.
  2. On your server, compute HMAC-SHA256(userId, secret) and send the result to the frontend.
  3. Pass the hash as userHash in Respondo.identify().
  4. Respondo verifies the hash server-side. If invalid, identity is stripped and the user is treated as anonymous.
Never expose your secret key in frontend code. The HMAC must be computed on your backend.

Server-side examples#

Node.jsjavascript
const crypto = require('crypto');

const SECRET = process.env.RESPONDO_IDENTITY_SECRET;

function generateUserHash(userId) {
  return crypto
    .createHmac('sha256', SECRET)
    .update(userId)
    .digest('hex');
}

// In your API endpoint:
app.get('/api/respondo-hash', (req, res) => {
  const hash = generateUserHash(req.user.id);
  res.json({ userHash: hash });
});
Pythonpython
import hmac, hashlib, os

SECRET = os.environ['RESPONDO_IDENTITY_SECRET']

def generate_user_hash(user_id: str) -> str:
    return hmac.new(
        SECRET.encode(),
        user_id.encode(),
        hashlib.sha256
    ).hexdigest()

# In your view / endpoint:
user_hash = generate_user_hash(request.user.id)
Gogo
import (
    "crypto/hmac"
    "crypto/sha256"
    "encoding/hex"
)

func GenerateUserHash(userID, secret string) string {
    mac := hmac.New(sha256.New, []byte(secret))
    mac.Write([]byte(userID))
    return hex.EncodeToString(mac.Sum(nil))
}

Frontend usage#

With Identity Verificationjavascript
// Fetch the hash from YOUR server
const { userHash } = await fetch('/api/respondo-hash').then(r => r.json());

Respondo.identify({
  email: user.email,
  name: user.name,
  userId: user.id,
  userHash: userHash  // HMAC-SHA256 signature
});