Widget SDK
Embed and control the KlicForge chat widget from JavaScript — installation, configuration, methods and events.
The widget SDK embeds the KlicForge chat widget in a web page and gives you a JavaScript API to control it.
The widget renders inside an isolated container, so its styles cannot leak into your page and your page's styles cannot break it.
Installation
Add this before the closing </body> tag:
<script src="https://unpkg.com/@bymos/[email protected]/agentkit-widget.iife.js"></script>
<script>
window.AgentKit.init({
agentId: 'your-agent-id',
tenantId: 'your-tenant-id',
apiBaseUrl: 'https://api.klicforge.ai',
});
</script>This registers window.AgentKit synchronously.
Find your agent ID and workspace ID in the dashboard, and get a ready-made copy-paste snippet on the agent's Sandbox tab, or from an agent's Channels → Widget settings.
The widget only loads on domains listed in the agent's allowed origins. If you see an access-restricted message, add the site's origin under the agent's Channels → Widget settings.
Mounting
init() creates a floating widget with a launcher button. To embed the chat inside an element
of your own layout instead, use mount():
window.AgentKit.mount(document.getElementById('support-chat'), {
agentId: 'your-agent-id',
tenantId: 'your-tenant-id',
apiBaseUrl: 'https://api.klicforge.ai',
});Configuration
init() and mount() accept these fields:
| Field | Type | Notes |
|---|---|---|
agentId | string | Required. |
apiBaseUrl | string | Required. |
tenantId | string | Tenant/organisation identifier. Required for conversation tracking and widget validation. |
user | object | Identity of the end-user — see Identifying your users. |
sessionId | string | Resume a specific session instead of the one persisted in localStorage. |
mode | 'floating' | 'inline' | Default 'floating'. Use 'inline' with mount() to embed in an element of your layout. |
title | string | Default 'AI Assistant'. Overrides the agent's display name in the header. |
subtitle | string | Short text shown below the agent name in the widget header. |
description | string | Used in the widget empty state. Defaults from the server; can be overridden here. |
avatarUrl | string | URL of the avatar image shown in the header and launcher. |
theme | object | mode ('light' | 'dark' | 'system'), accentColor, fontFamily, borderRadius. |
metadata | Record<string, unknown> | Arbitrary metadata attached to the session. |
streaming | boolean | Default true. Set false to receive whole replies instead of token streams. |
preview | boolean | Dashboard sandbox only. Sends the session cookie so a signed-in tenant member can chat with a draft/inactive agent. Leave false for third-party embeds. |
skipServerConfigFetch | boolean | Dashboard sandbox only. Skips the SDK's own config fetch when the host already supplies display fields inline. |
configChannel | 'draft' | 'published' | Dashboard sandbox only. 'draft' requires a session cookie for the owning tenant and is inert for third-party embeds. |
Controlling the widget
Both init() and mount() return an instance:
const widget = window.AgentKit.init({ ... });
widget.open();
widget.close();
widget.toggle();
widget.sendMessage('Hello');
widget.reset(); // start a fresh conversation
widget.getState();
widget.destroy();window.AgentKit.destroy(id) removes a widget by ID, and calling it with no argument removes
all of them.
Events
widget.on('message:received', (event) => {
console.log(event);
});
widget.off('message:received', handler);| Event | Fires when |
|---|---|
ready | The widget has initialised |
open / close | The widget is opened or closed |
conversation:started | A new conversation begins |
message:sent | The user sends a message |
message:received | The agent's reply arrives |
message:error | A message fails |
stream:start / stream:delta / stream:end | Streaming reply lifecycle |
control_mode_changed | A human takes over or hands back |
reset | The conversation is reset |
destroy | The widget is torn down |
Identifying your users
If you already know who the visitor is, pass an external identifier so their conversations link to the same contact across sessions and devices.
window.AgentKit.init({
agentId: 'your-agent-id',
tenantId: 'your-tenant-id',
apiBaseUrl: 'https://api.klicforge.ai',
user: {
externalId: 'user_123', // your own DB user ID, UUID, etc.
authId: 'auth0|abc123', // ID from your auth system — highest-priority lookup key
name: 'Jane Doe',
email: '[email protected]',
},
});All user fields are optional — omit user entirely for anonymous sessions.
Do not pass personal data you would not want in a browser. The identifier should be an opaque ID from your own system, not an email address.
Appearance
Greeting, branding, colours, whether file upload and voice notes are enabled, and links to your
privacy policy and terms are configured on the agent's Widget tab, so non-developers can
change them without a deployment. title, avatarUrl, and theme in the init config override
those defaults for a specific embed when set — see Configuration.
Sessions
A conversation persists across page loads in the browser, so a visitor who navigates around your
site keeps their conversation. reset() starts a fresh one. Sessions expire after a period of
inactivity set on the agent.
From 0.8 the SDK also establishes an abuse-protection session when the visitor opens the chat panel. It needs no configuration, adds nothing to a page whose chat is never opened, and a failure to establish one never blocks a message.
Troubleshooting
| Symptom | Likely cause |
|---|---|
window.AgentKit is undefined | The script tag runs after your init code, or failed to load |
| Access-restricted message | The origin is not in the agent's allowed origins |
| Widget opens but never replies | The agent's status is draft or inactive |
| Widget is clipped or invisible | A parent element has overflow: hidden or a low stacking context |
| Uploads rejected | The file type or size is not supported |