Skip to main content
The chat components let your customers converse with one of your Digital Workers from inside your app — with streaming replies, inline forms, conversation history, unread badges, and live replies from a human CSM. All components on this page must be rendered inside a <StatisfyProvider>.

DigitalWorkerChat

The full chat widget. The only required prop is the worker to talk to.

Props

Embedding in a launcher

For a collapsible chat bubble, pass your open state to presented and badge the launcher with onUnreadChange:
Unread is tracked client-side (per-thread last-seen counts in localStorage, refreshed by a background poll roughly every 30s). The active thread auto-marks read while presented is true.

Live CSM replies

When a human CSM replies to a conversation from Statisfy, the chat detects the new message on its next poll and surfaces it in the open thread — and as unread elsewhere. No extra wiring is needed; just keep history enabled (the default).

OnboardingModule

A thin wrapper around DigitalWorkerChat for onboarding surfaces. It:
  • Reads the customer_id from the session token and pins initialThreadId to onboarding:<customer_id> — so the same customer always resumes the same onboarding thread.
  • Enables autoLoadConversation, so the chat opens with the right form (or closing message) already on screen and prior history restored across refreshes.
  • Defaults formRenderer to DefaultFormRenderer.
OnboardingModuleProps accepts the same props as DigitalWorkerChat except initialThreadId and autoLoadConversation (both are derived for you).

Inline forms

When the agent needs structured input it emits a present_form tool call. Provide a formRenderer to render it as a real form; on submit, the chat posts a new turn with the collected values as structured_input. The SDK ships a ready-made renderer, DefaultFormRenderer:
To render forms in your own design system, supply a custom FormRenderer:
FormSpec has { prompt, fields }; each FormField has { key, label, type, options?, placeholder?, mandatory? }. The ctx.onSubmit(values) call replays the turn with those values; ctx.disabled is true while a submission is in flight.
If you omit formRenderer, present_form calls render as a generic “tool running” chip and the agent falls back to free-text input.

Headless client

Need full control of the conversation UI? Skip the components and drive the transport directly with createDigitalWorkerClient. (The provider isn’t required for the headless client — you pass config explicitly.)
The client exposes four methods:

sendMessage(content, threadId?, structuredInput?, formPrompt?)

One-shot send; resolves with the full reply.

streamMessage(options)

Streams the reply token-by-token over Server-Sent Events. Drive your UI from the handler callbacks.

loadConversation({ threadId, signal? })

Load a thread’s prior messages plus the orchestrator’s current next action.
Each message includes role (user | assistant | system), content, and a sender_kind (customer | agent | teammate) so you can distinguish AI replies from a human CSM’s.

listConversations({ source?, limit?, signal? })

List the customer’s conversations for a history panel.
Statisfy doesn’t store read-state — compute unread client-side by diffing each thread’s message_count against the last count you saw. See the API Reference for the underlying endpoints, request/response shapes, and error codes.