React Hooks & Provider

Build voice agent interfaces with React using AgentProvider and granular hooks.

Looking for pre-built UI components? See React UI Components. For the core JavaScript SDK, see JavaScript.

Installation

$npm install @deepgram/react

@deepgram/react lists @deepgram/agents as a dependency and re-exports the SDK types you need (AgentSessionConfig, AgentSettingsObject, MicrophoneOptions, and the rest), so a single npm install @deepgram/react is all you need for the React layer. If you want direct access to the SDK classes (AgentSession, AgentMicrophone, AgentPlayer), import them from @deepgram/agents.

Usage

Wrap your component tree in AgentProvider, then use hooks to subscribe to exactly the state slices you need. Each hook triggers re-renders only when its own values change.

1import {
2 AgentProvider,
3 useAgentState,
4 useAgentConversation,
5 useAgentMode,
6} from "@deepgram/react";
7
8function App() {
9 return (
10 <AgentProvider
11 config={{
12 auth: { tokenFactory: () => fetch("/api/token").then((r) => r.text()) },
13 agent: "YOUR_AGENT_ID",
14 }}
15 >
16 <VoiceAgent />
17 </AgentProvider>
18 );
19}
20
21function VoiceAgent() {
22 const { state, start, stop } = useAgentState();
23 const { conversation } = useAgentConversation();
24 const { mode } = useAgentMode();
25
26 return (
27 <div>
28 <p>Mode: {mode}</p>
29 <button onClick={() => (state === "connected" ? stop() : start())}>
30 {state === "connected" ? "Disconnect" : "Connect"}
31 </button>
32 <ul>
33 {conversation.map((msg) => (
34 <li key={msg.id}>
35 <strong>{msg.role}:</strong> {msg.content}
36 </li>
37 ))}
38 </ul>
39 </div>
40 );
41}

Replace YOUR_AGENT_ID with a Reusable Agent Configuration UUID, or pass an inline agent config object instead. See Agent Configuration for both patterns.

AgentProvider

The provider creates and manages AgentSession, AgentMicrophone, and AgentPlayer instances. All hooks below must be called within an AgentProvider.

1<AgentProvider
2 config={agentSessionConfig}
3 microphone={true}
4 microphoneOptions={{ vad: true }}
5 tts={true}
6 playerSampleRate={24_000}
7 autoStart={false}
8 onFunctionCall={handleFunctionCall}
9>
10 {children}
11</AgentProvider>

Props

PropTypeDefaultDescription
configAgentSessionConfigrequiredSession configuration. See JavaScript SDK for all options.
microphonebooleantrueEnable microphone capture.
microphoneOptionsMicrophoneOptionsundefinedOptions passed to AgentMicrophone (sample rate, VAD, noise suppression). See JavaScript SDK.
ttsbooleantrueEnable TTS audio playback.
playerSampleRatenumber24000Sample rate for the audio player.
autoStartbooleanfalseConnect to the agent immediately on mount.
onFunctionCall(fn: FunctionCallItem) => Promise<string> | stringundefinedDefault handler for agent function call requests. Dynamic tools registered with useAgentClientTool take priority over this prop.

Hooks

useAgentState

Connection state and lifecycle controls. Re-renders only when connection state changes.

1const {
2 state, // "idle" | "connecting" | "connected" | "reconnecting" | "disconnected"
3 isIdle, // true when state === "idle"
4 isConnecting, // true when state === "connecting"
5 isConnected, // true when state === "connected"
6 isReconnecting, // true when state === "reconnecting"
7 isDisconnected, // true when state === "disconnected"
8 isActive, // true when connected, connecting, or reconnecting
9 start, // () => Promise<void> — connect session + open mic
10 stop, // () => void — disconnect + close mic
11} = useAgentState();

useAgentConversation

Conversation history and text input. Re-renders when a new message arrives.

1const {
2 conversation, // ConversationEntry[]
3 clearConversation, // () => void
4 sendUserMessage, // (text: string) => void — inject a text message as the user
5} = useAgentConversation();

Each ConversationEntry contains:

FieldTypeDescription
idstringUnique identifier for the entry.
role"user" | "assistant"Who said it.
contentstringThe message text.

useAgentMode

Tracks the agent’s speaking/listening mode with playback awareness. The mode transitions from "speaking" to "listening" only after all queued audio finishes playing in the browser, not when the server sends the AgentAudioDone event. This prevents the UI from showing “listening” while the agent’s voice is still audible.

1const {
2 mode, // "idle" | "listening" | "speaking"
3 isSpeaking, // true when mode === "speaking"
4 isListening, // true when mode === "listening"
5} = useAgentMode();

The playback-aware transition is automatic. The provider measures AgentPlayer.getRemainingPlaybackTime() when the server signals audio-done, then delays the mode switch by that duration. No configuration needed.

useAgentMicrophone

Microphone state, mute controls, and input volume.

1const {
2 micActive, // true when hardware is open
3 micMuted, // true when muted (stream still open, not sending audio)
4 setMicMuted, // (muted: boolean) => void
5 toggle, // () => void — toggle mute state
6 enabled, // false when microphone={false} on provider — mic is fully disabled
7 getInputVolume, // () => number — returns 0-1, call per animation frame
8} = useAgentMicrophone();

getInputVolume() reads the current microphone level without triggering a re-render. Call it inside requestAnimationFrame or a canvas draw loop for smooth audio visualizations.

useAgentPlayer

Audio playback state, mute controls, and output volume.

