Web Chat Identity Verification

Pass verified user identity from your website to the Convrs Web Chat widget using JSON Web Tokens (JWTs). This allows agents, chatbots, and AI to know exactly who they are talking to — without relying on the user to identify themselves.

When the chat widget runs on an authenticated page (such as a customer portal, banking dashboard, or account area), your backend already knows who the user is. JWT identity verification lets you securely pass that information to Convrs so it can be used throughout the conversation.

What this enables:

  • Agents see verified customer details (name, account number, CRM link) without asking
  • Chatbots can personalize responses and access user-specific data in flow logic
  • AI has richer context for generating relevant answers
  • Returning users are automatically reconnected to their chat history, even across devices or after clearing cookies

What is a JWT?

A JSON Web Token (JWT) is an industry-standard method for securely transmitting information between two systems. It is widely used by platforms such as Stripe, Auth0, Intercom, and Zendesk for identity verification.

Agent Chat showing verified user details passed via JWT, including identity fields, status badges, and custom data in the user panel
An example of what agents see when a user connects with a JWT — verified identity, account details, and custom fields are displayed automatically in the user panel.

How JWT Works

A JWT is a short string of text that contains a set of claims (data about the user) and a cryptographic signature that proves the data has not been tampered with.

A JWT has three parts separated by dots: header.payload.signature

  • Header — identifies the token type and signing algorithm (always HS256 for Convrs)
  • Payload — contains the user data (name, email, account number, etc.)
  • Signature — a cryptographic hash that verifies the token was created by your server using your secret key

The token is generated by your backend server using a shared secret key that only your server and Convrs know. The user's browser carries the token but cannot read, modify, or forge it. When Convrs receives the token, it verifies the signature to confirm the data is authentic and has not been altered.

Why is this secure?

Without the signing secret, it is mathematically impossible to create a valid token. Even if someone intercepts a token in the browser, they cannot change the user's name, email, or any other field — any modification invalidates the signature. This is the same approach used by banks, payment processors, and identity providers worldwide.

Setup Overview

Setting up JWT identity verification involves three steps: generating a signing secret in Convrs, creating tokens on your backend, and adding a single line of JavaScript to your page.

Step 1 — Generate a Signing Secret

Create a signing secret in the Convrs administration panel. This secret is shared between your backend and Convrs.

Warning
Treat the signing secret like a password. Never expose it in client-side JavaScript, commit it to source control, or include it in API responses. If compromised, rotate it immediately from the Developer - WebChat panel.

Steps:

  1. Navigate to Administration > Organization Settings > Developer - WebChat.
  2. Click Generate Secret.
  3. Copy the secret and store it securely on your server (e.g. in an environment variable). This is the only time the full secret is shown.

Step 2 — Generate a JWT on Your Backend

When a user logs into your site, generate a JWT containing their identity information. This should be done server-side, never in the browser.

Use an established JWT library for your programming language. We recommend:

  • Node.jsjsonwebtoken (maintained by Auth0)
  • PythonPyJWT
  • PHPfirebase/php-jwt
  • Javaio.jsonwebtoken / jjwt
  • Rubyruby-jwt

Node.js example:

const jwt = require('jsonwebtoken');

const token = jwt.sign(
  {
    userId: 'user-12345',
    email: 'jane@example.com',
    name: 'Jane Doe',
  },
  process.env.CONVRS_SIGNING_SECRET,
  { algorithm: 'HS256', expiresIn: '1h' }
);

Python example:

import jwt, time, os

token = jwt.encode(
    {
        "userId": "user-12345",
        "email": "jane@example.com",
        "name": "Jane Doe",
        "exp": int(time.time()) + 3600,
    },
    os.environ["CONVRS_SIGNING_SECRET"],
    algorithm="HS256",
)
Token Expiry

Always set an expiry time (exp) on your tokens. We recommend 1 hour. The token is read when the chat widget connects, so a short-lived token limits the window for replay if intercepted. Generate the token once at login and reuse it across page loads within its lifetime.

Step 3 — Add the Token to Your Page

Pass the token to the chat widget by setting a global JavaScript variable on your page. This can appear anywhere — before or after the widget script tag.

Note
The token is a single string value — not an object. Set it as var ConvrsUser = "your.jwt.string";
Caching Warning

Pages containing the JWT token must not be cached by CDNs or edge servers. Set Cache-Control: private on any page that includes the token to prevent one user's identity from being served to another.

Steps:

  1. Set a global JavaScript variable called ConvrsUser containing the token string. Output this from your backend template into a script tag anywhere on the page.
