Web Chatbot SDK
A plain-JavaScript client for the EnableX Dialogs web channel. It wraps the guest Socket.IO connection and channel-web REST API described in Chat Bots so you can build a custom chat UI without implementing session handling, reconnects, or event parsing yourself.
First release of the Web Chatbot SDK. See Release Notes for what's included.
Download Web Chatbot SDK v1.0.0Dependencies
Load the Socket.IO client before this script:
<script src="https://cdn.socket.io/4.7.2/socket.io.min.js"></script>
<script src="dialogs-chatbot-web-v1.0.js"></script>
Minimal Usage
var chat = createDialogsChat({
host: 'https://your-chatbot-host.com',
botId: 'your-bot-id',
ROOT_PATH: '' // or '/api' if your API is under a path
});
chat.on('message', function (data) {
if (data.authorId) return; // skip echoed user message
var text = data.payload && data.payload.text;
if (text) console.log('Bot:', text);
});
chat.on('typing', function (data) {
console.log('Bot typing for', data.timeInMs, 'ms');
});
chat.connect()
.then(function () { return chat.createConversation(); })
.then(function (conversationId) {
return chat.sendMessage(conversationId, { type: 'text', text: 'Hello' });
})
.catch(function (err) { console.error(err); });
Creating a Client
| Function | Description |
|---|---|
createDialogsChat(config) | Creates a chat client. config: { host, botId, ROOT_PATH?, reconnect? }. Returns the client instance. |
chat.init(config) | (Optional) Set or update config after create. Same keys. Reconnect config: reconnect: { autoReconnect: true, maxAttempts: 5, delayMs: 2000 }. |
Connection and Session
| Function | Description |
|---|---|
chat.validateHost(origin?) | Optional. Calls the server validation endpoint (same as the official embed). Resolves if the current origin is allowed for this bot, rejects otherwise. origin defaults to window.location.origin. Use before connect() to enforce a client-side domain check. |
chat.connect() | Connects to the Dialogs guest socket. Must be called before any conversation or message API. Returns a Promise that resolves when connected. |
chat.reconnect() | Manually reconnect: disconnects (if connected) and calls connect() again. Returns the same Promise as connect(). |
chat.disableAutoReconnect() | Turns off auto-reconnect and clears any pending reconnect timer. |
chat.disconnect() | Closes the socket connection and clears reconnect timer. Emits a disconnect event. |
chat.isConnected() | Returns true if the socket is connected and webSessionId is available. |
chat.getWebSessionId() | Returns the current webSessionId (for debugging or custom API calls). |
Methods that require a connection (listConversations, getConversation, createConversation, resetConversation, sendMessage, sendFile) check both socket connection and webSessionId; if either is missing they reject with "Not connected. Call connect() first." Methods that don't use the session (getBotInfo, validateHost) may be called while disconnected.
Conversations
| Function | Description |
|---|---|
chat.listConversations(startupData?) | Lists conversations for the current user. Requires connect() first. Optional startupData: { name, email, phone, custom_id, isEmulator }. Returns a Promise with { conversations: [...] }. |
chat.getConversation(conversationId) | Loads one conversation with full message history. Requires connect() first. Returns a Promise with { id, messages: [...] }. |
chat.createConversation() | Creates a new conversation. Requires connect() first. Returns a Promise<conversationId> and sets it as the "current" conversation for sendMessage. |
chat.resetConversation(conversationId?) | Resets a conversation (clears the dialog session). Requires connect() first. conversationId optional; uses current if omitted. Listen for on('clear'), then call createConversation() for a new thread. |
chat.getBotInfo() | Fetches bot metadata (name, description, theme, startup message, etc). Does not require connect(). Uses config.botId from init(). |
chat.getConversationId() | Returns the current conversation id (from the last createConversation() or setConversationId()). |
chat.setConversationId(id) | Sets the current conversation id so sendMessage() without a first argument uses this id. |
Sending Messages
| Function | Description |
|---|---|
chat.sendMessage(conversationId, payload) | payload must include type (e.g. 'text') and type-specific fields (e.g. text: 'Hello'). conversationId optional — uses current if omitted. Returns a Promise that resolves when the request succeeds; the bot reply arrives via on('message'). |
chat.sendFile(conversationId, file, optionalPayload?) | Uploads a file via POST /messages/files (multipart/form-data). conversationId optional (uses current). file: File or Blob. optionalPayload: optional object (e.g. { caption: '...' }) sent as a JSON string. The file appears as a message; the bot reply may arrive via on('message') with payload.type === 'file' or 'image'. |
Events
Subscribe with chat.on(event, callback); unsubscribe with chat.off(event, callback).
| Event | When it fires | Callback argument |
|---|---|---|
'message' | A bot/agent message is received (not the echoed user message) | Message object: { id, conversationId, authorId, sentOn, payload: { type, text, ... }, ... } |
'typing' | The bot typing indicator is received | { timeInMs, conversationId } — show "typing…" for timeInMs ms |
'clear' | After resetConversation() — server sends guest.webchat.clear | Event data — use to clear the message list UI |
Reconnect events: disconnect (socket closed), reconnecting (attempt N of M), reconnected (success), reconnect_failed (gave up after max attempts).
Feature Support (v1.0.0)
| Feature | Supported | Notes |
|---|---|---|
| Connect to Dialogs backend | Yes | Guest socket + webSessionId; visitor id stored in localStorage. |
| Create a new conversation | Yes | createConversation() → convoId. |
| Send text messages | Yes | sendMessage(id, { type: 'text', text: '...' }). |
| Receive bot messages | Yes | Subscribe with on('message', fn); filter by !data.authorId for bot-only. |
| Typing indicator | Yes | Subscribe with on('typing', fn); use data.timeInMs. |
| Current conversation | Yes | getConversationId(), setConversationId(id); sendMessage() can omit the first argument. |
| List conversations | Yes | listConversations(startupData?) → pick a conversation for returning users. |
| Load conversation history | Yes | getConversation(conversationId) → convo.messages; render by authorId (user) vs. bot. |
| Reset conversation | Yes | resetConversation(conversationId?); listen on('clear'), then createConversation() for a new thread. |
| Bot info (name, theme, etc.) | Yes | getBotInfo() (no connect required). |
| File upload | Yes | sendFile(conversationId?, file, optionalPayload?) → POST /messages/files. |
| Send visit / other events | No | Not in this milestone — use the raw REST endpoint (see Chat Bots). |
| Quick reply / postback | No | Payload can be sent manually; the SDK does not parse or expose quick-reply UI. |
| Preferences (language) | No | Not in this milestone. |
Agent handoff (handoverStatus) | No | Messages may contain payload.handoverStatus; the SDK does not emit a dedicated event for it yet. |
Click-to-call (clickToCallEvent) | No | Not in this milestone. |
Authentication and Host Validation
Identity is entirely based on a visitor id (generated and stored in
localStorage) and the guest Socket.IO connection (webSessionId).
There is no separate "login" step, and the SDK does not check that the page is allowed to use
the bot (domain whitelist) before connecting — it connects to whatever host and
botId you pass in.
This means anyone who can load your app (or any page that uses this script) and knows
host and botId can connect to the socket and start a conversation
with that bot. The channel-web API is intended for "guest" (unauthenticated) web chat: the
server typically has checkAuthentication: false for the bot's channel-web router,
and does not validate the Origin or Referer of the request.
How the Official Embed Differs
The official inject.js embed calls a validation endpoint before showing the
widget — GET {host}/lite/{botId}/validation/?domainName={window.location.origin}&...
— and does not inject the iframe if that request is rejected. This is client-side
enforcement only: it does not protect the channel-web API or socket, so a custom
client talking to the API/socket directly can bypass it.
Recommendations
- Configure the Dialogs server: if the bot supports a domain whitelist for the web channel, configure it so only your app's origin is allowed, and use CORS on the chatbot-engine server so only your frontend's origin can call REST and Socket.IO from a browser.
- Optional client-side validation: call
chat.validateHost()beforeconnect()to get the same client-side gate as the official embed — the server must expose and enforce that endpoint. - Sensitive bots: use your own authentication — either a backend proxy (your frontend talks only to your server, which calls the Dialogs API/socket on the user's behalf) or the
X-BP-ExternalAuth/ExternalAuthheader if the Dialogs server supports it. - Operational: apply rate limiting and monitoring on the Dialogs/server side, and keep
hostandbotIdout of public repos.