React

React hooks for voice AI integration

Installation

npm install @ai-chans/sdk-react

Note:

If you're using Next.js App Router, components that use useVoiceAgent must be client components. Add "use client" at the top of the file.

useVoiceAgent Hook

The recommended way to add voice to React apps.

import { useVoiceAgent } from "@ai-chans/sdk-react"
function VoiceChat() {
const { state, isConnected, error, connect, disconnect } = useVoiceAgent(
{ agentToken: "agt_xxx" },
{
onTranscript: (text) => console.log("User:", text),
onResponse: (text) => console.log("Agent:", text),
}
)
const handleClick = () => {
if (state === "idle") {
connect()
} else {
disconnect()
}
}
return (
<div>
{error && <p style={{ color: "red" }}>{error}</p>}
<button onClick={handleClick} disabled={state === "connecting"}>
{state === "idle" ? "Start" : state === "connecting" ? "Connecting..." : "Stop"}
</button>
<p>Status: {state}</p>
</div>
)
}

Options

interface UseVoiceAgentOptions {
agentToken: string // Required: Agent token from dashboard
apiUrl?: string // Optional: API URL (default: https://api.chans.ai)
userId?: string // Optional: User ID for conversation segmentation
}

Callbacks

interface UseVoiceAgentCallbacks {
onStateChange?: (state: ChansState) => void
onConnected?: () => void
onAgentConnected?: (agent: AgentInfo) => void
onAgentDisconnected?: () => void
onTranscript?: (text: string) => void // Interim transcription
onUserTurnComplete?: (text: string) => void // Final transcription
onResponse?: (text: string) => void // Agent response
onDisconnected?: () => void
onError?: (error: Error) => void
}

Return Value

interface UseVoiceAgentReturn {
state: ChansState // Current connection state
isConnected: boolean // Whether connected
error: string | null // Error message if any
connect: () => Promise<void> // Start connection
disconnect: () => Promise<void> // End connection
}

Full Example

import { useState } from "react"
import { useVoiceAgent, type ChansState } from "@ai-chans/sdk-react"
interface Message {
role: "user" | "agent"
text: string
}
function VoiceChat() {
const [messages, setMessages] = useState<Message[]>([])
const { state, error, connect, disconnect } = useVoiceAgent(
{
agentToken: process.env.NEXT_PUBLIC_AGENT_TOKEN!,
apiUrl: process.env.NEXT_PUBLIC_API_URL,
},
{
onUserTurnComplete: (text) => {
setMessages((prev) => [...prev, { role: "user", text }])
},
onResponse: (text) => {
setMessages((prev) => [...prev, { role: "agent", text }])
},
onError: (err) => {
console.error("Voice error:", err)
},
}
)
return (
<div>
<h2>Voice Chat</h2>
{error && <div className="error">{error}</div>}
<div className="messages">
{messages.map((msg, i) => (
<div key={i} className={msg.role}>
<strong>{msg.role}:</strong> {msg.text}
</div>
))}
</div>
<button
onClick={state === "idle" ? connect : disconnect}
disabled={state === "connecting"}
>
{getButtonLabel(state)}
</button>
</div>
)
}
function getButtonLabel(state: ChansState): string {
switch (state) {
case "idle": return "Start Conversation"
case "connecting": return "Connecting..."
case "waiting": return "Waiting for agent..."
case "ready": return "Listening... (click to stop)"
case "processing": return "Processing..."
case "speaking": return "Agent speaking..."
default: return "Stop"
}
}

States

The hook returns a state value indicating the current connection status:

StateDescription
idleNot connected
connectingEstablishing connection
waitingConnected, waiting for agent
readyAgent connected, listening for speech
processingUser spoke, waiting for response
speakingAgent is responding
errorAn error occurred

Next