Skip to navigation

React Native

View as Markdown

For real-time voice on iOS and Android, the TypeScript SDK (sarvam-conv-ai-sdk/react-native) uses the same ConversationAgent client as Web. React Native has no built-in browser audio API, so you must pass your own AsyncAudioInterface for microphone capture and playback.

Install

npm install sarvam-conv-ai-sdk
import { ConversationAgent } from "sarvam-conv-ai-sdk/react-native";

Start a voice session

import {
ConversationAgent,
InteractionType,
} from "sarvam-conv-ai-sdk/react-native";
const audioInterface = new MyRNAudioInterface();
const agent = new ConversationAgent({
apiKey: "your_api_key",
config: {
org_id: "your_org_id",
workspace_id: "your_workspace_id",
app_id: "your_app_id",
user_identifier: "user123",
user_identifier_type: "custom",
interaction_type: InteractionType.CALL,
input_sample_rate: 16000,
output_sample_rate: 16000,
},
audioInterface,
platform: "react-native",
transcriptCallback: async (msg) => {
console.log(`${msg.role}: ${msg.content}`);
},
});
await agent.start();
const connected = await agent.waitForConnect(10);
if (!connected) {
// Show an error or retry
}

Set platform: "react-native" and pass an audioInterface that implements AsyncAudioInterface (see Custom audio interface below).

InteractionConfig

FieldRequiredDescription
user_identifier_typeYes'custom', 'email', 'phone_number', or 'unknown'
user_identifierYesThe identifier value; also what you search by in Log Analyser
org_idYesYour organization ID
workspace_idYesYour workspace ID
app_idYesThe agent to connect to
interaction_typeYesInteractionType.CALL for a voice session
input_sample_rateYes8000 or 16000 Hz
output_sample_rateYes16000 or 22050 Hz
versionNoPins a specific committed agent version. If omitted, the SDK uses the latest committed version, and the connection fails if the agent has no committed version
agent_variablesNoSeed agent variables at session start
initial_language_nameNoStarting language; must be one of the agent’s allowed languages
initial_state_nameNoStarting state, if the agent uses states
initial_bot_messageNoFirst message from the agent

Callbacks

Pass any of these to ConversationAgent to react to what happens during the call:

CallbackFires withUse it for
transcriptCallbacktranscript message (role: Role.USER or Role.BOT, content)A live transcript of both sides of the call
audioCallbackaudio chunkRaw agent audio, if you’re handling playback yourself
audioLevelCallbackoutput levelReal-time level for a speaking indicator
eventCallbacksession eventSession events such as connect, barge-in, and end
stateCallbackAgentStateDrive UI from IDLE, CONNECTING, CONNECTED, LISTENING, SPEAKING, or ERROR
startCallback—Session start
endCallback—Session end and cleanup

Custom audio interface

Implement AsyncAudioInterface and feed 16-bit PCM mono at the configured sample rate:

import {
AsyncAudioInterface,
AudioData,
} from "sarvam-conv-ai-sdk/react-native";
class MyRNAudioInterface implements AsyncAudioInterface {
async start(
inputCallback: (audioData: AudioData, frameCount: number) => Promise<void>,
): Promise<void> {
// Initialize your audio recording library
// Call inputCallback with a Uint8Array of 16-bit PCM data
}
async output(audio: Uint8Array, sampleRate?: number): Promise<void> {
// Play 16-bit PCM mono through the speaker
}
interrupt(): void {
// Stop all queued and playing audio (user barge-in)
}
async stop(): Promise<void> {
// Release microphone and audio resources
}
}

Recommended libraries:

Session methods

MethodDescription
await agent.start()Fetch a signed WebSocket URL and connect
await agent.waitForConnect(timeout?)Wait until connected; timeout is in seconds (returns false on timeout)
await agent.sendAudio(data)Send a raw PCM audio chunk
agent.isConnected()Current connection status
agent.getInteractionId()The current interaction (call) ID, once connected
agent.getState()Current AgentState
agent.mute() / agent.unmute()Mute or unmute the microphone without disconnecting. While muted, the SDK sends silence so VAD stays stable
agent.isMuted()Current mute status
await agent.waitForDisconnect()Wait until the session ends
await agent.stop()Close the connection and clean up

Call await agent.stop() on unmount so the WebSocket and audio interface are cleaned up. Reconnection is not supported: each WebSocket URL is single-use. If the connection drops, call stop() and create a new ConversationAgent.

Stop or recreate the agent when the app backgrounds. React Native suspends WebSockets in the background, and you cannot reuse the old URL:

import { useEffect, useRef } from "react";
import { AppState, AppStateStatus } from "react-native";
const appState = useRef(AppState.currentState);
useEffect(() => {
const subscription = AppState.addEventListener(
"change",
(nextState: AppStateStatus) => {
if (appState.current.match(/active/) && nextState === "background") {
agentRef.current?.stop();
}
appState.current = nextState;
},
);
return () => {
subscription.remove();
agentRef.current?.stop().catch(console.error);
};
}, []);

Troubleshooting

Microphone permission denied. Request the microphone before starting a voice session.

Expo:

import { Audio } from "expo-av";
const { granted } = await Audio.requestPermissionsAsync();
if (!granted) {
// Ask the user to enable the permission in Settings
}

Bare React Native, with react-native-permissions:

import { request, PERMISSIONS, RESULTS } from "react-native-permissions";
import { Platform } from "react-native";
const result = await request(
Platform.OS === "ios"
? PERMISSIONS.IOS.MICROPHONE
: PERMISSIONS.ANDROID.RECORD_AUDIO,
);
if (result !== RESULTS.GRANTED) {
// Handle denied permission
}

No audio output. Check device volume and the iOS silent switch. Confirm output() writes to the speaker at output_sample_rate.

Connection timeout. Check connectivity, API key, org_id / workspace_id / app_id, and that the agent has a committed version.

Never embed your API key in the app binary. Point baseUrl at a backend you control, leave apiKey empty, and pass your app auth in customHeaders (cookies are not available in React Native):

const agent = new ConversationAgent({
apiKey: "",
baseUrl: "https://api.yourapp.com/sarvam/",
customHeaders: {
Authorization: "Bearer eyJhbGciOiJIUzI1NiIs...",
"X-User-Id": "user-123",
},
platform: "react-native",
audioInterface: new MyRNAudioInterface(),
config: {
// ...
},
});