AI Chatbot Management

Identity Verification

Authenticate logged-in users in the Verly widget and power user-aware actions with verified contact data.

Identity verification lets your website tell Verly who the current logged-in user is. Once verified, the widget can personalize conversations, resolve the right contact record, and fill custom action variables with trusted user data.

What Identity Verification Enables

  • Personalized conversations so the agent can greet users by name and respond with account-aware context.
  • Authenticated actions using template variables like {{contact.externalId}} and {{contact.metadata.plan}}.
  • Automatic contact sync by creating or updating the Verly contact from the verified JWT.
  • Safer shared-device behavior when you reset identity on logout.

Before You Start

  • Your website already has the Verly widget embed script installed.
  • Identity verification is enabled for the chatbot in Deploy > Identity.
  • Your backend can sign JWTs with HS256.
  • Your identity secret is stored only on the server.
Never generate the JWT in the browser or expose your identity secret in client-side code.

How It Works

  1. A user signs in to your app.
  2. Your backend signs a JWT with the chatbot's identity secret.
  3. Your frontend calls window.conversly("identify", { token, ...publicMeta }).
  4. The widget sends the JWT and public metadata to Verly with each request.
  5. Verly verifies the token, resolves the contact, and injects trusted identity data into the session and custom actions.
  6. On logout, your app calls window.conversly("resetUser") to clear the stored identity and session references.

Step 1: Generate Your Identity Secret

  1. Open your chatbot in the Verly dashboard.
  2. Go to Deploy.
  3. Open the Identity tab.
  4. Click Generate Secret.
  5. Copy the generated secret and store it in a backend environment variable.

The generated secret starts with iv_. Rotating the secret immediately invalidates previously issued JWTs.

Step 2: Sign a JWT on Your Server

Use any JWT library that supports HS256. The token must include either sub or user_id, plus an exp timestamp.

const jwt = require("jsonwebtoken");

const secret = process.env.CONVERSLY_IDENTITY_SECRET;

function createConverslyIdentityToken(user) {
  return jwt.sign(
    {
      sub: user.id,
      email: user.email,
      name: user.name,
      phonenumber: user.phone,
      custom_attributes: {
        plan: user.plan,
        company_id: user.companyId,
        support_tier: user.supportTier,
      },
      exp: Math.floor(Date.now() / 1000) + 60 * 60,
    },
    secret,
    { algorithm: "HS256" }
  );
}

JWT Claims Reference

ClaimRequiredPurpose
sub or user_idYesStable unique user identifier. Stored as the contact's external ID.
expYesExpiration timestamp in Unix seconds. Recommended: 1 hour. Maximum: 24 hours.
emailNoStored on the contact and available to actions.
nameNoStored on the contact and available to the AI session.
phonenumberNoStored on the contact and available to actions.
custom_attributesNoArbitrary key-value data merged into contact metadata. Max serialized size: 4 KB.
Use a stable database ID or UUID for sub or user_id. Avoid identifiers like email or username if those values can change.

Step 3: Identify the User in the Widget

The widget API is exposed as window.conversly(...).

const response = await fetch("/api/conversly/identity-token");
const { token, user } = await response.json();

window.conversly("identify", {
  token,
  name: user.firstName,
  plan: user.plan,
});

Anything passed outside the JWT, such as name or plan, is treated as public session metadata. It can help the agent personalize replies, but it is not persisted to the contact record and does not power {{contact.*}} variables in actions.

Alternative: pre-load identity before the widget initializes

<script>
  window.converslyUserConfig = {
    token: identityTokenFromYourBackend,
    name: currentUser.firstName,
    plan: currentUser.plan
  };
</script>

<script
  src="https://widget.verlyai.xyz/embed.js"
  data-chatbot-id="bot_123"
></script>

Step 4: Reset Identity on Logout

window.conversly("resetUser");

This clears the stored identity token plus the local contact and conversation references. Always do this on logout, especially on shared browsers.

What Verly Stores and What the AI Can See

Data sourceVisible to the AI in-session?Available in custom actions?Persisted to contact?
Public metadata passed to identify()YesNoNo
Standard JWT fields like sub, email, name, phonenumberYesYes, via {{contact.*}}Yes
custom_attributes inside the JWTYesYes, via {{contact.metadata.*}}Yes

Template variables are resolved server-side from verified data. The model can use identity context in conversation, but it cannot forge {{contact.*}} values sent to your APIs.

Using Identity in Custom Actions

Once a user is verified, these variables are available in custom actions automatically:

VariableValue
{{contact.externalId}}The verified sub or user_id
{{contact.email}}The contact email from the JWT
{{contact.name}}The contact name from the JWT
{{contact.phone}}The contact phone number from the JWT
{{contact.id}}The internal Verly contact ID
{{contact.metadata.<key>}}Any value from custom_attributes

Example request configuration:

GET https://api.yourapp.com/companies/{{contact.metadata.company_id}}/users/{{contact.externalId}}/orders
X-Support-Tier: {{contact.metadata.support_tier}}

If a verified user asks, "Show me my recent orders," Verly can call your action with those placeholders already filled from the verified identity.

Contact Behavior

  • First verified session: Verly creates a contact with the external ID from the JWT.
  • Returning verified user: Verly finds the existing contact by external ID and updates provided fields.
  • Anonymous to verified: An existing visitor contact can be upgraded when identity is later supplied.
  • Different user on the same browser: Verly will not merge contacts across different external IDs.
  • Missing fields: Omitted fields are preserved on the existing contact.
  • Metadata updates: custom_attributes are shallow-merged into contact metadata.

Failure Behavior

Identity verification is designed to fail safely:

  • Invalid or malformed JWT: the chat continues in anonymous mode.
  • Expired JWT: the session degrades to anonymous mode until you identify the user again with a fresh token.
  • Oversized metadata payloads: identity metadata beyond the supported size limits is ignored.

End users do not see an error banner when this happens. The conversation still works, but user-aware actions and personalization will not.

Troubleshooting

The chatbot does not recognize the user

Check the following:

  • Identity verification is enabled in Deploy > Identity.
  • Your backend is signing with the current secret.
  • The JWT includes sub or user_id.
  • The token is not expired.
  • You are calling window.conversly("identify", ...), not a stale integration helper.

{{contact.*}} variables are empty in actions

Check the following:

  • The relevant fields are inside the JWT, not only in public metadata.
  • custom_attributes keys are flat and spelled exactly as referenced.
  • The JWT is being sent before the action-triggering message.

Users share a browser and see the wrong session

Always call window.conversly("resetUser") during logout or account switching.

Best Practices

  • Keep JWT lifetimes short. One hour is a good default.
  • Put action-critical data inside the JWT custom_attributes, not only in public metadata.
  • Re-issue a fresh token after login, account switching, or secret rotation.
  • Treat identity verification as best-effort and make your frontend resilient to anonymous fallback.
Copyright © 2026