The official, embeddable conversational form widget for Swfte ChatFlows. Drop-in onboarding, lead capture, support triage, surveys and voice — for React, Next.js, Vue, Svelte and plain HTML, in a single dependency.
A ChatFlow is a conversational replacement for a static form: a server-side runtime extracts structured fields from natural-language replies, validates them, branches, and finishes when every required field is collected. This widget is the polished, themeable, accessible front-end for that runtime — the same one that powers Swfte production deployments.
- About Swfte
- What is a ChatFlow?
- Features
- Installation
- Quick start
- Configuration
- Theming
- Callbacks
- Voice ChatFlows
- Security
- API
- Examples
- Other Swfte SDKs
- Resources
- License
Swfte is the unified AI infrastructure platform — one API for 200+ models from OpenAI, Anthropic, Google, Mistral, Meta and self-hosted GPU deployments, plus production-grade agents, workflows, chatflows, RAG, voice, and MCP servers.
Read the full company profile in ABOUT.md, or visit swfte.com to get started for free.
| Resource | Link |
|---|---|
| Product home | https://www.swfte.com |
| Documentation | swfte.com/resources |
| API reference | swfte.com/developers |
| Pricing | swfte.com/pricing |
| Security | swfte.com/security |
| Status | status.swfte.com |
| GitHub org | github.com/SwfteAI |
- swfte-python — Python SDK (PyPI)
- swfte-node — Node.js / TypeScript SDK (npm)
- swfte-java — Java SDK (Maven Central)
- swfte-chat-widget — embeddable chat widget (npm)
- swfte-chatflow-widget — embeddable conversational form widget (npm)
A ChatFlow is a server-side conversational form runtime. Where a traditional web form gives you a stack of inputs, a ChatFlow gives you a short, branching dialogue that:
- Asks for one piece of information at a time, in natural language.
- Extracts the structured field value from the user's free-text reply (with type coercion, validation, and confidence scoring).
- Branches based on what it has collected so far — skipping fields, looping, or asking follow-ups.
- Completes when every required field has a validated value, then hands back a clean JSON object to your app.
ChatFlows are a category, not a single product. People use them for user onboarding, B2B lead qualification, inbound support triage, NPS and customer-satisfaction surveys, booking and intake, voice phone-call data collection, and more. Anything that today is a multi-step form, a calendly link plus a Notion form, or a 10-question intake — can be replaced by a ChatFlow that completes in a fraction of the time, with higher completion rates and structured output ready for your CRM or database.
This widget renders a ChatFlow defined in your Swfte workspace, talks to the ChatFlow runtime API, and emits the final structured payload via a callback or hook.
- Drop-in React component —
<ChatFlowChat />renders a fully-themed, accessible chat surface in one line. - Headless hooks —
useChatFlow()exposes state and actions if you want to build your own UI. - Framework-agnostic core —
ChatFlowClientworks in vanilla JS, Vue, Svelte, Solid, web components — anything. - Next.js App Router handler —
createChatFlowHandler()keeps your API key server-side with a single import. - Voice-ready — built-in WebRTC and WebSocket voice clients with cold-start readiness UX baked in.
- Themeable — every color, radius, font and spacing exposed as a typed theme object or CSS variable.
- Stable browser identity — emits a persisted
browserIdso server-side voiceprint matching works across sessions. - TypeScript-first — exhaustive types, no
anyin the public surface. - Tree-shakeable, ESM + CJS — pulls in only what you import.
- MIT-licensed — use it anywhere, fork it, embed it.
# npm
npm install @swfte/chatflow-widget
# yarn
yarn add @swfte/chatflow-widget
# pnpm
pnpm add @swfte/chatflow-widgetReact and React DOM are optional peer dependencies — only required if you import from @swfte/chatflow-widget/react or @swfte/chatflow-widget/next.
The widget talks to a small proxy endpoint in your own backend that holds the Swfte API key. On Next.js you get this proxy with a one-liner; for everything else, use the proxy pattern.
import { ChatFlowProvider, ChatFlowChat } from '@swfte/chatflow-widget/react';
function OnboardingChat() {
return (
<ChatFlowProvider
config={{
endpoint: '/api/chatflow',
greeting: "Hey! I'm Zara from Workzil. Ready to set up your profile?",
onComplete: (data) => console.log('Collected:', data),
}}
>
<ChatFlowChat
agentName="Zara"
agentSubtitle="Workzil onboarding"
placeholder="Type your response..."
/>
</ChatFlowProvider>
);
}On Next.js (App Router), expose the proxy in app/api/chatflow/[...path]/route.ts:
import { createChatFlowHandler } from '@swfte/chatflow-widget/next';
export const { GET, POST } = createChatFlowHandler({
apiKey: process.env.SWFTE_API_KEY!,
chatFlowId: process.env.SWFTE_CHATFLOW_ID!,
workspaceId: process.env.SWFTE_WORKSPACE_ID!,
});That's it. The browser bundle never sees your API key. See docs/integrations/nextjs.md for the full walkthrough.
Build your own chat interface using the useChatFlow hook:
import { ChatFlowProvider, useChatFlow } from '@swfte/chatflow-widget/react';
import { useState } from 'react';
function CustomChat() {
const { state, send } = useChatFlow();
const [input, setInput] = useState('');
return (
<div>
{state.messages.map((msg) => (
<div key={msg.id} className={msg.role}>
{msg.content}
</div>
))}
<input
value={input}
onChange={(e) => setInput(e.target.value)}
onKeyDown={(e) => {
if (e.key === 'Enter') {
send(input);
setInput('');
}
}}
/>
<div>Progress: {state.progressPercent}%</div>
<div>Collected: {JSON.stringify(state.collectedData)}</div>
</div>
);
}The core ChatFlowClient is a tiny, dependency-free class. Drive any UI off it.
import { ChatFlowClient } from '@swfte/chatflow-widget';
const client = new ChatFlowClient({
endpoint: '/api/chatflow',
onComplete: (data) => saveProfile(data),
});
await client.start();
client.subscribe(() => {
const { messages, collectedData, progressPercent } = client.state;
renderUI(messages, collectedData, progressPercent);
});
await client.send('My name is Yuki, I am a product designer from Tokyo');See docs/integrations/vue.md, docs/integrations/svelte.md and docs/integrations/vanilla-html.md for framework-specific recipes.
Two configs to know: client config (for ChatFlowProvider / ChatFlowClient, runs in the browser, never holds secrets) and server config (for createChatFlowHandler, runs in your backend, holds the API key).
| Prop | Type | Default | Description |
|---|---|---|---|
endpoint |
string |
required | URL path to your mounted proxy handler, e.g. /api/chatflow. |
greeting |
string |
— | Optional greeting shown if the engine doesn't return one. |
prefilledData |
Record<string, unknown> |
{} |
Field values pre-populated when the session starts (e.g. userId). |
timeout |
number |
30000 |
Per-request timeout in ms. |
headers |
Record<string, string> |
{} |
Extra headers forwarded to your proxy (e.g. X-Tenant-Id). |
voiceRuntimeVersion |
'V1' | 'V2' |
server-resolved | Pin a voice runtime; default is whatever the server returns from /config. |
voiceEndpoint |
string |
server-resolved | Override the voice transport base URL. |
chatFlowId |
string |
server-resolved | Needed by voice clients to attach to the right flow. |
workspaceId |
string |
server-resolved | Needed by voice clients for GPU routing. |
voiceReadinessPollerEnabled |
boolean |
true |
Toggle the cold-start readiness poller. |
onComplete |
(data) => void |
— | Fires when the session reports sessionComplete. |
onFieldExtracted |
(fieldId, value, all) => void |
— | Fires every time a new field appears in collectedData. |
onMessage |
(message) => void |
— | Fires on every assistant message. |
onError |
(error) => void |
— | Fires on errors from the proxy. |
| Prop | Type | Default | Description |
|---|---|---|---|
apiKey |
string |
required | Swfte API key. Keep on the server. |
chatFlowId |
string |
required | The deployed ChatFlow id. |
workspaceId |
string |
— | Workspace scoping. |
baseUrl |
string |
https://api.swfte.com/agents |
Override for self-hosted Swfte. |
channel |
'WEB_CHAT' | 'VOICE' | 'SMS' | 'API' |
'WEB_CHAT' |
Channel for the session. |
language |
string |
'en-US' |
BCP-47 language tag. |
voiceRuntimeVersion |
'V1' | 'V2' |
'V1' |
Voice transport version. |
voiceEndpoint |
string |
derived from baseUrl |
Public voice endpoint. |
greeting |
string |
— | Greeting forwarded to the client via GET /config. |
| Prop | Type | Default | Description |
|---|---|---|---|
theme |
ChatFlowTheme |
default theme | Visual customization (see Theming). |
showHeader |
boolean |
true |
Show the agent header. |
agentName |
string |
'Assistant' |
Name in the header. |
agentSubtitle |
string |
— | Subtitle under the name. |
showProgress |
boolean |
true |
Show the progress bar. |
placeholder |
string |
'Type your response...' |
Input placeholder. |
className |
string |
— | Wrapper CSS class. |
style |
CSSProperties |
— | Inline styles on the wrapper. |
Every visual aspect is customizable through the theme prop:
<ChatFlowChat
theme={{
colors: {
primary: '#6366f1',
background: '#0f172a',
surface: '#1e293b',
text: '#f8fafc',
textMuted: '#94a3b8',
userBubble: '#6366f1',
userBubbleText: '#ffffff',
agentBubble: '#1e293b',
agentBubbleText: '#f8fafc',
border: '#334155',
progressBar: '#6366f1',
progressTrack: '#334155',
},
typography: {
fontFamily: "'Plus Jakarta Sans', sans-serif",
fontSize: '15px',
lineHeight: '1.5',
},
radius: {
container: '16px',
bubble: '20px',
input: '12px',
button: '12px',
},
spacing: {
messagePadding: '12px 16px',
containerPadding: '16px',
},
}}
/>Every theme value is also exposed as a CSS variable (--swfte-cf-color-primary, --swfte-cf-radius-bubble, …) so you can override styles from a stylesheet without touching JS. Full reference at docs/theming.md.
<ChatFlowProvider
config={{
endpoint: '/api/chatflow',
onComplete: (data) => {
// All required fields collected — save profile, redirect, fire analytics.
console.log('Final data:', data);
},
onFieldExtracted: (fieldId, value, allData) => {
// Called every time a new field is extracted.
console.log(`${fieldId} = ${value}`);
},
onMessage: (message) => {
// Called on every agent message.
console.log('Agent:', message.content);
},
onError: (error) => {
console.error(error.code, error.message);
},
}}
>
...
</ChatFlowProvider>The widget ships with both Swfte Voice transports built in: a legacy WebSocket/PCM client (V1) and a Rust voice-runtime + WebRTC/WHIP client (V2). Your server picks the runtime; the browser auto-resolves.
import { ChatFlowProvider, useVoice, useVoiceReadinessStatus } from '@swfte/chatflow-widget/react';
import { useRef } from 'react';
function VoiceUI() {
const voice = useVoice();
const readiness = useVoiceReadinessStatus();
const audioRef = useRef<HTMLAudioElement>(null);
return (
<>
<audio ref={audioRef} autoPlay />
<button onClick={() => voice.start(audioRef.current!)}>Talk</button>
<button onClick={voice.stop}>Stop</button>
<p>{readiness.copy}</p>
</>
);
}The provider polls GET {endpoint}/v2/gpu/readiness during the cold-start window and surfaces a copy string ready to render as a loader caption ("warming up", "connected via cloud", "connected"). See docs/use-cases/voice-onboarding.md.
Never ship your Swfte API key to the browser. The widget is designed for a small server-side proxy that holds the key and forwards a narrow set of routes:
POST /start— create sessionPOST /input— send user messagePOST /prewarm— fire-and-forget GPU warm-upGET /session/:id— read stateGET /config— public runtime config
On Next.js, createChatFlowHandler builds this proxy for you. On any other stack, docs/proxy-pattern.md shows the request/response shapes — it's a 40-line implementation in any language.
Other recommendations:
- Bind the proxy to authenticated users only.
- Issue short-lived signed URLs for any media.
- Rate-limit
POST /inputper session. - Lock CORS to your own origins.
For full posture details, see swfte.com/security and SECURITY.md.
| Member | Type | Description |
|---|---|---|
start() |
Promise<void> |
Create the session and emit the greeting. |
send(text) |
Promise<void> |
Send user input, append the assistant reply. |
reset() |
void |
Reset the store back to idle. |
subscribe(fn) |
() => void |
Subscribe to state changes; returns an unsubscribe. |
state |
Readonly<ChatFlowState> |
Current state snapshot. |
messages |
readonly ChatFlowMessage[] |
Convenience getter. |
collectedData |
Readonly<Record<string, unknown>> |
Convenience getter. |
isComplete |
boolean |
True when status is completed. |
Functional alternative to new ChatFlowClient(config). Same return type.
| Export | Kind | Description |
|---|---|---|
ChatFlowProvider |
component | Wires a ChatFlowClient into context, owns voice. |
ChatFlowChat |
component | Drop-in chat surface. |
useChatFlow |
hook | { client, state, send, start, reset, voice, voiceReadiness }. |
useChatFlowMessages |
hook | Subscribe to just the messages array. |
useVoice |
hook | The voice sub-controller. |
useVoiceReadinessStatus |
hook | Cold-start readiness with renderable copy. |
| Export | Kind | Description |
|---|---|---|
createChatFlowHandler(config) |
factory | Returns { GET, POST } for App Router. |
| Export | Kind | Description |
|---|---|---|
ChatFlowClient, createChatFlowClient |
class / fn | Framework-agnostic core. |
ChatFlowApi |
class | Lower-level HTTP client (rarely needed directly). |
ChatFlowStore |
class | Reducer-style store backing the client. |
prepareSelfHostedModels, pollUntilReady |
fn | Self-hosted model warm-up helpers. |
startReadinessPoller, useVoiceReadiness |
fn / hook | GPU readiness polling. |
VERSION |
constant | Package version string. |
Full per-symbol reference at docs/api-reference.md and swfte.com/developers.
Minimal, runnable starters live in examples/:
examples/01-react-onboarding— Vite + React onboarding flow.examples/02-nextjs-lead-capture— Next.js App Router with the proxy route fully wired.examples/03-vue-survey— Vue 3 + Vite, NPS-style survey.examples/04-vanilla-html— Single-fileindex.htmlwith the framework-agnostic client.
Cookbooks for common use-cases live in docs/:
- Onboarding
- Lead qualification
- Support triage
- NPS / customer-satisfaction surveys
- Voice phone-call onboarding
- swfte-python — Python SDK (PyPI)
- swfte-node — Node.js / TypeScript SDK (npm)
- swfte-java — Java SDK (Maven Central)
- swfte-chat-widget — embeddable chat widget (npm)
- swfte.com — product home.
- swfte.com/products/chatflows — ChatFlows product page.
- swfte.com/products/voice — Swfte Voice.
- swfte.com/products/agents — Swfte Agents.
- swfte.com/resources — guides and cookbooks.
- swfte.com/developers — full API reference.
- swfte.com/pricing — pay-as-you-go pricing.
- swfte.com/security — security and compliance posture.
- status.swfte.com — service status.
- github.com/SwfteAI — open-source SDKs and examples.
PRs welcome — see CONTRIBUTING.md and CODE_OF_CONDUCT.md. Significant contributions require a signed CLA at cla.swfte.com.
Disclose vulnerabilities to security@swfte.com; details in SECURITY.md.