Embed Knowi's Agentic BI chat interface directly into your application. There are two approaches depending on how much control you need over the UI:
SSO Chat Embed -- Drop the full Knowi chat interface into your app via iframe. No custom UI needed. Your users get the same chat experience with all built-in features (data sources, suggestions, chat history, themes).
Headless Chat API -- Build your own chat UI. Send questions via REST API, get structured responses back. Available in streaming (Server-Sent Events) and synchronous modes.
Interactive Demo -- Try both approaches with a live configuration tool and generated code snippets.
The SSO embed renders the full Knowi Agentic BI chat inside an iframe using Single Sign-On authentication. This is the fastest way to add AI-powered data chat to your application.
knowi-api.js included in your pageCreate a user that will interact with the embedded chat. This is typically done server-side when the user logs into your application.
POST /sso/user/create
Content-Type: application/x-www-form-urlencoded
ssoCustomerToken=YOUR_CUSTOMER_SSO_TOKEN
&user=user@example.com
&userToken=a_secret_for_this_user
The response returns an SSO key for the user. Store this -- you'll need it to create sessions.
Generate a session token each time the user needs to access the embedded chat.
POST /sso/session/create
Content-Type: application/x-www-form-urlencoded
user=user@example.com
&userToken=SSO_KEY_FROM_STEP_1
&expiry=3600
The response is the session token string. Pass this to the embed SDK.
Include the Knowi embed SDK and render the chat interface:
<script src="https://www.knowi.com/minify/knowi-api.min.js"></script>
<script>
Knowi.render('#chat-container', {
type: 'aiConverse',
url: 'https://www.knowi.com/',
token: 'SESSION_TOKEN_FROM_STEP_2',
themeId: 'light',
view: {
aiConverseMode: true,
aiConverseOptions: {
useSources: 'all',
chatHistory: 'hidden',
greeting: 'How can I help you today?',
suggestions: ['Show revenue by region', 'Create a dashboard']
}
}
});
</script>
| Option | Values | Description |
|---|---|---|
type | 'aiConverse' | Required. Specifies the chat embed mode. |
url | 'https://www.knowi.com/' | Your Knowi instance URL (include trailing slash). |
token | string | SSO session token from Step 2. |
themeId | 'light', 'dark', or custom key | Theme to apply to the embedded chat. |
| Option | Values | Default | Description |
|---|---|---|---|
useSources | 'all', 'datasets', 'documents' | 'all' | What the AI can search. 'datasets' restricts to structured query data. 'documents' restricts to uploaded documents (PDFs, etc.). |
sources | object | none | Limit AI access to specific datasets or documents. Provide datasets array (dataset names or IDs) and/or documents array (document names or IDs). If omitted, all user's datasets/documents are accessible. See example below. |
chatHistory | 'hidden', 'collapsed', 'expanded' | 'hidden' | Whether to show the chat history sidebar. |
greeting | string | 'Hi there!' | Custom greeting displayed when the chat loads. |
suggestions | string array | none | Suggested prompts shown below the greeting. |
agents | array of strings | none (all agents) | Restrict which AI agents are available. Pass an array of agent slugs (e.g. ['data-analyst', 'create-dashboard']). If omitted, all agents the user has permission to use are available. Slugs are the lowercase-hyphenated agent names (e.g. 'alert-management', 'report-management', 'create-widget'). |
showModelSelector | boolean | false | Show the LLM model selector in the chat. |
hideUpload | boolean | false | Hide the file upload button. |
hideRefresh | boolean | false | Hide the refresh/reset button. |
hideSources | boolean | false | Hide the data sources selector button. |
hideSkills | boolean | false | Hide the skills/agents selector button. |
hideDisclaimer | boolean | false | Hide the AI disclaimer text below the input. |
showNewChatButton | boolean | true | Show the "New Chat" button in sidebar and top bar. |
showResetChatButton | boolean | true | Show the reset/new chat button at bottom (only visible when sidebar is hidden). |
welcomeLogo | string (URL) | hidden | Custom logo URL for welcome screen center icon. Hidden by default in embed mode; set a URL to show a custom logo. |
theme | object | none | Customize colors, fonts, and button styles. See Theme Customization below. |
Use the sources parameter to restrict which datasets and documents the AI can access. This is useful for embedded scenarios where you want to limit the scope of data available to specific users or contexts.
Example:
aiConverseOptions: {
useSources: 'all',
sources: {
datasets: ['Sales Data', 'Customer Analytics', 334, 445],
documents: ['Product Guide', 'FAQ', 'doc-abc123', 'doc-xyz789']
}
}
Datasets can be specified by name or ID:
'Sales Data', 'Customer Analytics'334, 445Documents can be specified by name or identifier:
'Product Guide', 'FAQ''doc-abc123', 'doc-xyz789'
Additional notes:
- You can specify only datasets or only documents (both are not required)
- If sources is omitted, the AI can access all datasets/documents the user has permission to view
- Names and identifiers are matched exactly (case-sensitive)
How It Works:
When sources is provided, AI agents enforce a two-layer security model:
sources whitelistThis ensures users can only interact with the specific data you've explicitly allowed in the embedded context.
The theme object in aiConverseOptions allows you to customize the look and feel of the embedded chat to match your brand.
All properties are optional - sensible defaults are applied automatically. You can override any specific property while keeping the rest at their default values.
How defaults work:
- If you don't specify a theme object, all elements use default styling
- primaryColor is used ONLY for user message bubbles (unless overridden by userBubbleColor)
- Buttons, inputs, and other UI elements have their own independent defaults
- You can customize any specific property while keeping the rest at their defaults
Example - Minimal theme: ```javascript theme: { primaryColor: '#667eea' // Only this one property } // Result: User message bubbles will be blue // All buttons, inputs, and other elements use their default styling (orange/gray) ```
theme: {
primaryColor: '#667eea',
backgroundColor: '#F9FAFB',
userBubbleColor: '#667eea',
userBubbleTextColor: '#FFFFFF',
aiBubbleColor: '#f5f5f5',
aiBubbleTextColor: '#333333',
fontFamily: 'Arial, sans-serif'
}
| Property | Default | Description |
|---|---|---|
primaryColor | #f28c37 | Primary brand color used for accents and highlights. |
backgroundColor | #F9FAFB | Main background color of the chat interface. |
userBubbleColor | #667eea | Background color of user message bubbles. |
userBubbleTextColor | #FFFFFF | Text color inside user message bubbles. |
aiBubbleColor | #f5f5f5 | Background color of AI message bubbles. |
aiBubbleTextColor | #333333 | Text color inside AI message bubbles. |
fontFamily | 'Inter, sans-serif' | Font family for the entire chat interface. |
theme: {
buttons: {
submit: {
backgroundColor: '#667eea',
color: '#FFFFFF',
borderRadius: '8px',
fontSize: '14px',
padding: '8px 16px'
},
upload: {
color: '#98A2B3',
hoverColor: '#475467',
hoverBackgroundColor: '#F2F4F7'
},
reset: {
color: '#98A2B3',
hoverColor: '#475467'
},
sources: {
color: '#475467',
backgroundColor: 'transparent',
hoverBackgroundColor: '#F2F4F7'
},
skills: {
color: '#475467',
borderColor: '#E4E7EC'
},
newChat: {
backgroundColor: '#f28c37',
color: '#FFFFFF'
},
sidebarToggle: {
color: '#475467',
hoverColor: '#101828'
}
}
}
| Button | Supported Properties | Defaults | Description |
|---|---|---|---|
submit | backgroundColor, color, borderRadius, fontSize, padding | Orange (#f28c37), white text, 8px radius | The send message button (arrow icon). |
upload | color, hoverColor, hoverBackgroundColor | Gray (#98A2B3) with darker hover | The file upload button (plus icon). |
reset | color, hoverColor | Gray (#98A2B3) with darker hover | The reset/clear button (refresh icon). |
sources | color, backgroundColor, hoverBackgroundColor | Dark gray text, transparent background | The data sources button (shows selected datasets/documents). |
skills | color, borderColor | Gray text and border | The skills selector button (AI agent selection). |
newChat | backgroundColor, color | Orange (#f28c37), white text | The "New Chat" button (appears in header and sidebar). |
sidebarToggle | color, hoverColor | Gray with dark hover | The sidebar expand/collapse button (hamburger icon). |
theme: {
input: {
backgroundColor: '#FFFFFF',
borderColor: '#E4E7EC',
textColor: '#344054',
placeholderColor: '#98A2B3',
focusBorderColor: '#f28c37'
}
}
| Property | Default | Description |
|---|---|---|
backgroundColor | #FFFFFF | Background color of the input box. |
borderColor | #E4E7EC | Border color when input is not focused. |
textColor | #344054 | Text color inside the input box. |
placeholderColor | #98A2B3 | Color of the placeholder text. |
focusBorderColor | #f28c37 (orange) | Border color when input is focused. |
theme: {
sidebar: {
backgroundColor: '#FFFFFF',
borderColor: '#E4E7EC',
sessionHoverColor: '#F2F4F7',
sessionActiveColor: 'rgba(242, 140, 55, 0.06)'
}
}
| Property | Default | Description |
|---|---|---|
backgroundColor | #FFFFFF | Background color of the chat history sidebar. |
borderColor | #E4E7EC | Border color between sidebar and main chat area. |
sessionHoverColor | #F2F4F7 | Background color when hovering over a chat session. |
sessionActiveColor | rgba(242, 140, 55, 0.06) | Background color of the currently active chat session. |
theme: {
welcome: {
greetingColor: '#101828',
subtitleColor: '#475467',
disclaimerColor: '#667085'
}
}
| Property | Default | Description |
|---|---|---|
greetingColor | #101828 | Text color of the main greeting message. |
subtitleColor | #475467 | Text color of the subtitle below the greeting. |
disclaimerColor | #667085 | Text color of the disclaimer text. |
theme: {
suggestionChips: {
backgroundColor: '#F2F4F7',
color: '#344054',
hoverBackgroundColor: '#E4E7EC',
borderColor: '#D0D5DD'
}
}
| Property | Default | Description |
|---|---|---|
backgroundColor | #F2F4F7 | Background color of suggestion chips. |
color | #344054 | Text color of suggestion chips. |
hoverBackgroundColor | #E4E7EC | Background color when hovering over a chip. |
borderColor | #D0D5DD | Border color of suggestion chips. |
Knowi.render('#chat-container', {
type: 'aiConverse',
url: 'https://www.knowi.com/',
token: 'YOUR_SSO_TOKEN',
view: {
aiConverseMode: true,
aiConverseOptions: {
greeting: 'Welcome to our AI assistant!',
suggestions: ['Show revenue trends', 'Create a dashboard'],
theme: {
// Basic colors
primaryColor: '#4F46E5',
backgroundColor: '#FFFFFF',
userBubbleColor: '#4F46E5',
userBubbleTextColor: '#FFFFFF',
aiBubbleColor: '#F3F4F6',
aiBubbleTextColor: '#1F2937',
fontFamily: 'Roboto, sans-serif',
// Buttons
buttons: {
submit: {
backgroundColor: '#4F46E5',
color: '#FFFFFF',
borderRadius: '12px'
},
newChat: {
backgroundColor: '#10B981',
color: '#FFFFFF'
}
},
// Input
input: {
borderColor: '#D1D5DB',
focusBorderColor: '#4F46E5',
placeholderColor: '#9CA3AF'
},
// Suggestion chips
suggestionChips: {
backgroundColor: '#EEF2FF',
color: '#4F46E5',
hoverBackgroundColor: '#E0E7FF'
}
}
}
}
});
The headless API lets you build your own chat interface. You send questions via REST, and get back structured JSON responses with text, data tables, widget embeds, or clarification prompts.
All API requests use the Authorization: Bearer <token> header. Three token types are accepted (the server tries them in order):
/sso/session/create| Endpoint | Method | Description |
|---|---|---|
/api/v1/agent/chat | POST | Synchronous -- returns the full response in one JSON payload. |
/api/v1/agent/chat/stream | POST | Streaming -- returns Server-Sent Events with real-time progress updates. |
POST /api/v1/agent/chat
Content-Type: application/json
Authorization: Bearer YOUR_TOKEN
{
"message": "show top 10 customers by revenue",
"sessionId": "optional-session-id-for-follow-ups",
"contextType": "global",
"contextId": "optional-widget-or-dashboard-id",
"settings": {
"model": "gpt-4o",
"targetAgent": "DataAnalyst",
"selectedDatasets": ["dataset-id-1", "dataset-id-2"],
"useDatasets": true
}
}
| Field | Required | Description |
|---|---|---|
message | Yes | The user's question or instruction. |
sessionId | No | Include to continue a conversation. Omit to start a new session. |
contextType | No | Scope the AI to a specific context: 'global' (default), 'widget', or 'dashboard'. |
contextId | No | The ID of the widget or dashboard when contextType is not 'global'. |
settings.model | No | Override the default LLM model (e.g., 'gpt-4o', 'claude-3-5-sonnet'). |
settings.targetAgent | No | Route to a specific agent instead of auto-routing. Pass the enum name (e.g., 'DATA_ANALYST', 'CREATE_DASHBOARD'). See Available Agents section below for the complete list with display names and enum values. |
settings.selectedDatasets | No | Restrict the AI to specific dataset IDs. |
settings.useDatasets | No | Enable/disable automatic dataset discovery. Default: true. |
{
"responseType": "data",
"text": "Here are the top 10 customers by revenue.",
"sessionId": "abc123-def456-...",
"data": {
"columns": [
{ "name": "Customer", "type": "string" },
{ "name": "Revenue", "type": "number" }
],
"rows": [
{ "Customer": "Acme Corp", "Revenue": 52000 },
...
]
}
}
| Field | Description |
|---|---|
responseType | One of: 'text', 'data', 'widget', 'dashboard', 'clarification'. |
text | The AI's response message. Always present. |
sessionId | Session ID for follow-up messages. Always present. |
data | Present when responseType is 'data'. Contains columns and rows. |
embed | Present when responseType is 'widget' or 'dashboard'. Contains url and html (ready-to-use iframe HTML). |
options | Present when responseType is 'clarification'. Array of { label, value } objects the user can pick from. |
text -- A plain text answer from the AI.
data -- Structured query results with columns and rows. Render as a table or pass to a charting library.
widget -- The AI created a widget. The embed field contains a url to the widget and html with a ready-to-use iframe tag.
dashboard -- The AI created a dashboard. Same embed structure as widget.
clarification -- The AI needs more information. The options array contains choices to present to the user. Send the selected value back as the next message.
The streaming endpoint returns real-time progress as the AI works. Events follow the SSE format:
event: progress
data: {"type":"progress","message":"Searching datasets..."}
event: progress
data: {"type":"progress","message":"Running query..."}
event: result
data: {"responseType":"data","text":"Here are the results.","sessionId":"...","data":{...}}
| Event Type | Description |
|---|---|
progress | Intermediate status update. Show to the user as a loading indicator. |
result | Final response. Same structure as the synchronous response body. |
error | An error occurred. Contains code and message fields. |
{
"error": true,
"code": "PERMISSION_DENIED",
"message": "User does not have permission to use AI agents."
}
| Code | HTTP Status | Description |
|---|---|---|
PERMISSION_DENIED | 403 | User lacks AI agent permissions. |
APPLICATION_ERROR | 400 | Invalid request (e.g., empty message, invalid session). |
INTERNAL_ERROR | 500 | Unexpected server error. |
const response = await fetch('https://www.knowi.com/api/v1/agent/chat', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer YOUR_TOKEN'
},
body: JSON.stringify({
message: 'show top 10 customers by revenue'
})
});
const data = await response.json();
console.log(data.text);
if (data.data) console.table(data.data.rows);
if (data.embed) document.getElementById('container').innerHTML = data.embed.html;
const response = await fetch('https://www.knowi.com/api/v1/agent/chat/stream', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer YOUR_TOKEN'
},
body: JSON.stringify({
message: 'show top 10 customers by revenue'
})
});
const reader = response.body.getReader();
const decoder = new TextDecoder();
let buffer = '';
let eventType = null;
while (true) {
const { done, value } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
const lines = buffer.split('\n');
buffer = lines.pop();
for (const line of lines) {
if (line.startsWith('event:'))
eventType = line.slice(6).trim();
else if (line.startsWith('data:')) {
const data = JSON.parse(line.slice(5));
if (eventType === 'progress') {
showLoadingMessage(data.message);
} else if (eventType === 'result') {
displayResponse(data);
} else if (eventType === 'error') {
showError(data.message);
}
}
}
}
Sessions maintain conversation context so follow-up questions work. When you send the first message without a sessionId, the API creates a new session and returns the ID in the response. Include that sessionId in subsequent requests to continue the conversation.
// First message -- new session
{ "message": "show revenue by region" }
// Response includes sessionId: "abc123..."
// Follow-up -- same session
{ "message": "now filter that to Q4 only", "sessionId": "abc123..." }
To start a fresh conversation, omit the sessionId.
When using the settings.targetAgent parameter, you can route requests to specific AI agents instead of relying on automatic routing. Pass the enum name (e.g., 'DATA_ANALYST', 'CREATE_DASHBOARD') as the value.
DATA & ANALYTICS
| Display Name | Enum Value | Description |
|---|---|---|
| Search Assets | SEARCH_ASSETS | Search across all Knowi assets - dashboards, widgets, datasets, reports, and documents |
| Data Analyst | DATA_ANALYST | Answer questions about data using datasets and documents. Generates charts, text answers, and searches knowledge base. |
| Get Recommendations | RECOMMENDATION | Generate AI-powered insights and recommendations for widgets (requires widget context) |
| Create Dataset | CREATE_DATASET | Create datasets from natural language descriptions by searching across datasources |
| Connect Datasource | CREATE_DATASOURCE | Guide users through connecting datasources via conversation |
| Query Your Data | NLP_AGENT | Convert natural language to SQL queries for data analysis |
| Export Data | DATA_EXPORT | Export widget or dashboard data to CSV or Excel format for download |
DASHBOARDS
| Display Name | Enum Value | Description |
|---|---|---|
| Create Dashboard | CREATE_DASHBOARD | Create AI-powered dashboards from natural language descriptions |
| Manage Filters | DASHBOARD_FILTER | Set up and configure dashboard filters using natural language (requires dashboard context) |
| Dashboard Settings | DASHBOARD_SETTINGS | Configure dashboard properties: name, theme, header, footer, description, and dimensions (requires dashboard context) |
| Dashboard Summary | DASHBOARD_SUMMARY | Generate summaries and narratives that describe the current dashboard state (requires dashboard context) |
| Share Dashboard | SHARE_DASHBOARD | Generate shareable URL for dashboard that can be accessed without login (requires dashboard context) |
| Rearrange Layout | WIDGET_LAYOUT | Reposition and resize widgets on a dashboard grid (requires dashboard context) |
| Add Widget to Dashboard | ADD_WIDGET_TO_DASHBOARD | Add an existing widget to a dashboard (requires dashboard context) |
WIDGETS
| Display Name | Enum Value | Description |
|---|---|---|
| Create Widget | CREATE_WIDGET | Create the appropriate widget type with optimal settings based on data and requirements (requires dashboard context) |
| Customize Widget | UPDATE_WIDGET_SETTINGS | Update widget visual settings, formatting, and display options without changing the data (requires widget context) |
REPORTS & ALERTS
| Display Name | Enum Value | Description |
|---|---|---|
| Send Report | REPORT_DELIVERY | Deliver dashboards, widgets, or datasets via Email, Slack, Teams, or Webhooks |
| Manage Reports | REPORT_MANAGEMENT | Create, list, edit, pause, unpause, test run, and delete scheduled reports |
| Manage Alerts | ALERT_MANAGEMENT | Create, list, edit, pause, unpause, test, and delete data alerts |
Example Usage:
{
"message": "create a sales dashboard",
"settings": {
"targetAgent": "CREATE_DASHBOARD"
}
}
Note: Some agents require specific context via contextType and contextId parameters (e.g., dashboard ID or widget ID).