Deskbell

Configure the widget

The four layers of widget configuration, their precedence, and every option the element accepts, listed from the descriptor the widget itself reads.

Four layers, each an escape hatch for the one below. Most deployments stop at the first.

  1. Dashboard. Set appearance under Appearance. No code, no redeploy.
  2. Attributes. Override anything per page from the embed code.
  3. CSS. --deskbell-* custom properties for colour, ::part() for shape.
  4. Slots. Replace the launcher, header, empty state or footer with your own markup.

Precedence, lowest to highest:

defaults  <  dashboard config  <  attributes / JS config  <  host-page CSS

Host-page CSS wins last on purpose. deskbell-widget { --deskbell-accent: red } is the most explicit statement of intent on the page, so nothing resolved at runtime beats it. No rule in the widget uses !important.

Every table in this section is rendered from packages/shared/src/widget-config.ts at build time. That is the same descriptor the widget, the embed loader, the React wrapper, the dashboard editor and the database schema read, so this page cannot list an option the widget does not have.

Settings, Appearance: the option form on the left and the widget rendering the changes live on the right

Options

Each option is an attribute on <deskbell-widget>. On the script tag, prefix it with data-.

List options are separated by |, because questions contain commas. Object options take JSON.

Identity

AttributeTypeDefaultDescription
project-keystring—Public widget key. Not a secret — origin binding is the control.
api-urlstring—Your Deskbell server. Leave empty when the widget is on the same origin.
localestring—BCP-47 tag for the visitor's language. Defaults to the browser's.
contextcontext—Where on your site the conversation starts, as JSON: { "account": { "id": "…", "name": "…" } }. Stored with the thread, shown in the dashboard.
readonlybooleanfalseShow one conversation with no composer, for support staff whose token carries the project's staff claim.
conversation-idstring—The conversation to open on load. With read-only it loads through the staff preview.

Theme

AttributeTypeDefaultDescription
color-schemelight | dark | autolightLight, dark, or follow the visitor's system setting.
accentCSS value#2b6b4fDrives the launcher, header, your messages and focus rings.
radiusCSS value16pxBorder radius of the chat panel, e.g. 16px or 0.
fontCSS valuesystem-ui, -apple-system, sans-serifAny CSS font-family value. Load the font on your own page.
themeobject—Fine-grained overrides for any of the widget's CSS custom properties.
color-scheme-selectorstring—CSS selector of the element your site keeps its theme on, e.g. html. A dark or light class or data-theme there overrides the colour scheme.

Launcher

AttributeTypeDefaultDescription
launcherbell | chat | sparkle | nonebellBuilt-in icon, or 'none' if you open the widget from your own button.
launcher-icon-urlstring—Square image used instead of the built-in icon.
launcher-labelstring—Text beside the icon, e.g. 'Ask AI'. Turns the circle into a pill.
positionbottom-right | bottom-leftbottom-rightWhich corner the launcher sits in.
offset-xnumber20Distance from the side of the viewport, in pixels.
offset-ynumber20Distance from the bottom of the viewport, in pixels.
launcher-draggablebooleanfalseLet visitors drag the launcher anywhere on screen. The panel follows; the position is not remembered.

Behaviour

AttributeTypeDefaultDescription
modefloating | inlinefloatingFloating: a launcher opens a panel. Inline: the widget fills its container and is always open; give the element a height.
open-on-loadbooleanfalseOpen the panel automatically when the page loads.
trigger-selectorstring—CSS selector — clicking any matching element opens the widget.
hotkeystring—Shortcut that opens the widget, e.g. mod+k. Empty to disable.
conversation-historybooleantrueLet visitors return to their recent conversations.
history-layoutstack | sidebarstackStack: a list view behind a back button. Sidebar: threads in a collapsible rail beside the conversation, with delete.
resume-threadlast | newest | nonelastWhat a fresh open shows: the thread this browser last had open, the visitor's newest thread, or nothing.
thread-idle-minutesnumber30A thread silent for this long is not resumed; the next question starts a new one. 0 never rolls over.
scope-keystring—A key of the page's context. When present, the sidebar can show only the threads started under that key's value.
feedbackbooleantrueShow thumbs up/down under answers. Feeds the docs-gap analytics.
feedback-reasonsJSON array—Reasons offered on a downvote, each with an id, a label and an optional free-text limit. JSON; empty means the built-in three.

Content

AttributeTypeDefaultDescription
suggested-questionslist, max 4—Up to four starter questions shown in the empty state.
prompt-groupsJSON array—Cards in the empty state, each a title, optional description and icon, and up to six prompts. JSON; replaces the suggested questions when set.
disclaimerstring—Short notice above the footer, e.g. that answers are AI-generated. Markdown links work.
copyobject—Override any of the widget's UI strings.
powered-bybooleantrueRemoving the badge requires an enterprise licence.

Where the rest lives

  • Theming: tokens, parts, slots, following the page's theme, and the recipes.
  • Behaviour: inline mode, welcome cards, feedback reasons, the thread sidebar, where a conversation starts, the draggable launcher, the disclaimer, answer formatting and branding.
  • JavaScript API: commands, events and lifecycle.

On this page