1const {
2 outputMuted, // true when muted
3 setOutputMuted, // (muted: boolean) => void
4 toggle, // () => void — toggle mute state
5 enabled, // false when tts={false} on provider — playback is fully disabled
6 getOutputVolume, // () => number — returns 0-1, call per animation frame
7} = useAgentPlayer();

useAgentControls

Action methods only, no state. All returned functions are useCallback-wrapped refs with stable identity — they never change between renders. Components that use only this hook will never re-render due to agent state changes.

Use this for components that dispatch commands but do not display state, such as a toolbar or keyboard shortcut handler.

1const {
2 start, // () => Promise<void>
3 stop, // () => void
4 sendUserMessage, // (text: string) => void
5 clearConversation, // () => void
6 setMicMuted, // (muted: boolean) => void
7 setOutputMuted, // (muted: boolean) => void
8} = useAgentControls();
1// Safe in effects — stable refs mean no re-runs
2useEffect(() => {
3 const handleKey = (e: KeyboardEvent) => {
4 if (e.key === "m") setMicMuted((prev) => !prev);
5 };
6 window.addEventListener("keydown", handleKey);
7 return () => window.removeEventListener("keydown", handleKey);
8}, [setMicMuted]); // setMicMuted identity never changes

useAgentClientTool

Register a client-side tool handler scoped to the component lifecycle. The handler is automatically unregistered when the component unmounts, so tools only exist while the component that provides them is mounted.

1useAgentClientTool(
2 name: string,
3 handler: (fn: FunctionCallItem) => Promise<string> | string
4): void

Dynamic tools registered with this hook take priority over the onFunctionCall prop on AgentProvider. If no dynamic tool matches the requested function name, the provider falls back to onFunctionCall.

1function WeatherWidget() {
2 const [weather, setWeather] = useState(null);
3
4 useAgentClientTool("get_weather", async (fn) => {
5 const { city } = JSON.parse(fn.input);
6 const data = await fetchWeather(city);
7 setWeather(data);
8 return JSON.stringify(data);
9 });
10
11 return weather ? <WeatherCard data={weather} /> : null;
12}

The handler always captures the latest closure, so referencing component state inside the handler works without stale-state issues.

1function MapComponent() {
2 const [location, setLocation] = useState({ lat: 0, lng: 0 });
3
4 // Always reads the current location value
5 useAgentClientTool("getLocation", () => {
6 return JSON.stringify(location);
7 });
8
9 useAgentClientTool("setLocation", (fn) => {
10 const coords = JSON.parse(fn.input);
11 setLocation(coords);
12 return JSON.stringify({ ok: true });
13 });
14
15 return <Map center={location} />;
16}

useAgentSession

Raw escape hatch to the underlying AgentSession instance. Use for advanced operations not covered by other hooks, such as listening to custom events or calling lower-level session methods.

1const session = useAgentSession();
2
3useEffect(() => {
4 const handler = (msg) => console.log("Agent thinking:", msg);
5 session.on("agent-thinking", handler);
6 return () => session.off("agent-thinking", handler);
7}, [session]);

useAgentContext

Access the full context value. Prefer the focused hooks above for selective re-rendering. This hook is available when you need several unrelated values without importing multiple hooks.

1const ctx = useAgentContext();
2// ctx.state, ctx.mode, ctx.conversation, ctx.micMuted, etc.

Standalone Hook

For simpler apps that do not need shared state across multiple components, useDeepgramAgent manages the session, microphone, and player internally without requiring a provider.

1import { useDeepgramAgent } from "@deepgram/react";
2
3function VoiceAgent() {
4 const {
5 state,
6 conversation,
7 micActive,
8 outputMuted,
9 start,
10 stop,
11 setMicMuted,
12 setOutputMuted,
13 sendUserMessage,
14 interrupt,
15 } = useDeepgramAgent({
16 config: {
17 auth: { tokenFactory: () => fetch("/api/token").then((r) => r.text()) },
18 agent: "YOUR_AGENT_ID",
19 },
20 micOptions: { vad: true },
21 playerSampleRate: 24_000,
22 onFunctionCall: async (fn) => {
23 return JSON.stringify({ result: "ok" });
24 },
25 });
26
27 return (
28 <div>
29 <button onClick={() => (state === "connected" ? stop() : start())}>
30 {state === "connected" ? "Disconnect" : "Start"}
31 </button>
32 <ul>
33 {conversation.map((msg) => (
34 <li key={msg.id}>
35 <strong>{msg.role}:</strong> {msg.content}
36 </li>
37 ))}
38 </ul>
39 </div>
40 );
41}

Options

OptionTypeDefaultDescription
configAgentSessionConfigrequiredSession configuration (auth, agent ID, settings).
micOptionsMicrophoneOptions{}Microphone options (sample rate, VAD, noise suppression).
playerSampleRatenumber24000Audio player sample rate.
onFunctionCall(fn) => Promise<string> | stringundefinedHandler for agent function call requests.

Return values

ValueTypeDescription
stateAgentStateCurrent connection state.
micActivebooleanWhether the microphone hardware is open.
outputMutedbooleanWhether agent audio output is muted.
conversationConversationEntry[]Conversation history.
start() => Promise<void>Connect session and open microphone.
stop() => voidDisconnect session and close microphone.
setMicMuted(muted: boolean) => voidMute or unmute the microphone.
setOutputMuted(muted: boolean) => voidMute or unmute agent audio.
sendUserMessage(text: string) => voidInject a text message as the user.
interrupt() => voidInterrupt agent speech immediately.

useDeepgramAgent does not support useAgentClientTool. Use the provider pattern if you need per-component tool registration.