@helixcall/widget-react-native
v0.4.2
Published
Drop-in Helix AI chat widget for React Native apps (Expo + bare). Chat with your tenant's AI agent, with live-agent handoff.
Downloads
2,548
Maintainers
Readme
@helixcall/widget-react-native
Drop-in Helix AI chat widget for React Native apps (Expo + bare). Your tenant's AI agent answers in-app, with seamless live-agent handoff. Chat-only in this version (voice is on the roadmap).
No native modules — works in Expo Go and bare React Native.
Install
npm install @helixcall/widget-react-nativePeer deps: react >= 17, react-native >= 0.70.
Quick start — floating launcher
import { HelixChat } from "@helixcall/widget-react-native";
export default function App() {
return (
<>
{/* your app */}
<HelixChat tenantId="YOUR_TENANT_ID" />
</>
);
}A floating "Need help?" pill appears bottom-right; tapping it opens the chat panel.
Options
<HelixChat
tenantId="YOUR_TENANT_ID"
agentId="OPTIONAL_AGENT_ID" // pin a specific agent; omit for the tenant default
apiUrl="https://api.helixcall.com" // override only for self-hosted / staging
appearance={{ title: "Acme Support", accent: "#5b3df5", avatarUrl: "https://…/logo.png" }}
/>If you don't pass appearance, the widget loads the appearance configured in Widget Studio for your tenant.
Theme the built-in UI (theme)
appearance is content (title, copy, prompts, accent, avatar — can come from the backend). theme is look — pure-visual overrides applied on the client:
<HelixChat
tenantId="…"
appearance={{ title: "Acme", accent: "#5b3df5", avatarUrl: "https://…/logo.png" }}
theme={{
headerColor: "#0b0b0b", // header bar (defaults to accent)
userBubbleColor: "#5b3df5", // sent bubbles (defaults to accent)
botBubbleColor: "#f1f0ff",
botTextColor: "#1a1a1a",
bubbleRadius: 22, // bubble corner radius
fontFamily: "Inter", // applied to all text
position: "left", // launcher side
launcherStyle: "bubble", // round FAB instead of the labelled pill
launcherLabel: "Chat with us",
placeholder: "Type a message…",
panelStyle: "full", // full-screen instead of bottom sheet
hidePoweredBy: true, // white-label
}}
/>| theme key | Default |
|---|---|
| accentTextColor | #fff |
| background | #fff |
| headerColor | appearance.accent |
| userBubbleColor / userTextColor | accent / #fff |
| botBubbleColor / botTextColor | #f7f7f7 / #131313 |
| bubbleRadius | 18 |
| fontFamily | system |
| position | right |
| launcherStyle | pill (or bubble) |
| launcherLabel | Need help? |
| placeholder | Ask {name} anything… |
| panelStyle | sheet (or full) |
| hidePoweredBy | false |
For a design that goes beyond these knobs, drop to the headless API below and build the UI yourself.
Embed in your own screen (no launcher)
const [open, setOpen] = useState(false);
<HelixChat tenantId="…" embedded open={open} onClose={() => setOpen(false)} />Headless — bring your own design (recommended for custom apps)
Skip the bundled component entirely and own 100% of the UI. The hook handles streaming, the live-agent handoff, and all API plumbing; you render whatever you want.
import { useHelixChat } from "@helixcall/widget-react-native";
function Support() {
// `active: true` starts live-agent polling without the launcher's open/closed concept.
const { messages, loading, liveAgent, agentName, send, stop, reset } =
useHelixChat({ tenantId: "…", active: true });
// render `messages` / call send(text) with your own components
}useHelixChat returns:
| field | type | use |
|---|---|---|
| messages | { id, role, content }[] | the thread (assistant content updates live as it streams) |
| loading | boolean | a reply is streaming |
| liveAgent | boolean | a human agent has taken over |
| agentName | string | who the user is talking to |
| appearance | WidgetAppearance | tenant content (title/prompts/avatar) if you want to use it |
| send(text) | fn | send a user turn |
| stop() | fn | abort the in-flight reply |
| reset() | fn | clear the conversation |
| client | HelixChatClient | the underlying client for advanced calls |
Full reference: example/HeadlessChatScreen.tsx is a complete, hand-styled chat screen built only with this hook (custom header, bubbles, typing, live-agent badge, suggested prompts, composer, reset) — copy it and restyle.
Lowest level: the client
import { createHelixChat } from "@helixcall/widget-react-native";
const client = createHelixChat({ tenantId: "…" });
const cancel = client.send(history, { onDelta, onDone, onError }); // SSE streamed over XHR
const { liveAgent, messages } = await client.pollAgent(since); // human-agent takeoverHow it works
Talks to the same backend as the web widget:
POST /v1/channels/web— streams the assistant reply (SSE overXMLHttpRequest, since RN'sfetchcan't stream a response body).GET /v1/widget/config— tenant appearance + agent name.GET /v1/widget/messages— polls for a human agent's replies + takeover while the panel is open.
Voice (opt-in)
Talk to the same AI agent by voice, like the web widget. Voice needs native WebRTC, so it ships as a separate entry — the chat features above stay dependency-free.
Install the peers + rebuild (not Expo Go — needs a dev/standalone build):
npx expo install @telnyx/webrtc react-native-webrtc react-native-incall-manager
react-native-incall-manageris required on iOS — it puts the audio session intoplayAndRecordand routes audio. Without it an iOS call connects then ends immediately (no mic track).
Add the WebRTC config plugin (microphone permission) to app.json:
{ "plugins": [["@config-plugins/react-native-webrtc", {
"microphonePermission": "Allow $(PRODUCT_NAME) to use your microphone for calls."
}]] }Then:
import { useHelixVoice } from "@helixcall/widget-react-native/voice";
function CallButton({ tenantId }: { tenantId: string }) {
const { state, muted, transcript, start, stop, toggleMute } = useHelixVoice({ tenantId });
// state: "idle" | "connecting" | "live" | "error"
// transcript: { id, role: "user" | "assistant", text, final }[] — live, updates as speech is recognized
return state === "idle"
? <Button title="Talk to us" onPress={start} />
: <>
{transcript.map((l) => <Text key={l.id}>{l.role === "user" ? "You" : "Agent"}: {l.text}</Text>)}
<Button title="End" onPress={stop} />
</>;
}useHelixVoice returns a live transcript (caller + agent), built from the AI realtime events the call streams — render it in your voice UI. It also returns error (a string) on failure, so you can surface why a call didn't start.
It calls POST /v1/widget/voice to get the AI assistant, then anonymous-logs in over WebRTC — the exact same backend flow as the web widget. Full example: example/VoiceButton.tsx.
Note: voice uses the web
@telnyx/webrtcSDK on top ofreact-native-webrtc(the dedicated RN voice SDK has no anonymous AI-assistant login). Verify audio routing on a real device build.
Roadmap
- Image / file attachments (vision).
- Voice: optional CallKit/ConnectionService UI.
