WidgetConfig Schema
Every field of the widget runtime config you can inject via the embed
WidgetConfig is the resolved configuration the widget runs on. The dashboard produces it. You can also inject a pre-resolved InjectableWidgetConfig through the embed (the config prop or wexioSettings.config) to skip the bootstrap fetch.
type InjectableWidgetConfig =
Omit<WidgetConfig, "branding" | "status" | "security"> & {
security?: InjectableWidgetSecurity;
};Top-Level Fields
| Field | Type | Default | Meaning |
|---|---|---|---|
status | "active" | "disabled" | "plan_blocked" | active | Backend-owned; not host-overridable. |
defaultTab | WidgetTab | home | Initial tab. |
localeStrategy | "AUTO" | "WEBSITE" | "DEFAULT" | AUTO | How the active locale is chosen. |
defaultLocale | string (BCP-47) | en | Canonical / fallback language. |
supportedLocales | string[] | [] | Content allow-list; empty = no filter. |
contentLocaleFallback | boolean | true | Render fallback-locale content when untranslated. |
security | WidgetSecurity | - | Auth config (see below). |
features | WidgetFeatures | all on | Tab toggles. |
theme | WidgetTheme | null | null | Palette, radii, launcher, font. |
themeMode | "light" | "dark" | "auto" | auto | Default mode. |
operatorAvatars | { src; alt }[] | - | Operator avatars for the header and Home. The widget shows the first 3 and a +N circle for the rest. |
organizationLogo | { light; dark } | null | - | Per-mode header logo. |
showLogoInLauncher | boolean | false | Show the header logo on the launcher instead of the chat icon. |
greeting | { headline; subheadline } | "Hi there 👋" | Home top copy; empty hides it. |
homeLayout | HomeBlock[] | null | null | Ordered Home blocks (null = default layout). |
prechatForm | WidgetPrechatForm | null | disabled | Prechat gate. |
branding | WidgetBranding | null | null | Badge visibility (not injectable). |
sounds | WidgetSounds | null | - | Notification sounds. |
messenger | WidgetMessengerConfig | null | - | Messenger copy & behaviour. |
botProtection | WidgetBotProtection | null | - | Turnstile config. |
tracking | WidgetTracking | null | null | Visitor-activity tracking switches. null means both are on. |
contentVersion | number | - | 1 or higher means the widget reads the slot fields below and ignores the legacy messenger.messages and homeLayout. Absent means a legacy config. |
homeSlots | HomeSlot[] | null | null | Home blocks as variants with an audience rule. |
greetingSlot | GreetingSlot | null | - | The greeting as variants. Read only when capabilities has greetingVariants. |
capabilities | string[] | [] | Feature flags the backend sends, such as greetingVariants. Empty means an older backend. |
integrationId, name, publicKey, and allowedOrigins are not part of WidgetConfig. They are internal admin fields.
Enums
type WidgetTab = "home" | "messages" | "help" | "news" | "profile";
type WidgetLocaleStrategy = "AUTO" | "WEBSITE" | "DEFAULT";
type LauncherPosition = "RIGHT_BOTTOM" | "LEFT_BOTTOM";
type PrechatFieldKind = "NAME" | "EMAIL" | "PHONE" | "CUSTOM_TEXT";
type WidgetMessengerMessageKind = "HINT" | "SYSTEM" | "MESSAGE";features
interface WidgetFeatures {
home: boolean;
messenger: boolean;
help: boolean;
news: boolean;
profile?: boolean; // default true
}If defaultTab points at a disabled feature, the widget falls back to Messages, then Home, Help and News, in that order. With a single feature enabled, the bottom nav disappears.
theme
interface WidgetTheme {
light?: WidgetThemePalette;
dark?: WidgetThemePalette;
radii?: { sm?: number; md?: number; lg?: number; xl?: number };
launcherPosition?: LauncherPosition;
launcherOffset?: { x: number; y: number }; // px from the corner, each axis 0-200
fontFamily?: string;
homeBackdropGlow?: boolean; // default true, the radial glow behind the Home header
}WidgetThemePalette keys (all optional strings): background, surface, surfaceElevated, text, textMuted, textSubtle, border, borderStrong, primary, primaryHover, primaryForeground, launcherBackground, launcherForeground, success, danger, homeBackdrop. homeBackdrop is the hex colour of the glow behind the Home header. Unset, it follows primary of the same mode. See Theming for the CSS-variable mapping.
security
interface WidgetSecurity {
requireAuth: boolean;
google: { enabled: boolean; clientId: string | null };
passkey: { enabled: boolean };
}In InjectableWidgetConfig, security is the slimmer InjectableWidgetSecurity: requireAuth?, google.enabled?, passkey.enabled?. The Google clientId is not host-injectable. The backend reads it from the integration.
prechatForm
interface WidgetPrechatForm {
enabled: boolean;
fields: {
kind: PrechatFieldKind; // NAME | EMAIL | PHONE | CUSTOM_TEXT
key: string; // /^[a-z0-9_]{1,32}$/
label: string; // empty → localized default
required: boolean;
}[];
}messenger
interface WidgetMessengerConfig {
title: string | null; // ≤120, null → localized default
description: string | null; // ≤500, null → localized default
aiAssistantAvatar: string | null;
aiAssistant?: { enabled: boolean; name: string | null; avatar: string | null };
commands: string[]; // ≤20, each /^\/[a-zA-Z0-9_-]{1,32}$/
messages: { kind: "HINT" | "SYSTEM" | "MESSAGE"; text: string }[]; // ≤10
messageSlots?: MessageSlot[]; // read instead of messages when contentVersion >= 1
showRelatedNews: boolean;
showRelatedHelpArticles: boolean;
showReactionCounts: boolean;
}aiAssistant.enabled: false hides the agent name on AI messages and the welcome. A null name uses the default. A MESSAGE entry is a plain chat bubble, a real welcome message. See Messenger and Message Targeting.
sounds
interface WidgetSounds {
enabled: boolean;
inboundSoundId: string | null; // preset id or full URL
outboundSoundId: string | null;
volume: number; // 0.0 … 1.0
}botProtection
interface WidgetBotProtection {
turnstile: { enabled: boolean; siteKey: string | null };
}tracking
interface WidgetTracking {
trackWidgetLinks: boolean; // links the visitor opens inside the widget
trackWebsitePages: boolean; // pages the visitor views on your site
}See Analytics.
Targeted Content
With contentVersion of 1 or higher, the backend sends welcome messages, Home blocks and the greeting as slots. Each slot holds an ordered list of variants, and each variant can carry an audience rule in when. The backend has already filtered visitors and filled in every variable. The widget matches origins and paths against the host page and uses the first variant that matches.
interface ContentRule {
visitors?: "ALL" | "ANONYMOUS" | "SIGNED_IN";
origins?: string[];
paths?: { match: "CONTAINS" | "STARTS_WITH" | "EQUALS"; value: string }[];
}
interface MessageSlot { id: string; kind: "HINT" | "SYSTEM" | "MESSAGE"; variants: MessageVariant[]; reappearAfterDays?: number | null }
interface MessageVariant { id: string; when?: ContentRule; text: string; buttons: { id: string; label: string }[] }
interface HomeSlot { id: string; kind: string; variants: { id: string; when?: ContentRule; block: HomeBlock }[] }
interface GreetingSlot { id: string; variants: { id: string; when?: ContentRule; headline: string; subheadline: string }[] }A button is a quick reply: a click sends its label as a visitor message. reappearAfterDays (1 to 365) is how long the launcher bubble stays away after a visitor closes it. null means until the content changes. An unknown condition in when never matches.
Home Blocks
homeLayout is an ordered array of blocks (max 12). The renderer skips unknown kinds.
type HomeBlock =
| { kind: "quick-actions"; buttons: HomeQuickActionButton[]; layout?: "stacked" | "inline" }
| { kind: "help-search"; placeholder?: string; suggestions: HomeHelpSuggestionsConfig }
| { kind: "pinned-articles"; articleIds: string[]; title?: string }
| { kind: "news-preview"; maxItems?: number; title?: string }
| { kind: "team-status"; showResponseTime: boolean; showOperatorAvatars: boolean } // presence, reply time and next opening come from the backend
| { kind: "divider" }
| { kind: "rich-text"; markdown: string }
| { kind: "ask-question"; title?: string; subtitle?: string; action?: "open-messenger" | "open-help" | "open-news" } // default open-messenger
| { kind: "recent-message"; title?: string }
| { kind: "featured-article"; newsId?: string; ctaLabel?: string };
interface HomeQuickActionButton {
label?: string; // ≥1 of label/icon required
icon?: { kind: "named"; name: string; colored?: boolean } // curated list of channel logos and action icons | { kind: "media"; url: string };
action: "open-messenger" | "open-help" | "open-news" | "open-url";
url?: string; // required for "open-url"
style?: "default" | "primary" | "ghost"; // max 1 "primary" per block
}
interface HomeHelpSuggestionsConfig {
mode: "popular" | "recent" | "category" | "manual";
maxItems: number; // 3–8
categoryId?: string; // required for "category"
articleIds?: string[]; // required for "manual"
}Related
- Theming - the palette to CSS variable mapping.
- Web Component - inject a config with
window.wexioSettings. - Data Model - the stored
WebIntegrationrecord.