Chatbot Config & Theming
GET /api/v1/chat/config returns the public UI configuration for the chatbot tied to the
visitor token. Fetch it after POST /api/v1/chat/auth and before rendering the first chat
screen. The response contains display identity, fully resolved theme values, livechat controls,
URL-triggered popup messages, and dynamic form references.
For endpoint authentication and the full conversation flow, see Chatbot API Flow.
Naming and resolution rules
The config response is designed so clients can render without guessing:
- Colors are always suffixed
_colorand scoped by their parent object. Usetheme.input.background_color, notinput_background_color. - The theme is fully resolved. Every color and size the widget needs is required and non-null. The server resolves defaults. Clients should apply values directly and never write fallback logic.
| nullappears only when null is meaningful: optional assets such as logos, launcher images, and avatars, or optional effects such as gradient color and borders wherenullmeans no border.- Sizes are CSS length strings, such as
"40px"or"2.5em". Multipliers are unitless floats with a documented base. - Image assets are objects, for example
{ "url": "https://cdn.example.com/avatar.png" }. - Booleans are
*_enabledtoggles or adjective flags with server defaults. - Discriminated unions only appear for genuinely different shapes, with one
typefield.
Complete response example
{
"display": {
"name": "Customer Service Bot",
"avatar": {
"url": "https://cdn.example.com/bot-avatar.png"
},
"welcome_message": "Hi! How can I help you?",
"subtitle": {
"text": "You are chatting with an AI assistant.",
"link": {
"text": "Contact support",
"url": "https://shop.example.com/support"
}
},
"privacy_policy_url": "https://shop.example.com/privacy"
},
"livechat": {
"enabled": true,
"configured": true,
"availability_status": "live",
"availability_reason": "always_on",
"show_livechat_logo": true,
"attachments_enabled": true,
"max_attachment_size_bytes": 5242880
},
"theme": {
"brand": {
"primary_color": "#4F46E5"
},
"surface": {
"background_gradient_color": "#FFFFFF",
"background_color": "#FFFFFF",
"muted_text_color": "#6B7280"
},
"header": {
"alignment": "center",
"logo": {
"url": "https://cdn.example.com/logo.png"
},
"button": {
"background_color": "#F3F4F6",
"icon_color": "#111827"
}
},
"messages": {
"assistant": {
"background_color": "#F3F4F6",
"text_color": "#111827",
"avatar_size": "40px",
"border_color": null,
"thinking_border_gradient": ["#FFFFFF", "#4F46E5", "#FFFFFF"]
},
"user": {
"background_color": "#4F46E5",
"text_color": "#FFFFFF",
"border_color": null
}
},
"input": {
"text_color": "#333333",
"placeholder_color": "#a9a9a9",
"background_color": "#FFFFFF",
"border_color": "#000000",
"height": "2.5em",
"send_button": {
"icon_color": "#FFFFFF"
}
},
"launcher": {
"adaptive_icon_color_enabled": false,
"image": {
"desktop_url": null,
"mobile_url": null
}
},
"product_card": {
"button": {
"background_color": "#4F46E5",
"bold": true
},
"discount_price_color": "#cc0000"
},
"layout": {
"border_radius_multiplier": 1
},
"font": {
"web": {
"family": "'Inter', sans-serif",
"asset_url": "https://fonts.askdiverge.ai/system/fonts/default/web/inter-regular.woff2",
"format": "woff2",
"sha256": null
},
"ios": {
"asset_url": "https://fonts.askdiverge.ai/system/fonts/default/native/inter-regular.ttf",
"format": "ttc",
"sha256": null
},
"android": {
"asset_url": "https://fonts.askdiverge.ai/system/fonts/default/native/inter-regular.ttf",
"format": "ttc",
"sha256": null
}
}
},
"dark_theme": {
"brand": {
"primary_color": "#4F46E5"
},
"surface": {
"background_gradient_color": null,
"background_color": "#1c1c1e",
"muted_text_color": "#9ba1a6"
},
"header": {
"alignment": "center",
"logo": {
"url": "https://cdn.example.com/logo.png"
},
"button": {
"background_color": "rgba(44, 44, 46, 0.85)",
"icon_color": "#ffffff"
}
},
"messages": {
"assistant": {
"background_color": "#2c2c2e",
"text_color": "#f2f2f7",
"avatar_size": "40px",
"border_color": null,
"thinking_border_gradient": ["#FFFFFF", "#4F46E5", "#FFFFFF"]
},
"user": {
"background_color": "#4F46E5",
"text_color": "#ffffff",
"border_color": null
}
},
"input": {
"text_color": "#f2f2f7",
"placeholder_color": "#8e8e93",
"background_color": "#2c2c2e",
"border_color": "#3a3a3c",
"height": "2.5em",
"send_button": {
"icon_color": "#ffffff"
}
},
"launcher": {
"adaptive_icon_color_enabled": false,
"image": {
"desktop_url": null,
"mobile_url": null
}
},
"product_card": {
"button": {
"background_color": "#4F46E5",
"bold": true
},
"discount_price_color": "#ff6b6b"
},
"layout": {
"border_radius_multiplier": 1
},
"font": {
"web": {
"family": "'Inter', sans-serif",
"asset_url": "https://fonts.askdiverge.ai/system/fonts/default/web/inter-regular.woff2",
"format": "woff2",
"sha256": null
},
"ios": {
"asset_url": "https://fonts.askdiverge.ai/system/fonts/default/native/inter-regular.ttf",
"format": "ttc",
"sha256": null
},
"android": {
"asset_url": "https://fonts.askdiverge.ai/system/fonts/default/native/inter-regular.ttf",
"format": "ttc",
"sha256": null
}
}
},
"popup_messages": [
{
"message": "Need help finding the right size? Ask me!",
"url_pattern": "https://shop.example.com/products/*"
}
],
"forms": [
{
"trigger": "livechat_waiting",
"form_id": "livechatWaitingContact",
"name": "Waiting contact",
"override_targets": [],
"submit_actions": []
}
]
}Display
| Field | Purpose and render location | Null semantics |
|---|---|---|
display.name | Header/title bar name. Server falls back from header title to chat window title to chatbot_id. | Never null. |
display.avatar.url | Assistant avatar image used beside assistant messages and in the header area when present. | null means no custom avatar. |
display.welcome_message | Initial greeting shown at the start of a new conversation. | null means no configured greeting. |
display.subtitle.text | Header subtitle text below the display name. | null means no subtitle text. |
display.subtitle.link | Optional link rendered in the header subtitle area. | null means no subtitle link. |
display.subtitle | Combined subtitle object. When present, at least one of text or link is non-null. | null means no configured subtitle or link. |
display.privacy_policy_url | Footer privacy link. | Never null; server falls back to the default Diverge privacy policy. |
Theme
theme.brand
| Field | Purpose and render location | Null semantics |
|---|---|---|
primary_color | Primary accent for title/link accents, send button background, product CTA fallback, and user message background fallback. Default #1a1d56. | Never null. |
theme.surface
| Field | Purpose and render location | Null semantics |
|---|---|---|
background_color | Main chat window background behind messages, livechat panels, and composer. Default #ffffff. | Never null. |
background_gradient_color | Top title-bar and bottom footer fade overlay color. | null means derive the fade from background_color or white. |
muted_text_color | Header subtitle, footer links, livechat helper copy, close-rating copy, and session form helper text. Default #707070. | Never null. |
theme.header
| Field | Purpose and render location | Null semantics |
|---|---|---|
alignment | Header title/subtitle alignment. Default center. | Never null. |
logo.url | Header logo above the title. | null means no custom logo. |
button.background_color | Header utility button group background for livechat, reset, minimize, and close controls. Default rgba(242, 240, 239, 0.85). | Never null. |
button.icon_color | Header utility icon color. Default #000000. | Never null. |
theme.messages
| Field | Purpose and render location | Null semantics |
|---|---|---|
assistant.background_color | Assistant message bubble background. Default #e5eaf5. | Never null. |
assistant.text_color | Assistant message text. Default #262641. | Never null. |
assistant.avatar_size | Assistant avatar width and height as a CSS length. Default 1.3em. | Never null. |
assistant.border_color | Assistant message bubble border. | null means no border. |
assistant.thinking_border_gradient | Color stops for the assistant thinking-state border animation. | Empty array means the widget uses its built-in primary/neutral fallback. |
user.background_color | User message bubble background. Default is theme.brand.primary_color. | Never null. |
user.text_color | User message text. Default #ffffff. | Never null. |
user.border_color | User message bubble border. | null means no border. |
theme.input
| Field | Purpose and render location | Null semantics |
|---|---|---|
text_color | Composer textarea text. Default #333333. | Never null. |
placeholder_color | Composer placeholder text. Default #a9a9a9. | Never null. |
background_color | Composer field background before widget opacity. Default #ffffff. | Never null. |
border_color | Composer field outline color before widget opacity. Default #000000. | Never null. |
height | Composer minimum textarea height as a CSS length. Default 2.5em. | Never null. |
send_button.icon_color | Send button arrow/icon color. Default #ffffff. | Never null. |
theme.launcher
| Field | Purpose and render location | Null semantics |
|---|---|---|
adaptive_icon_color_enabled | Whether the launcher icon adapts to the host page background. Default false. | Never null. |
image.desktop_url | Desktop launcher image. | null means use the default launcher icon. |
image.mobile_url | Mobile launcher image. | null means use the desktop launcher image or default icon. |
theme.product_card
| Field | Purpose and render location | Null semantics |
|---|---|---|
button.background_color | Product card CTA and add-to-cart button background. Default is theme.brand.primary_color. | Never null. |
button.bold | Whether product CTA text is bold. Default true. | Never null. |
discount_price_color | Intended color for discount or previous-price text in product cards. The current web widget does not render this field yet. Default #cc0000. | Never null. |
theme.layout
| Field | Purpose and render location | Null semantics |
|---|---|---|
border_radius_multiplier | Multiplies the widget's built-in default radii. 1 means default. | Never null. |
theme.font
| Field | Purpose and render location | Null semantics |
|---|---|---|
web.family | CSS font-family value used by web clients. | Never null. |
web.asset_url | Hosted web font asset or stylesheet. | Never null. |
web.format | Web font asset format, or stylesheet. | Never null. |
web.sha256 | SHA-256 hex digest of the web font file bytes, intended as a client cache key. Not an integrity proof on its own. | null when the chatbot uses the default system font or the digest is unknown (legacy uploads). |
ios.asset_url | Native iOS font asset. | Never null. |
ios.format | iOS font asset format. | Never null. |
ios.sha256 | SHA-256 hex digest of the iOS font file bytes, intended as a client cache key. Not an integrity proof on its own. | null when the chatbot uses the default system font or the digest is unknown (legacy uploads). |
android.asset_url | Native Android font asset. | Never null. |
android.format | Android font asset format. | Never null. |
android.sha256 | SHA-256 hex digest of the Android font file bytes, intended as a client cache key. Not an integrity proof on its own. | null when the chatbot uses the default system font or the digest is unknown (legacy uploads). |
When sha256 is non-null, prefer it over asset_url alone when deciding whether to reuse a
cached font file. When it is null, treat it as no server-provided cache key and fall back to
URL-based caching or re-fetch. Clients that need verification must hash the downloaded bytes and
compare to the config value.
Dark mode
dark_theme is a required sibling of theme with the same shape. Choose the active theme once
from the visitor's color scheme and apply it directly:
const activeTheme = prefersDark ? config.dark_theme : config.theme;Do not merge dark_theme with theme, and do not add null checks or fallback logic. When dark
mode is not configured for a chatbot, the server returns dark_theme equal to theme, so existing
chatbots keep their light appearance for dark-scheme visitors.
Dashboard users configure this in the Chatbot page under Branding → Dark mode. In v1, assets and mode-independent fields are shared across modes: header logo, launcher images, assistant avatar size, input height, product button boldness, layout, and font assets.
| Dark field fallback | Default behavior |
|---|---|
brand.primary_color | Light theme.brand.primary_color |
surface.background_gradient_color | null |
surface.background_color | #1c1c1e |
surface.muted_text_color | #9ba1a6 |
header.button.background_color | rgba(44, 44, 46, 0.85) |
header.button.icon_color | #ffffff |
messages.assistant.background_color | #2c2c2e |
messages.assistant.text_color | #f2f2f7 |
messages.assistant.border_color | Light theme.messages.assistant.border_color |
messages.assistant.thinking_border_gradient | Light theme.messages.assistant.thinking_border_gradient |
messages.user.background_color | Dark brand.primary_color |
messages.user.text_color | #ffffff |
messages.user.border_color | Light theme.messages.user.border_color |
input.text_color | #f2f2f7 |
input.placeholder_color | #8e8e93 |
input.background_color | #2c2c2e |
input.border_color | #3a3a3c |
input.send_button.icon_color | #ffffff |
product_card.button.background_color | Dark brand.primary_color |
product_card.discount_price_color | #ff6b6b |
Livechat
| Field | Purpose and render location | Null semantics |
|---|---|---|
enabled | Whether a visitor can request a live agent now. Default false. | Never null. |
configured | Whether livechat is configured and can become available. Default false. | Never null. |
availability_status | Current live/offline state for livechat UI. Default offline. | Never null. |
availability_reason | Why livechat is live or offline. Default disabled. | Never null. |
show_livechat_logo | Controls whether the livechat header button/logo is shown before a handover is active. Default true. | Never null. |
attachments_enabled | Whether livechat attachments are allowed. Default false unless livechat is configured. | Never null. |
max_attachment_size_bytes | Attachment upload limit in bytes. Default 5242880. | Never null. |
Popup messages
| Field | Purpose and render location | Null semantics |
|---|---|---|
popup_messages[].message | Popup text shown when the current page URL matches url_pattern. | Never null. |
popup_messages[].url_pattern | URL pattern that triggers the popup. | Never null. |
An empty array means no URL-triggered popups are configured.
Forms
| Field | Purpose and render location | Null semantics |
|---|---|---|
forms[].form_id | Stable form identifier. Fetch the full definition with GET /api/v1/chat/forms/{form_id}. | Never null. |
forms[].name | Optional operator-facing form name. | null means unnamed. |
forms[].trigger | When the form can be used, such as livechat_waiting or session_start. | Never null. |
forms[].override_targets | Built-in action targets this form replaces. | Empty array means no overrides. |
forms[].submit_actions | Post-submit actions such as saving a lead or starting livechat. | Empty array means no extra submit actions. |
An empty array means no dynamic forms are available to this visitor/session.
Dashboard label to API field
| Dashboard label | API field |
|---|---|
| Primary color | theme.brand.primary_color |
| Avatar | display.avatar.url |
| Header logo | theme.header.logo.url |
| Header Title | display.name |
| Header Subtitle | display.subtitle.text |
| Privacy Policy URL | display.privacy_policy_url |
| Background gradient | theme.surface.background_gradient_color |
| Chat background | theme.surface.background_color |
| Muted text | theme.surface.muted_text_color |
| Header button background | theme.header.button.background_color |
| Header button icon | theme.header.button.icon_color |
| Assistant message | theme.messages.assistant.background_color |
| Assistant message text | theme.messages.assistant.text_color |
| Assistant message border | theme.messages.assistant.border_color |
| Avatar size | theme.messages.assistant.avatar_size |
| User message | theme.messages.user.background_color |
| User message text | theme.messages.user.text_color |
| User message border | theme.messages.user.border_color |
| Input text | theme.input.text_color |
| Input placeholder | theme.input.placeholder_color |
| Input background | theme.input.background_color |
| Input border | theme.input.border_color |
| Input field height | theme.input.height |
| Send button icon | theme.input.send_button.icon_color |
| Button background | theme.product_card.button.background_color |
| Discount price | theme.product_card.discount_price_color |
| Border Radius | theme.layout.border_radius_multiplier |
| Custom Chat Button Image | theme.launcher.image.desktop_url |
| Mobile Chat Button Image | theme.launcher.image.mobile_url |
| Adaptive start button color | theme.launcher.adaptive_icon_color_enabled |