Configuration
Complete reference for site configuration options. All fields are validated against a Zod schema on the server. Required fields are marked; everything else has sensible defaults.
Site Config (top level)
The top-level object passed when creating or updating a site via the admin API or dashboard.
| Field | Type | Default | Description |
|---|---|---|---|
| siteId | string | required | Unique identifier. Lowercase alphanumeric with hyphens only (^[a-z0-9-]+$), 1-100 chars. |
| allowedOrigins | string[] | required | URLs allowed to load the widget. Must be valid URLs. At least one required. The server checks the Origin header against this list. |
| enabled | boolean | true | Enable or disable the site. Disabled sites reject all widget requests. |
| branding | object | {} | Widget appearance and text. See branding below. |
| ai | object | required | AI provider configuration. See ai below. |
| guardrails | object | required | Security and topic guardrails. See guardrails below. |
| knowledge | object | {} | Knowledge sources for context. See knowledge below. |
| tickets | object | {} | Ticket creation settings. See tickets below. |
| rateLimit | object | {} | Per-IP rate limiting. See rateLimit below. |
branding
Controls the widget's visual appearance, text, and position. All fields are optional with sensible defaults. The branding object is sent to the client as part of the public config — no secrets are exposed.
| Field | Type | Default | Description |
|---|---|---|---|
| name | string | "Assistant" | Display name shown in the widget header and used as the replacement when scrubbing AI provider names from responses. 1-100 chars. |
| tagline | string | — | Short tagline below the name. Up to 200 chars. Optional. |
| logoUrl | string (URL) | — | URL to a logo image displayed in the widget header. Must be a valid URL. Optional. |
| colors.primary | hex color | #6366f1 | Primary accent color. Used for the header, bubble button, and user message background. |
| colors.primaryForeground | hex color | #ffffff | Text color on primary-colored backgrounds (header, bubble button). |
| colors.background | hex color | #ffffff | Widget background color for the chat area and input bar. |
| colors.foreground | hex color | #1f2937 | Primary text color used for assistant messages and general text. |
| colors.bubbleBackground | hex color | #f3f4f6 | Background color for assistant message bubbles. |
| colors.userBubbleBackground | hex color | #6366f1 | Background color for user message bubbles. |
| colors.userBubbleForeground | hex color | #ffffff | Text color inside user message bubbles. |
| position | enum | "bottom-right" | Widget position: "bottom-right" or "bottom-left". |
| welcomeMessage | string | "Hi! How can I help you today?" | First message shown when the user opens the chat window. Up to 500 chars. |
| inputPlaceholder | string | "Type your message..." | Placeholder text in the message input field. Up to 200 chars. |
#6366f1). Shorthand hex (#fff) and named colors are not accepted.ai
Kody works with any OpenAI-compatible chat completions API. This includes Ollama, vLLM, llama.cpp, OpenAI, and many other providers. The AI config is stored server-side only — API keys are never sent to the browser.
| Field | Type | Default | Description |
|---|---|---|---|
| baseUrl | string (URL) | required | OpenAI-compatible API base URL. Examples: http://localhost:11434/v1 (Ollama), https://api.openai.com/v1 (OpenAI). |
| apiKey | string | "ollama" | API key sent in the Authorization: Bearer header. For Ollama, any non-empty string works. Min 1 char. |
| model | string | required | Model name to request from the provider. Examples: llama3, gpt-4o, mistral. Min 1 char. |
| temperature | number | 0.7 | Sampling temperature controlling response randomness. Range: 0 (deterministic) to 2 (very creative). |
| maxTokens | integer | 1024 | Maximum tokens in the AI response. Range: 1-32768. |
| topP | number | — | Nucleus sampling parameter. Range: 0-1. Optional. Only set this if you know what you are doing — most use cases are better served by adjusting temperature alone. |
| systemPromptPrefix | string | — | Custom text appended to the auto-generated system prompt under an "ADDITIONAL INSTRUCTIONS" section. Up to 4000 chars. Use this to give the AI extra persona details or behavioral instructions. |
- Ollama:
baseUrl: "http://localhost:11434/v1",apiKey: "ollama" - OpenAI:
baseUrl: "https://api.openai.com/v1",apiKey: "sk-..." - vLLM:
baseUrl: "http://localhost:8000/v1",apiKey: "token" - llama.cpp:
baseUrl: "http://localhost:8080/v1",apiKey: "token"
guardrails
Controls security filtering and topic restrictions. For a deep dive, see the Security page.
| Field | Type | Default | Description |
|---|---|---|---|
| allowedTopics | string[] | required | Topics the assistant is allowed to discuss. At least one required. Each string 1-200 chars. Injected into the system prompt as allowed topics. |
| topicDescription | string | required | Human-readable description of what the assistant should help with. Injected into the system prompt. 1-4000 chars. |
| refusalMessage | string | "I can only help with topics related to this website..." | Message the AI is instructed to use when refusing off-topic requests. Up to 500 chars. |
| blockedInputPatterns | string[] | [] | Additional regex patterns to block in user input (on top of the 17 built-in prompt injection patterns). Each is tested case-insensitively. |
| blockedOutputPatterns | string[] | [] | Regex patterns to block in AI responses. If a response matches any pattern, it is blocked entirely and not sent to the user. |
| maxInputLength | integer | 2000 | Maximum user message length in characters. Range: 1-10000. |
| enablePromptInjectionDetection | boolean | true | Enable built-in prompt injection pattern detection. Checks for instruction overrides, role switching, mode escalation, system prompt extraction, and format injection. |
| enableOutputScrubbing | boolean | true | Scrub 30+ AI provider names from responses and detect system prompt leaks. Strongly recommended to keep enabled. |
knowledge
Provides contextual information to the AI via the system prompt. For details on each source type, see Knowledge Sources.
| Field | Type | Default | Description |
|---|---|---|---|
| sources | KnowledgeSource[] | [] | Array of knowledge sources. Supports 4 types: text, faq, url, file. See Knowledge Sources. |
| maxContextTokens | integer | 4000 | Token budget for knowledge context injected into the system prompt. Range: 100-32000. Higher values increase AI costs and latency. |
tickets
Enable users to create support tickets from the chat widget. For provider-specific setup, see Ticket Providers.
| Field | Type | Default | Description |
|---|---|---|---|
| enabled | boolean | false | Enable ticket creation from the widget. Shows a ticket button in the chat UI. |
| promptMessage | string | "Would you like me to create a support ticket..." | Message prompting the user to create a ticket. Up to 500 chars. |
| providers | TicketProvider[] | [] | Array of ticket providers. Supports 5 types: jira, github, linear, email, webhook. Tickets are sent to all configured providers. See Ticket Providers. |
| requiredFields | string[] | ["email", "description"] | Fields the user must fill in to submit a ticket. Valid values: "name", "email", "subject", "description". |
rateLimit
Per-IP rate limiting to protect your AI backend from abuse. All limits are enforced server-side.
| Field | Type | Default | Description |
|---|---|---|---|
| messagesPerMinute | integer | 10 | Max messages per IP per minute. Range: 1-120. |
| messagesPerHour | integer | 100 | Max messages per IP per hour. Range: 1-1000. |
| messagesPerDay | integer | 1000 | Max messages per IP per day. Range: 1-10000. |
Embedding the Widget
There are two ways to embed the widget on your page:
1. Script tag with data attributes
<script
src="https://api.kody.codai.app/widget.js"
data-site-id="your-site-id"
async
></script>2. window.KodyConfig
<script>
window.KodyConfig = {
siteId: "your-site-id",
position: "bottom-left",
name: "Support Bot",
primaryColor: "#10b981"
};
</script>
<script src="https://api.kody.codai.app/widget.js" async></script>Complete Example
A full site configuration using all available options:
{
"siteId": "my-docs",
"allowedOrigins": ["https://example.com", "https://www.example.com"],
"enabled": true,
"branding": {
"name": "DocBot",
"tagline": "Your documentation assistant",
"logoUrl": "https://example.com/logo.png",
"colors": {
"primary": "#6366f1",
"primaryForeground": "#ffffff",
"background": "#ffffff",
"foreground": "#1f2937",
"bubbleBackground": "#f3f4f6",
"userBubbleBackground": "#6366f1",
"userBubbleForeground": "#ffffff"
},
"position": "bottom-right",
"welcomeMessage": "Hi! Ask me anything about our docs.",
"inputPlaceholder": "Ask a question..."
},
"ai": {
"baseUrl": "http://localhost:11434/v1",
"apiKey": "ollama",
"model": "llama3",
"temperature": 0.7,
"maxTokens": 1024,
"systemPromptPrefix": "You specialize in developer documentation. Always include code examples when relevant."
},
"guardrails": {
"allowedTopics": ["documentation", "api", "setup", "troubleshooting"],
"topicDescription": "Questions about our product documentation and API",
"refusalMessage": "I can only help with documentation-related questions. Is there something else I can assist you with?",
"blockedInputPatterns": [],
"blockedOutputPatterns": [],
"maxInputLength": 2000,
"enablePromptInjectionDetection": true,
"enableOutputScrubbing": true
},
"knowledge": {
"sources": [
{
"type": "text",
"title": "About Us",
"content": "We build developer tools used by over 10,000 teams worldwide."
},
{
"type": "faq",
"entries": [
{
"question": "What are your support hours?",
"answer": "Monday to Friday, 9am-5pm EST."
}
]
},
{
"type": "url",
"url": "https://example.com/docs.md",
"title": "Documentation",
"refreshIntervalHours": 24
},
{
"type": "file",
"filePath": "product-guide.md",
"title": "Product Guide"
}
],
"maxContextTokens": 4000
},
"tickets": {
"enabled": true,
"promptMessage": "Would you like me to create a support ticket for this issue?",
"providers": [
{
"provider": "github",
"owner": "your-org",
"repo": "support",
"token": "ghp_...",
"labels": ["kody-ticket"]
}
],
"requiredFields": ["email", "description"]
},
"rateLimit": {
"messagesPerMinute": 10,
"messagesPerHour": 100,
"messagesPerDay": 1000
}
}