Web / vanilla JS
For the web SDK, plain HTML pages, Vue, Svelte, or any non-React framework.
On this page
1. Drop-in chat widget
Paste this into any HTML page. No build, no framework. The widget hits your backend for a token, opens the chat WebSocket, and renders a minimal but styled chat panel.
<!-- Anywhere in your HTML -->
<div
id="kl-chat"
data-channel-id="chn_abc123"
data-token-url="/api/kardolive/chat-token"
data-user-id="user_42"
data-display-name="Yousof"
style="width: 320px; height: 480px;"
></div>
<script src="https://kardocloud.com/widgets/chat.js" defer></script>
The widget calls POST /api/kardolive/chat-token on your backend (you implement this — see
Auth & tokens). The body it sends:
{
"channelId": "chn_abc123",
"userId": "user_42",
"displayName": "Yousof"
}
Your endpoint returns:
{ "token": "<short-lived JWT>", "chatUrl": "wss://chat.kardocloud.com" }
That's it. The widget styles itself for dark backgrounds; override CSS variables on the parent element to theme.
2. @kardolive/sdk
For more control than the drop-in widget but less work than raw WebSocket.
npm install @kardolive/sdk
For your backend (server-to-server):
import { Kardolive } from '@kardolive/sdk';
const kl = new Kardolive({ apiKey: process.env.KARDOLIVE_API_KEY });
// Create a chat channel
const channel = await kl.channels.create({
type: 'direct',
memberIds: ['user_42', 'user_99'],
});
// Mint a token for the client
const tok = await kl.channels.mintToken({
userId: 'user_42',
channelId: channel.id,
});
// tok = { token, chatUrl, expiresAt }
For your client (browser/mobile) — pass the JWT, NOT the API key:
import { Kardolive } from '@kardolive/sdk';
// JWT comes from your backend (see Auth & tokens)
const kl = new Kardolive({ accessToken: jwtFromYourServer });
// Sessions (calls/conferences) — full mediasoup-client wrapper
const session = await kl.sessions.mintToken('sess_xyz', {
userId: 'user_42',
displayName: 'Yousof',
role: 'guest',
});
// session = { token, sfuUrl, chatUrl, role, perms }
3. Drop-in scenarios
Kardolive ships 7 fully-wired example scenarios as standalone HTML pages.
They handle chat + media + interactions out of the box. Pass them
?room=<id>&token=<jwt> and they just work.
| Scenario | URL | Best for |
|---|---|---|
| Live shopping | /scenarios/shopping/ | Product overlay + cart + gifts |
| Webinar | /scenarios/webinar/ | Q&A queue, big audience |
| Audio room | /scenarios/audio-room/ | Clubhouse-style |
| Video call | /scenarios/video-call/ | 1:1 telehealth-grade |
| Voice call | /scenarios/voice-call/ | Audio-only with pulse + dial pad |
| Karaoke | /scenarios/karaoke/ | Lyrics + tips |
| Classroom | /scenarios/classroom/ | Whiteboard + hand-raise + breakouts |
Open one in an iframe or new window:
// after minting a session token on your backend:
const url = `https://kardocloud.com/scenarios/classroom/?room=${sessionId}&token=${token}`;
window.open(url, '_blank');
// or embed:
<iframe
src={url}
width="100%" height="600"
allow="camera; microphone; display-capture; fullscreen"></iframe>
4. Raw WebSocket — for total control
If you need full UI control and don't want any SDK:
// 1. mint a JWT from your backend (see Auth & tokens)
const { token, chatUrl } = await fetch('/api/kardolive/chat-token', {
method: 'POST', headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ channelId: 'chn_abc' }),
}).then((r) => r.json());
// 2. open WS
const ws = new WebSocket(
`${chatUrl}/v1/chat/socket?room=chn_abc&token=${token}`,
);
// 3. send / receive
ws.onopen = () => {
ws.send(JSON.stringify({ type: 'chat.send', data: { body: 'hello' } }));
};
ws.onmessage = (e) => {
const env = JSON.parse(e.data);
switch (env.type) {
case 'welcome': console.log('connected as', env.data.you); break;
case 'chat': renderMessage(env.data); break;
case 'chat.edited': updateMessage(env.data); break;
case 'chat.deleted':removeMessage(env.data.id); break;
case 'reaction': addReaction(env.data); break;
case 'typing': showTyping(env.data); break;
case 'presence': updateViewerCount(env.data); break;
case 'gift': floatGift(env.data); break;
case 'system': log(env.data.body); break;
}
};
Sending commands the server understands (full list in reference):
// edit a message you authored
ws.send(JSON.stringify({ type: 'chat.edit', data: { id: 'msg_x', body: 'new body' } }));
// mark read up to now (drives unread counts on other clients)
ws.send(JSON.stringify({ type: 'read.mark', data: {} }));
// typing on/off
ws.send(JSON.stringify({ type: 'typing.start', data: {} }));
ws.send(JSON.stringify({ type: 'typing.stop', data: {} }));
// emoji reaction on a message
ws.send(JSON.stringify({ type: 'reaction.add', data: { messageId: 'msg_x', emoji: '❤' } }));
// gift / super chat
ws.send(JSON.stringify({ type: 'gift.send', data: { kind: 'rose', amountCents: 100 } }));
ws.send(JSON.stringify({ type: 'superchat.send', data: { body: 'Great!', amountCents: 500, currency: 'USD' } }));