Skip to navigation

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 focused hooks to access the state and controls your component needs.

import {
AgentProvider,
useAgentState,
useAgentConversation,
useAgentMode,
} from "@deepgram/react";
function App() {
return (
<AgentProvider
config={{
auth: { tokenFactory: () => fetch("/api/token").then((r) => r.text()) },
agent: "YOUR_AGENT_ID",
}}
>
<VoiceAgent />
</AgentProvider>
);
}
function VoiceAgent() {
const { state, start, stop } = useAgentState();
const { conversation } = useAgentConversation();
const { mode } = useAgentMode();
return (
<div>
<p>Mode: {mode}</p>
<button onClick={() => (state === "connected" ? stop() : start())}>
{state === "connected" ? "Disconnect" : "Connect"}
</button>
<ul>
{conversation.map((msg) => (
<li key={msg.id}>
<strong>{msg.role}:</strong> {msg.content}
</li>
))}
</ul>
</div>
);
}

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.

<AgentProvider
config={agentSessionConfig}
microphone={true}
microphoneOptions={{ sampleRate: 16_000 }}
tts={true}
playerSampleRate={24_000}
autoStart={false}
onFunctionCall={handleFunctionCall}
>
{children}
</AgentProvider>

Props

PropTypeDefaultDescription
configAgentSessionConfigrequiredSession configuration. See JavaScript SDK for all options.
microphonebooleantrueEnable microphone capture.
microphoneOptionsMicrophoneOptionsundefinedOptions passed to AgentMicrophone (sample rate, echo cancellation, noise suppression, auto gain control). 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.
onError(message: AgentErrorMessage) => voidundefinedHandler for server-reported agent errors.
onSdkError(error: Error) => voidundefinedHandler for SDK transport errors and automatic-start failures.
onWarning(message: AgentWarningMessage) => voidundefinedHandler for server-reported agent warnings.
onLatencyReport(message: LatencyReportMessage) => voidundefinedHandler for agent latency reports.
onInjectionRefused(message: InjectionRefusedMessage) => voidundefinedHandler when the server rejects an injected message.
onListenUpdated(message: ListenUpdatedMessage) => voidundefinedHandler when the server confirms a updateListen() request.
onPromptUpdated(message: PromptUpdatedMessage) => voidundefinedHandler when the server confirms a updatePrompt() request.
onSpeakUpdated(message: SpeakUpdatedMessage) => voidundefinedHandler when the server confirms a updateSpeak() request.
onThinkUpdated(message: ThinkUpdatedMessage) => voidundefinedHandler when the server confirms a updateThink() request.
onHistory(message: HistoryMessage) => voidundefinedHandler for conversation history received from the server.

Hooks

useAgentState

Connection state and lifecycle controls.

const {
state, // "idle" | "connecting" | "connected" | "reconnecting" | "disconnected"
isIdle, // true when state === "idle"
isConnecting, // true when state === "connecting"
isConnected, // true when state === "connected"
isReconnecting, // true when state === "reconnecting"
isDisconnected, // true when state === "disconnected"
isActive, // true when connected, connecting, or reconnecting
start, // () => Promise<void> — connect session + open mic
stop, // () => void — disconnect + close mic
} = useAgentState();

useAgentConversation

Conversation history and text input.

const {
conversation, // ConversationEntry[]
clearConversation, // () => void
sendUserMessage, // (text: string) => void — inject a text message as the user
sendAgentMessage, // (message: string, behavior?: "default" | "queue" | "interrupt") => void
} = 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.

const {
mode, // "idle" | "listening" | "thinking" | "speaking"
isSpeaking, // true when mode === "speaking"
isListening, // true when mode === "listening"
isThinking, // true when mode === "thinking"
} = 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.

const {
micActive, // true when hardware is open
micMuted, // true when muted (stream still open, not sending audio)
setMicMuted, // (muted: boolean) => void
toggle, // () => void — toggle mute state
enabled, // false when microphone={false} on provider — mic is fully disabled
getInputVolume, // () => number — returns 0-1, call per animation frame
} = 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.

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

useAgentControls

Action methods only, no state. Like the other focused hooks, it consumes AgentContext, so its component re-renders when the provider value changes.

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

const {
start, // () => Promise<void>
stop, // () => void
sendUserMessage, // (text: string) => void
sendAgentMessage, // (message: string, behavior?: "default" | "queue" | "interrupt") => void
updateListen, // (listen: ListenSettings) => void
updateThink, // (think: ThinkSettings | ThinkSettings[]) => void
updateSpeak, // (speak: SpeakSettings | SpeakSettings[]) => void
updatePrompt, // (prompt: string) => void
clearConversation, // () => void
setMicMuted, // (muted: boolean) => void
setOutputMuted, // (muted: boolean) => void
} = useAgentControls();
useEffect(() => {
const handleKey = (e: KeyboardEvent) => {
if (e.key === "m") setMicMuted(true);
};
window.addEventListener("keydown", handleKey);
return () => window.removeEventListener("keydown", handleKey);
}, [setMicMuted]);

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.