<!-- Your existing Convrs webchat embed -->
<script defer id="convrs-webchat"
  src="https://webchat.conv.rs/YOUR_WIDGET_ID.js">
</script>

<!-- Add this anywhere on the page -->
<script>var ConvrsUser = "eyJhbGciOi...";</script>

The widget reads ConvrsUser when it opens the WebSocket connection. If the variable is not set, the widget operates normally without identity verification.

JWT Payload Fields

The JWT payload contains the data you want to pass to Convrs. Fields are divided into identity fields, automation data, and agent display data.

Identity Fields

These fields identify the user and update their contact record in Convrs.

Note
The userId field creates a permanent mapping between your user and their Convrs identity. If a user clears their cookies or switches devices, the userId ensures they are reconnected to the same conversation history. Use a stable ID (database primary key, UUID) — not an email address, which may change.
FieldTypeRequiredDescription
userIdStringRecommendedA stable, unique identifier for the user in your system (e.g. database ID, UUID). Used to permanently link the user to their Convrs chat history across devices and sessions. Without this, returning users who clear cookies will appear as new visitors.
emailStringNoThe user's email address. Must be a valid email format — invalid addresses are silently ignored.
nameStringNoThe user's display name. Replaces the randomly generated name assigned to anonymous visitors. Automatically split into first and last name for the agent's contact panel.
phoneStringNoPhone number in international format (e.g. +447700900123).
localeStringNoLanguage/locale code (e.g. en-GB, fr-FR). Sets the user's language preference for the conversation.
crmIDStringNoAn identifier that links the user to a record in your CRM system. Displayed to agents alongside a link if a CRM integration is configured.

User Data (userData)

The userData object passes custom data that is available to chatbot flows and logic blocks. This allows your chatbot to personalize responses and make decisions based on information from your system — without needing API calls during the conversation.

{
  "userData": {
    "accountNumber": "AC-12345",
    "plan": "enterprise",
    "vipTier": "gold",
    "companyName": "Acme Corporation",
    "activeSince": "2023-01-15"
  }
}

userData is a freeform key-value object — you control the keys and values. There is no fixed schema. Values can be strings, numbers, or booleans.

How it works with flows:

  • Data is stored on the user's record and merged with any existing userData (top-level keys are updated; keys not present in the JWT are left unchanged)
  • In the Flow Builder, access values using logic blocks with the syntax {{userData.accountNumber}}
  • Use conditions like userData.plan == "enterprise" to branch conversation flows
  • The data is available immediately — no API calls or integrations required
Example Use Cases
  • Route VIP customers to a priority queue based on userData.vipTier
  • Greet the user by company name: "Welcome, {{userData.companyName}}!"
  • Skip identity verification steps if userData.accountNumber is already set
  • Show different product options based on userData.plan

Warning
Do not include sensitive data (passwords, API keys, credit card numbers) in userData. While the JWT is signed, the payload is base64-encoded and can be read by anyone with access to the browser.

Agent Display Data (agentData)

The agentData array defines information displayed to agents in the user panel during a live chat. Unlike userData (which is for chatbot automation), agentData is specifically designed for human agents and supports rich formatting.

Each item in the array is an object with a label (what the agent sees as the field name) and a value (the data). Items are displayed in the order they appear in the array, giving you full control over the layout.

{
  "agentData": [
    { "label": "Account",      "value": "AC-12345" },
    { "label": "Plan",         "value": "Enterprise", "type": "status", "color": "info" },
    { "label": "VIP Tier",     "value": "Gold",       "type": "status", "color": "warning" },
    { "label": "Verified",     "value": true,         "type": "boolean" },
    { "label": "Member Since", "value": "2024-03-15", "type": "date" },
    { "label": "Last Login",   "value": "2026-04-23T14:30:00Z", "type": "datetime" },
    { "label": "Balance",      "value": 1250.00,      "type": "currency", "currency": "USD" },
    { "label": "Points",       "value": 48750,        "type": "number" },
    { "label": "Email",        "value": "jane@example.com", "type": "email" },
    { "label": "Mobile",       "value": "+447700900123",     "type": "phone" },
    { "label": "CRM Record",   "value": "https://crm.example.com/12345", "type": "link", "text": "View in CRM" }
  ]
}

Agents see this data in a Visitor Details card in the user panel, with a lock icon indicating the data has been verified and can be trusted.

FieldRequiredDescription
labelYesThe field name displayed to the agent (e.g. "Account Number", "Plan")
valueYesThe data value — can be a string, number, or boolean depending on the type
typeNoFormatting type (see table below). Defaults to plain text if omitted.

Supported Display Types

The type field controls how the value is formatted for the agent. If omitted, the value is displayed as plain text.

