Cette page est publiée en anglais et en ukrainien ; la version anglaise figure ci-dessous.
Widget configuration in code: window.ShukaiConfig
For developers, in code: every key a page may set in window.ShukaiConfig, where each default comes from, and the three things about the merge that surprise people.
The widget’s configuration is assembled in three layers, last one wins: the built-in defaults, the
configuration the owner saved in the panel (served by GET /widget/config), and whatever the page
puts in window.ShukaiConfig before the script loads.
In the panel: an owner sets these on the Widget settings screen, without code; this page is for setting them from the page’s own code.
<script>
window.ShukaiConfig = {
color: "#059669",
position: "bottom-left",
voiceCharacter: "fox",
theme: { "launcher-radius": "16px" },
};
</script>
<script src="…/widget.js" data-key="…" data-code="…" data-agent-base="…" async></script>
Three things about the merge
- It is shallow.
theme,launcher,stringsandcustomCsseach replace the served value whole, not merge into it. A page that setsstrings: { send: "Go" }throws away every other localized string the owner’s visitors would have had (missing keys fall back to English); a page that setslauncher: { type: "none" }drops the owner’s label and container. - An invalid
positionstops the widget mounting — it is validated, and the constructor throws. Use one of the four corners exactly. - A host override of a server-fixed key changes only the page. Six keys are served as fixed
values whatever the owner’s row holds (
showActionButtons,voiceInputPace,voiceInputAutosend,defaultModeDesktop,defaultModeMobile,teaserDelayMs). A page may still override them, but the server keeps acting on its own value: hide the action buttons withshowActionButtons: falseand the server still counts every escalation link as offered.
Keys a page may set
Appearance
| Key | Type | Default | Meaning |
|---|---|---|---|
color |
CSS colour | #4f46e5 |
the primary colour; a shortcut for theme.primary, which wins over it |
position |
bottom-right · bottom-left · top-right · top-left |
bottom-right |
the owner’s corner; a visitor’s drag overrides it for that visitor |
theme |
{ token: value } |
{} |
theme tokens without the --sa- prefix; unknown tokens are ignored, values are sanitized — Theming |
customCss |
string | "" |
raw CSS appended last inside the shadow root |
strings |
{ key: text } |
48 English keys | the widget’s own text; the served map is localized, so set this only to change a word on purpose |
Launcher and orb
| Key | Type | Default | Meaning |
|---|---|---|---|
launcher.type |
orb · image · none |
orb |
the animated character, an image, or nothing (headless) — Launcher and skins |
launcher.value |
URL | "" |
the image for type: "image"; ignored for orb |
launcher.label |
string | "" |
a visible label makes the launcher a pill; also its aria-label |
launcher.container |
elevated · flat · bare |
elevated |
fill and shadow, fill only, or transparent |
voiceCharacter |
mic · fox · monster · robot2 · kozak |
robot2 |
the orb’s skin; an unknown id draws robot2 |
voiceOrbColor |
CSS colour | "" |
the orb’s body; blank follows the primary colour. The drawn colour is derived and clamped, greys stay grey |
orbColours |
{ slot: colour } |
— | the skin’s own parts; applied to the skin actually drawn |
launcherAttention |
off · subtle · prominent |
subtle |
the closed launcher’s attract animation and the greeting teaser; off is neither |
Behaviour
| Key | Type | Default | Meaning |
|---|---|---|---|
navigateEnabled |
boolean | true |
the widget performs a same-origin navigate itself unless the page cancels the event |
pageActionsEnabled |
boolean | false |
the assistant may fill and press on the page (served from the owner’s setting and the plan) |
pageActionsSubmitPolicy |
off · confirm · auto |
off in the bundle; confirm for a new widget |
the consent gate for presses, enforced server-side |
pageReadValues |
off · marked · all |
off |
which field values may leave the browser |
teaserEnabled |
boolean | false in the bundle; derived from launcherAttention when served |
the greeting bubble on the closed launcher |
faqs |
string[] | [] |
the suggestion chips; the companion shows up to 3, the teaser up to 2 |
greeting |
string | "" |
the opening line; no teaser without one |
handoffCollect · handoffAlways |
boolean | false |
the in-chat contact form; the «Contact us» entrance in the dock, drawn when a target or the form is behind it |
aiLabel |
boolean | false |
the «AI assistant» tag above the hint line (::part(companion-ai-label), string companion.ai_label); the owner switches it on |
actionButtonTypes |
array | ["navigate"] |
which action types draw a button under an answer; served from the owner’s widget |
Where it appears — display only; the key is public, so these are not access control
| Key | Type | Default | Meaning |
|---|---|---|---|
pageRule |
all · except · only |
all |
on every page, every page except pagePatterns, or only on them |
pagePatterns |
string[] | [] |
paths: /login, {id} for any one part (/orders/{id}/receipt), a trailing * for a page and everything under it (/account/*); query ignored |
signedInOnly |
boolean | false |
drawn only after Shukai.setUser(token) — User identity |
A pattern names a page when it matches the address’s path or the route your page declared with
Shukai.setContext({ route }) — which is how a hash-routed app uses these too. A placeholder is a
whole part of the path (/orders/{id}, not /orders/order-{id}), and a path in another alphabet is
written as you read it (/ціни). The verdict is taken again on every route change.
Voice
| Key | Type | Default | Meaning |
|---|---|---|---|
conversationModeEnabled |
boolean | false |
the character’s microphone and spoken answers |
voiceInputEnabled |
boolean | false |
the composer’s dictation microphone |
voice |
{ lang: { name } } |
{} |
the owner’s per-language voice overrides; read by the server when it picks a voice |
Keys a page should not set
These are the connection and served-only lists. Overriding them makes the widget talk to the wrong place or lose what the server computed.
agentBase, widgetKey, code, agentCode (the connection — come from the snippet);
pageLang (derived from <html lang>); supportedLanguages, sttLanguages, sttAutonyms,
handoffTargets (served lists); pageRead, proactive (server-computed from the agent’s
sources); previewMode (the panel’s preview only — it switches page actions off);
voiceProvider (not a key since 2026-10-05: the one voice tier runs on the server, and a value
here is ignored).
Reading the served configuration
GET /widget/config?code=&lang= returns the owner’s configuration in snake_case, localized for
lang; the widget maps it to the camelCase keys above. The response is on
Widget config. The active flag is read before anything else
and cannot be overridden from the page: an inactive widget mounts nothing.