useAgentClientTool(
name: string,
handler: (fn: FunctionCallItem) => Promise<string> | string
): 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.

function WeatherWidget() {
const [weather, setWeather] = useState(null);
useAgentClientTool("get_weather", async (fn) => {
const { city } = JSON.parse(fn.input);
const data = await fetchWeather(city);
setWeather(data);
return JSON.stringify(data);
});
return weather ? <WeatherCard data={weather} /> : null;
}

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

function MapComponent() {
const [location, setLocation] = useState({ lat: 0, lng: 0 });
// Always reads the current location value
useAgentClientTool("getLocation", () => {
return JSON.stringify(location);
});
useAgentClientTool("setLocation", (fn) => {
const coords = JSON.parse(fn.input);
setLocation(coords);
return JSON.stringify({ ok: true });
});
return <Map center={location} />;
}

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.

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

useAgentContext

Access the full context value. Prefer the focused hooks above for a smaller, purpose-specific API surface. This hook is available when you need several unrelated values without importing multiple hooks.

const ctx = useAgentContext();
// 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.

import { useDeepgramAgent } from "@deepgram/react";
function VoiceAgent() {
const {
state,
conversation,
micActive,
outputMuted,
start,
stop,
setMicMuted,
setOutputMuted,
sendUserMessage,
interrupt,
} = useDeepgramAgent({
config: {
auth: { tokenFactory: () => fetch("/api/token").then((r) => r.text()) },
agent: "YOUR_AGENT_ID",
},
micOptions: { sampleRate: 16_000 },
playerSampleRate: 24_000,
onFunctionCall: async (fn) => {
return JSON.stringify({ result: "ok" });
},
});
return (
<div>
<button onClick={() => (state === "connected" ? stop() : start())}>
{state === "connected" ? "Disconnect" : "Start"}
</button>
<ul>
{conversation.map((msg) => (
<li key={msg.id}>
<strong>{msg.role}:</strong> {msg.content}
</li>
))}
</ul>
</div>
);
}

Options

OptionTypeDefaultDescription
configAgentSessionConfigrequiredSession configuration (auth, agent ID, settings).
micOptionsMicrophoneOptions{}Microphone options (sample rate, echo cancellation, noise suppression, auto gain control).
playerSampleRatenumber24000Audio player sample rate.
onFunctionCall(fn) => Promise<string> | stringundefinedHandler for agent function call requests.
onError(message: AgentErrorMessage) => voidundefinedHandler for server-reported agent errors.
onSdkError(error: Error) => voidundefinedHandler for SDK transport errors.
onWarning(message: AgentWarningMessage) => voidundefinedHandler for server-reported agent warnings.
onLatencyReport(message: LatencyReportMessage) => voidundefinedHandler for agent latency reports.
onInjectionRefused(message: InjectionRefusedMessage) => voidundefinedHandler when the server rejects an injected message.
onListenUpdated(message: ListenUpdatedMessage) => voidundefinedHandler when the server confirms a updateListen() request.
onPromptUpdated(message: PromptUpdatedMessage) => voidundefinedHandler when the server confirms a updatePrompt() request.
onSpeakUpdated(message: SpeakUpdatedMessage) => voidundefinedHandler when the server confirms a updateSpeak() request.
onThinkUpdated(message: ThinkUpdatedMessage) => voidundefinedHandler when the server confirms a updateThink() request.
onHistory(message: HistoryMessage) => voidundefinedHandler for conversation history received from the server.

Return values

ValueTypeDescription
stateAgentStateCurrent connection state.
modeAgentModeCurrent agent mode: "idle", "listening", "thinking", or "speaking".
isSpeakingbooleanWhether the agent is speaking.
isListeningbooleanWhether the agent is listening.
isThinkingbooleanWhether the agent is preparing a response.
micActivebooleanWhether the microphone hardware is open.
micMutedbooleanWhether the microphone is muted.
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.
sendAgentMessage(message: string, behavior?: AgentMessageBehavior) => voidInject a text message as the agent. behavior can be "default", "queue", or "interrupt".
updateListen(listen: ListenSettings) => voidUpdate speech-to-text settings during the session.
updateThink(think: ThinkSettings | ThinkSettings[]) => voidUpdate LLM settings during the session.
updateSpeak(speak: SpeakSettings | SpeakSettings[]) => voidUpdate text-to-speech settings during the session.
updatePrompt(prompt: string) => voidUpdate the agent system prompt during the session.
clearConversation() => voidClear the local conversation history and request that the session clears its history.
interrupt() => voidInterrupt agent speech immediately.

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