Quickstart
Create a custom widget channel, connect the visitor SDK, and exchange your first messages in a few minutes.
1. Create the channel
In the dashboard, go to Settings → Channels → Widget → Add widget and pick
Custom widget. The configurator opens on the Install tab, which shows your
integration snippet with the channel id (live_chat_…) already filled in.
2. Allowlist your origins
A fresh channel accepts every origin. Under Install → Advanced security
settings, enable the allowed-domains gate and list the origins your frontend
runs on (e.g. https://www.example.com). Requests from anywhere else are
rejected at the CORS layer.
During local development, add your dev origin (e.g. http://localhost:3000)
too — or leave the gate off until you go live.
3. Connect and exchange messages
Import the SDK as an ES module and create a client with your channel id:
<script type="module">
import { createChatClient } from "https://widget.k2.konvoai.com/sdk.js";
const chat = createChatClient({ channelId: "live_chat_YOUR_CHANNEL_ID" });
chat.on("message", (message) => {
// An agent (human or AI) replied — render it in your UI.
console.log(message.body);
});
await chat.connect();
chat.sendMessage({ body: "Hello!" });
</script>connect() runs the auth handshake and resolves once the realtime connection
is open. After that, sendMessage returns immediately with a message id; the
ack event fires with the same id once the server has durably accepted the
message.
4. Restore history on page load
Visitors expect their conversation to survive a reload. Fetch it before (or while) connecting:
const { streamId, messages } = await chat.getHistory();
for (const message of messages) {
// message.author is "user" (the visitor) or "agent".
render(message);
}streamId is null when the visitor has no open conversation yet.
5. Wire up the rest
A production chat UI usually also wants:
// Typing indicators — both directions.
chat.on("typing", ({ active, displayName }) => showTypingIndicator(active));
input.addEventListener("input", () => chat.sendTyping(true));
// Read receipts on agent messages you render.
chat.on("message", (message) => {
render(message);
chat.markDelivered(message.id);
chat.markSeen(message.id); // when it's actually on screen
});
// Attachments: upload first, then reference the uploadId.
const upload = await chat.uploadAttachment(file);
chat.sendMessage({ body: "", attachmentIds: [upload.uploadId] });
// Link the visitor's email once you know it.
await chat.identify("visitor@example.com");
// Connection state for your "reconnecting…" hint.
chat.on("connection", ({ status, issue }) => updateBanner(status, issue));The full method and event surface — including error codes and limits — is in the SDK reference.