TypeValue FormatRenders AsAdditional Fields
(default)StringBold text
dateDate string (e.g. 2024-03-15)Formatted date in the agent's locale (e.g. "15 Mar 2024")
datetimeISO 8601 string (e.g. 2026-04-23T14:30:00Z)Formatted date and time in the agent's locale (e.g. "23 Apr 2026, 14:30")
numberNumberLocale-formatted number with thousand separators (e.g. "48,750")
currencyNumberCurrency-formatted number (e.g. "$1,250.00")currency — ISO 4217 code (e.g. USD, GBP, EUR)
emailStringClickable email link
phoneStringClickable phone link
linkURL stringClickable link (opens in new tab)text — display text shown instead of the URL (e.g. "View in CRM")
booleantrue or falseGreen checkmark or red cross icon
statusStringColoured badge/pillcolor — one of: success (green), danger (red), warning (yellow), info (blue), primary (default blue), secondary (grey)

Full Example

A complete example showing all available fields in a single JWT payload.

Complete JWT Payload

This example includes identity fields, automation data, and agent display data.

{
  "userId": "user-12345",
  "email": "jane@example.com",
  "name": "Jane Doe",
  "phone": "+447700900123",
  "locale": "en-GB",
  "crmID": "CRM-56789",

  "userData": {
    "accountNumber": "AC-12345",
    "plan": "enterprise",
    "vipTier": "gold"
  },

  "agentData": [
    { "label": "Account",      "value": "AC-12345" },
    { "label": "Plan",         "value": "Enterprise", "type": "status", "color": "info" },
    { "label": "VIP Tier",     "value": "Gold",       "type": "status", "color": "warning" },
    { "label": "Verified",     "value": true,         "type": "boolean" },
    { "label": "Balance",      "value": 1250.00,      "type": "currency", "currency": "USD" },
    { "label": "CRM Record",   "value": "https://crm.example.com/12345", "type": "link", "text": "View in CRM" }
  ]
}

Node.js — generating and outputting the token:

// Server-side (e.g. Express route handler)
const jwt = require('jsonwebtoken');

app.get('/dashboard', (req, res) => {
  const user = req.session.user; // your authenticated user

  const convrsToken = jwt.sign(
    {
      userId: user.id,
      email: user.email,
      name: user.fullName,
      userData: {
        accountNumber: user.accountNumber,
        plan: user.plan,
      },
      agentData: [
        { label: 'Account', value: user.accountNumber },
        { label: 'Plan',    value: user.plan, type: 'status', color: 'info' },
      ],
    },
    process.env.CONVRS_SIGNING_SECRET,
    { algorithm: 'HS256', expiresIn: '1h' }
  );

  res.render('dashboard', { convrsToken });
});

HTML template output:

<script>var ConvrsUser = "{{convrsToken}}";</script>
<script defer id="convrs-webchat"
  src="https://webchat.conv.rs/YOUR_WIDGET_ID.js">
</script>

Best Practices

Follow these recommendations for a secure and reliable integration.

Security

Recommendations for keeping your integration secure.

  • Always use HS256 — this is the only signing algorithm accepted by Convrs
  • Set an expiry — use expiresIn: '1h' (or the exp claim) to limit the token's lifetime
  • Generate tokens server-side only — never expose the signing secret in client-side code
  • Store the secret securely — use environment variables, not configuration files committed to source control
  • Rotate secrets if compromised — use the Rotate Secret feature in the Developer - WebChat panel, which provides a 48-hour grace period for the previous secret
  • Do not cache pages with tokens — set Cache-Control: private to prevent CDNs from serving one user's token to another

Token Lifecycle

How to manage token generation and refresh.

  • Generate once at login — create the token when the user authenticates and store it in the server-side session
  • Reuse across page loads — output the same token on each page within its lifetime, rather than generating a new one per page
  • Refresh before expiry — if using a single-page application, regenerate the token at 75% of its lifetime (e.g. after 45 minutes for a 1-hour token)
  • For SPAs and static sites — expose a /api/chat-token endpoint that returns a fresh token, and call it when the page loads

Testing

Use the built-in token verification tool to test your integration before going live.

Note
This verifies the token against your organization's signing secret and checks for expiry — exactly the same validation that happens when a user connects with the widget. See Organization Settings for full details on the Developer - WebChat panel.

Steps:

  1. Navigate to Administration > Organization Settings > Developer - WebChat.
  2. Paste your JWT token into the Test a JWT Token field.
  3. Click Verify Token.
  4. If valid, you will see the decoded payload with all the fields. If invalid, you will see the specific error (expired, invalid signature, etc.).
Convrs Web Chat API