Quick Start
An easy to follow guide to setup the SDK and incorporate Orga AI into your app
Installation
Install the SDK from npm
npm install @orga-ai/sdk-react-native
Install the peer dependencies
npm install react-native-webrtc react-native-incallmanager
Project configuration
This SDK requires both camera and microphone permissions.
Configure app.json
{
"expo": {
"ios": {
"infoPlist": {
"NSCameraUsageDescription": "Allow $(PRODUCT_NAME) to access your camera",
"NSMicrophoneUsageDescription": "Allow $(PRODUCT_NAME) to access your microphone"
}
},
"android": {
"permissions": [
"android.permission.CAMERA",
"android.permission.RECORD_AUDIO"
]
}
}
}
Development build
The SDK requires a development build and won’t workin in Expo Go due to native dependencies. Won’t work on a simulator either. Must use a physical device
npx expo prebuild
eas build --platform all --profile development
Set Up Backend Proxy
You need a secure backend proxy to protect your API key. The location of your environment variables depends on your chosen approach:
Option A: Using Expo API Routes (SDK 50+)
If using Expo API Routes, create a .env file in your Expo project root:
ORGA_API_KEY=your_orga_api_key_here
USER_EMAIL=your_user_email_here
Get your API key from the OrgaAI dashboard: https://platform.orga-ai.com/login
// app/orga-client-secrets+api.ts
const ORGA_API_KEY = process.env.ORGA_API_KEY;
const fetchIceServers = async (ephemeralToken: string) => {
const URL = `https://api.orga-ai.com/v1/realtime/ice-config`;
try {
const iceServersResponse = await fetch(URL, {
method: "GET",
headers: {
Authorization: `Bearer ${ephemeralToken}`,
},
});
const data = await iceServersResponse.json();
return data.iceServers;
} catch (error) {
console.error("Error fetching ice servers:", error);
throw error;
}
};
export async function GET(request: Request) {
const USER_EMAIL = process.env.USER_EMAIL;
if (!ORGA_API_KEY) {
return NextResponse.json(
{ error: 'Missing ORGA_API_KEY environment variable' },
{ status: 500 }
);
}
if (!USER_EMAIL) {
return NextResponse.json(
{ error: 'Missing USER_EMAIL environment variable' },
{ status: 500 }
);
}
const apiUrl = `https://api.orga-ai.com/v1/realtime/client-secrets?email=${encodeURIComponent(USER_EMAIL)}`;
const ephemeralResponse = await fetch(apiUrl, {
method: "POST",
headers: {
Authorization: `Bearer ${ORGA_API_KEY}`,
},
});
if (!ephemeralResponse.ok) {
throw new Error('Failed to fetch session token');
}
const { ephemeral_token } = await ephemeralResponse.json();
const iceServers = await fetchIceServers(ephemeral_token);
return Response.json({ ephemeralToken: ephemeral_token, iceServers }, {status: 200})
} catch (error) {
return Response.json({error: "Internal server error"}, { status: 500 });
}
}
Option B: Custom Backend Server
If using a separate backend server, store your environment variables in your backend project:
Create a .env file in your backend project (NOT in your React Native app):
ORGA_API_KEY=your_orga_api_key_here
Your React Native app should only contain the backend URL:
# In your React Native app's .env
API_URL=https://your-backend-url.com
Never store the ORGA_API_KEY in your mobile app's environment variables. It should always be kept secure on the server side.
// Example using Express
import express, { Request, Response } from 'express';
import cors from 'cors';
// Note: RTCIceServer is available in modern browsers and Node.js environments
// If you get type errors, you may need to install @types/webrtc or define the type:
// interface RTCIceServer { urls: string | string[]; username?: string; credential?: string; }
// Define types for OrgaAI API responses
interface OrgaEphemeralTokenResponse {
ephemeral_token: string;
}
interface OrgaIceConfigResponse {
iceServers: RTCIceServer[];
}
interface OrgaEphemeralResponse {
ephemeralToken: string;
iceServers: RTCIceServer[];
}
// Extend Express Request to include user (if using authentication)
interface AuthenticatedRequest extends Request {
user?: {
id: string;
email: string;
};
}
const app = express();
app.use(cors()); // Configure appropriately for production
// Add your authentication middleware
app.use(authMiddleware);
const ORGA_API_KEY = process.env.ORGA_API_KEY;
app.get('/api/orga-client-secrets', async (req: AuthenticatedRequest, res: Response) => {
// Your user authentication/session validation here
const userId = req.user?.id; // Example: Get from your auth system
if (!ORGA_API_KEY) {
return res.status(500).json({ error: 'Server configuration error: missing ORGA_API_KEY' });
}
const userEmail = req.user?.email;
if (!userEmail) {
return res.status(400).json({ error: 'Missing user email (req.user.email). Make sure your auth middleware sets it.' });
}
try {
const ephemeralResponse = await fetch(`https://api.orga-ai.com/v1/realtime/?email=${encodeURIComponent(userEmail)}`, {
method: 'POST',
headers: {
Authorization: `Bearer ${ORGA_API_KEY}`,
},
});
if (!ephemeralResponse.ok) {
throw new Error('Failed to fetch ephemeral token');
}
const ephemeralData = (await ephemeralResponse.json()) as OrgaEphemeralTokenResponse;
const { ephemeral_token } = ephemeralData;
// Fetch ICE servers
const iceResponse = await fetch('https://api.orga-ai.com/v1/realtime/ice-config', {
headers: { Authorization: `Bearer ${ephemeral_token}` },
});
if (!iceResponse.ok) {
throw new Error('Failed to fetch ICE servers');
}
const iceData = (await iceResponse.json()) as OrgaIceConfigResponse;
const { iceServers } = iceData;
const response: OrgaEphemeralResponse = {
ephemeralToken: ephemeral_token,
iceServers,
};
res.json(response);
} catch (error) {
console.error('Error:', error);
res.status(500).json({ error: 'Internal server error' });
}
});
app.listen(5000, () => console.log('Server running on port 5000'));
Security Note: Your backend proxy should:
-
Store the OrgaAI API key securely (use environment variables)
-
Implement proper authentication/authorization
-
Add rate limiting and request validation
-
Use HTTPS in production
-
Configure CORS appropriately
Initialize the SDK
Layout provider
// app/_layout.tsx
import { OrgaAI, OrgaAIProvider } from '@orga-ai/sdk-react-native';
OrgaAI.init({
logLevel: 'debug',
fetchSessionConfig: async () => {
const response = await fetch('/api/orga-client-secrets'); //Expo API route
//const response = await fetch('https://your_backend_url/api/orga-client-secrets');
const { ephemeralToken, iceServers } = await response.json();
return { ephemeralToken, iceServers };
},
// OR use sessionConfigEndpoint which points directly to your backend.
// Useful if you don't need any custom implementation.
// sessionConfigEndpoint: 'https://<url>/api/orga-client-secrets',
model: 'orga-1-beta',
voice: 'alloy',
});
export default function RootLayout() {
return (
<OrgaAIProvider>
<Stack />
</OrgaAIProvider>
);
}
Main Screen
// app/index.tsx
import { StyleSheet, Text, View } from "react-native";
import {
OrgaAICameraView,
OrgaAIControls,
useOrgaAI
} from "@orga-ai/sdk-react-native";
export default function HomeScreen() {
const {
userVideoStream,
connectionState,
isMicOn,
isCameraOn,
startSession,
endSession,
toggleCamera,
toggleMic,
flipCamera,
} = useOrgaAI();
const handleStart = async () => {
await startSession({
onSessionConnected: () => {
console.log("Connected!");
},
});
};
return (
<View style={styles.container}>
<OrgaAICameraView
streamURL={userVideoStream ? userVideoStream.toURL() : undefined}
containerStyle={styles.cameraViewContainer}
style={{ width: "100%", height: "100%" }}
>
<OrgaAIControls
connectionState={connectionState}
isCameraOn={isCameraOn}
isMicOn={isMicOn}
onStartSession={startSession}
onEndSession={endSession}
onToggleCamera={toggleCamera}
onToggleMic={toggleMic}
onFlipCamera={flipCamera}
/>
</OrgaAICameraView>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#1e293b",
},
cameraViewContainer: {
width: "100%",
height: "100%",
},
placeholder: {
flex: 1,
justifyContent: "center",
alignItems: "center",
},
placeholderText: {
color: "white",
fontSize: 16,
marginTop: 12,
},
});
Troubleshooting
ConfigurationError: OrgaAI must be initialized before use
Ensure that Orga.init is setup and has all of it required properties.
OrgaAI.init({
logLevel: 'debug',
fetchSessionConfig: async () => {
const response = await fetch('/api/orga-client-secrets');
const { ephemeralToken, iceServers } = await response.json();
return { ephemeralToken, iceServers };
}
});
Error: useOrgaAI must be used within an OrgaAIProvider
Wrap your app with the OrgaAIProvider
export default function RootLayout() {
return (
<OrgaAIProvider>
<Stack />
</OrgaAIProvider>
);
}
Invariant Violation: new NativeEventEmitter() requires a non-null argument
Be sure both peer dependencies react-native-webrtc and react-native-incallmanager are installed.
After these are install make sure you’ve created created a new development build.
npx expo prebuild
eas build --platform all --profile development