Developer
Widget SDK
Embed and control the ConverseLead chat widget on your website using the JavaScript SDK.
Installation
Add the widget script before the closing </body> tag on every page where you want the chat widget to appear.
<script src="https://your-server.com/static/widget.js"></script>
<script>
clchat('init', { apiKey: 'cl_YOUR_API_KEY' });
</script>The script automatically detects its own URL and uses the same origin for API calls, so no additional server configuration is needed.
Script URL
your-server.com with the domain where your ConverseLead instance is hosted. You can find this in your admin dashboard.API Overview
All widget methods are called through the global clchat() function. The first argument is always the method name, followed by an optional options object.
clchat('methodName', { /* options */ });Available methods:
| Method | Description |
|---|---|
init | Initialize the widget with your API key and options |
identify | Link the visitor to a known user in your system |
open | Open the chat window |
close | Close the chat window |
logout | Clear the session and start fresh |
init
Initialize the widget. This must be called once on page load before using any other method.
clchat('init', {
apiKey: 'cl_YOUR_API_KEY',
primaryColor: '#8b5cf6',
position: 'right',
});Options
| Name | Type | Description |
|---|---|---|
apiKey | string | Your website API key. Find this in the admin dashboard under Website Settings. Starts with cl_. |
primaryColor | string | Override the widget accent color. Accepts any hex color (e.g. #3b82f6). If omitted, uses the color set in your admin dashboard. |
position | 'right' | 'left' | Which corner to place the chat button. Default: right. |
notificationSound | boolean | Play a chime when a new message arrives while the widget is closed. Default: true. |
desktopNotifications | boolean | Show browser desktop notifications for new messages. Requires user permission. Default: false. |
autoOpenOnReply | boolean | Automatically open the widget when an agent or AI replies. Default: false. |
onNewMessage | function | Callback fired when a new agent or AI message arrives while the widget is closed. Receives a data object with conversationId, role, content, agentName, and createdAt. |
Single Page Apps (SPA)
init once when the app mounts. The widget persists across route changes automatically.identify
Link the current chat visitor to a known user in your application. This enables you to see customer names, emails, and metadata in the admin dashboard, and automatically promotes the contact from “lead” to “customer” status.
clchat('identify', {
externalUserId: 'user_12345',
name: 'Jane Doe',
email: '[email protected]',
phone: '+1 555-0100',
company: 'Acme Inc',
metadata: {
plan: 'enterprise',
accountId: 'acc_789',
},
});Options
| Name | Type | Description |
|---|---|---|
externalUserId | string | Your application's unique user ID. When provided, the contact is promoted from lead to customer. Used for cross-referencing between your system and ConverseLead. |
name | string | The user's display name. Shown to agents in the admin dashboard. |
email | string | Email address. Used for contact deduplication: if a contact with this email already exists, it will be merged rather than duplicated. |
phone | string | Phone number in any format. |
company | string | Company or organization name. |
metadata | object | Arbitrary key-value pairs for custom data. Maximum 20 keys, 500 characters per value. Useful for passing plan type, account info, feature flags, etc. |
When to call identify
Call identify whenever you know who the user is:
- After login — right after your user authenticates
- On page load — if the user is already logged in (check your session)
- After sign-up — immediately after account creation
You can call identify at any time — before or after a conversation has started. If a conversation already exists, the contact information is updated in place.
Example: React integration
import { useEffect } from 'react';
import { useUser } from './auth'; // your auth hook
function App() {
const user = useUser();
useEffect(() => {
// Initialize widget once
clchat('init', { apiKey: 'cl_YOUR_API_KEY' });
}, []);
useEffect(() => {
// Identify when user logs in
if (user) {
clchat('identify', {
externalUserId: user.id,
name: user.name,
email: user.email,
metadata: {
plan: user.plan,
role: user.role,
},
});
}
}, [user]);
return <div>...</div>;
}Example: Next.js integration
// app/layout.tsx or a client component
'use client';
import { useEffect } from 'react';
import Script from 'next/script';
export function ChatWidget({ user }) {
useEffect(() => {
if (typeof window.clchat === 'undefined') return;
clchat('init', { apiKey: 'cl_YOUR_API_KEY' });
if (user) {
clchat('identify', {
externalUserId: user.id,
name: user.name,
email: user.email,
});
}
}, [user]);
return (
<Script
src="https://your-server.com/static/widget.js"
strategy="afterInteractive"
/>
);
}open & close
Programmatically control the widget visibility. Useful for triggering the chat from custom UI elements.
// Open the chat window
clchat('open');
// Close the chat window
clchat('close');Common use cases
- Custom “Need help?” button that opens the chat
- Triggering chat after a failed action (e.g. payment error)
- Opening chat from a help menu or navigation link
- Closing chat after a successful resolution
<!-- Custom help button -->
<button onclick="clchat('open')">
Need help? Chat with us
</button>logout
Clear the current visitor session and reset the widget to an anonymous state. Call this when your user logs out of your application.
// When user logs out of your app
function handleLogout() {
// Clear your app's session
auth.signOut();
// Reset the chat widget
clchat('logout');
}This clears all locally stored data (visitor ID, conversation history reference, contact info). The next visitor will get a fresh, anonymous session.
Important
logout when your user signs out. Without this, the next person to use the same browser could see the previous user's chat session.Visitor Lifecycle
Every visitor gets an automatically generated anonymous ID that persists across page loads on the same domain.
- Generated automatically on the first
initcall if none exists - Survives page navigations and full page refreshes
- Cleared when
logoutis called or browser storage is cleared - Unique per domain — different sites and incognito windows get separate IDs
The visitor ID is the foundation of session continuity. It allows a visitor to return to your site and see their previous conversation history, even if they haven't identified themselves.
Conversation Behavior
Lazy creation
Conversations are created only when the visitor sends their first message, not when the widget loads. This means:
- No empty conversations clutter your dashboard from page views
- Bot traffic and idle visitors don't create noise
- Conversation counts accurately reflect real engagement
Conversation expiry
After 30 minutes of inactivity (configurable), the widget automatically starts a new conversation the next time the visitor sends a message. The previous conversation is preserved and remains accessible in the admin dashboard.
Conversation history
When a returning visitor opens the widget, their most recent conversation is loaded automatically with full message history. Older messages are loaded on scroll via pagination.
File Sharing
Visitors can share files directly through the chat widget using the attachment button. Supported file types:
| Category | Formats |
|---|---|
| Images | JPG, PNG, GIF, WebP |
| Videos | MP4, WebM, MOV |
| Audio | MP3, WAV, WebM |
| Documents | PDF, DOC, DOCX, TXT |
Maximum file size is 50 MB. Images and videos are displayed inline in the conversation. Documents and other files appear as downloadable attachments.
Escalation to Human
The widget includes a built-in “Talk to a human” option that visitors can use to request a human agent. When triggered:
- The AI stops responding automatically
- A banner appears: “A human will respond shortly”
- Your team is notified via email and/or Slack (if configured)
- Once an agent replies, the banner disappears and the conversation continues normally
The AI can also trigger escalation automatically when it determines the visitor needs human assistance.
Real-time Features
The widget maintains a live connection for real-time updates:
- Instant messages — agent replies appear immediately without polling
- Typing indicators — visitors see animated dots when an agent is typing
- Status updates — escalation banners and conversation state changes are reflected live
- Background notifications — badge, toast, and sound alerts when the widget is minimized
The connection automatically reconnects if it drops due to network issues.
Notifications
When the widget is minimized, visitors are notified of new messages through multiple channels:
- Unread badge — a red counter appears on the chat bubble
- Toast preview — a small popup shows the agent name and message snippet
- Sound — a short chime plays (disable with
notificationSound: false) - Desktop notifications — browser notifications when enabled and permitted
Opening the widget clears the badge and marks all messages as read. The unread state persists across page reloads.
Options
Configure notification behavior through init options:
clchat('init', {
apiKey: 'cl_YOUR_API_KEY',
// Notification options
notificationSound: true, // Play a chime on new messages (default: true)
desktopNotifications: false, // Browser notifications (default: false)
autoOpenOnReply: false, // Auto-open widget on reply (default: false)
onNewMessage: function(data) { // Callback for new messages (optional)
console.log(data.agentName + ': ' + data.content);
},
});| Name | Type | Description |
|---|---|---|
notificationSound | boolean | Play a short chime when a message arrives while the widget is closed. A 2-second cooldown prevents rapid sounds. Default: true. |
desktopNotifications | boolean | Show browser desktop notifications for new messages. The widget requests permission on the first incoming message. If the user denies, notifications are silently skipped. Default: false. |
autoOpenOnReply | boolean | Automatically open the widget when an agent or AI replies while it is closed. Default: false. |
onNewMessage | function | Callback fired for each new agent or AI message that arrives while the widget is closed. Does not fire for the visitor's own messages. |
onNewMessage callback
Use the onNewMessage callback to react to incoming messages in your own UI — for example, showing a custom banner or tracking analytics.
clchat('init', {
apiKey: 'cl_YOUR_API_KEY',
onNewMessage: function(data) {
console.log(data.agentName + ': ' + data.content);
},
});The callback receives a single object with the following fields:
| Name | Type | Description |
|---|---|---|
conversationId | string | The ID of the conversation the message belongs to. |
role | string | Always 'assistant' for both AI and human agent messages. |
content | string | The message text content. |
agentName | string | Display name of the agent (e.g. 'Sofia', 'Marco'). |
createdAt | string | ISO 8601 timestamp of when the message was created. |
Optional
CSS Isolation
The widget renders inside an iframe, so its styles are fully isolated from your page. Your CSS won't affect the widget, and the widget won't affect your page layout.
No style conflicts
Troubleshooting
Widget doesn't appear
- Verify the script URL is correct and accessible
- Check the browser console for errors
- Ensure
clchat('init', ...)is called after the script has loaded - Confirm your API key is valid and matches the website in your dashboard
Chat history not loading
- The visitor ID is stored in
localStorage. If your site clears storage, history will be lost. - Different subdomains are treated as different sites. Use the same domain for continuity.
- Incognito/private browsing starts a fresh session every time.
identify not working
- Make sure
inithas been called first - The contact may take a moment to appear in the admin dashboard
- Check that at least one field (email, name, or externalUserId) is provided