This package lets you start Vapi calls directly in your React Native app.
β οΈ Important Notes- π Prerequisites
- π§ Installation
- π Quick Start
- π§ Advanced Usage
- π Troubleshooting
- π Expo Integration
- π API Reference
- π€ Contributing
- π License
- π Support
- This guide is for bare React Native projects. If you use expo build, skip to the Expo Integration
- Requires React Native 0.60+ for autolinking support
- Not compatible with Expo Go - requires custom native code
- Not compatible with TurboModules - requires
newArchEnabled=falseinandroid/gradle.properties
- React Native 0.60+
- Node.js 20+
- React Native CLI or @react-native-community/cli
- Xcode 14+ (for iOS development)
- Android Studio (for Android development)
- CocoaPods (for iOS dependencies)
- Minimum iOS version: 12.0
- Screen sharing: Requires iOS 14.0+
- Minimum SDK: 24
newArchEnabled in your android/gradle.properties file.
Install @vapi-ai/react-native along with its peer dependencies:
# Install main dependencies
npm install @vapi-ai/react-native @daily-co/react-native-daily-js @react-native-async-storage/async-storage react-native-background-timer react-native-get-random-values
# Install exact WebRTC version (important for compatibility)
npm install --save-exact @daily-co/react-native-webrtc@118.0.3-daily.4- Update the
platformin yourPodfile, since@daily-co/react-native-webrtconly works on iOS 12 and above:
platform :ios, '12.0'Note: If you wish to send screen share from iOS, it only works on iOS 14 and above. In this case, use iOS 14.0 instead of iOS 12.0.
- Install CocoaPods dependencies:
npx pod-install- Configure Info.plist (required to prevent crashes):
Add these keys to your ios/YourApp/Info.plist:
| Key | Type | Value |
|---|---|---|
NSCameraUsageDescription |
String | "This app needs camera access for voice calls" |
NSMicrophoneUsageDescription |
String | "This app needs microphone access for voice calls" |
UIBackgroundModes |
Array | Item 0: voip |
UIBackgroundModes is handled slightly differently and will resolve to an array. For its first item, specify the value voip. This ensures that audio will continue uninterrupted when your app is sent to the background.
To add the new rows through Xcode, open the Info.plist and add the following three rows:
| Key | Type | Value |
|---|---|---|
| Privacy - Camera Usage Description | String | "Vapi Playground needs camera access to work" |
| Privacy - Microphone Usage Description | String | "Vapi Playground needs microphone access to work" |
| Required background modes | Array | 1 item |
| ---> Item 0 | String | "App provides Voice over IP services" |
If you view the raw file contents of Info.plist, it should look like this:
<dict>
...
<key>NSCameraUsageDescription</key>
<string>Vapi Playground needs camera access to work</string>
<key>NSMicrophoneUsageDescription</key>
<string>Vapi Playground needs microphone access to work</string>
<key>UIBackgroundModes</key>
<array>
<string>voip</string>
</array>
</dict>
- Update AndroidManifest.xml - Add permissions:
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>- Update build.gradle - Set minimum SDK in your top-level
build.gradlefile:
minSdkVersion = 24newArchEnabled=false(If you run into any issues, refer to Github issues like these, or the react-native-webrtc installation docs, which walk you through a more complicated process. The simpler process laid out above seems to work in a vanilla modern React Native CLI-based setup).
import Vapi from '@vapi-ai/react-native';
// Initialize with your API key
const vapi = new Vapi('your-vapi-api-key');vapi.on('call-start', () => {
console.log('Call started');
});
vapi.on('call-end', () => {
console.log('Call ended');
});
vapi.on('volume-level', (volume) => {
console.log('Volume level:', volume);
});
vapi.on('error', (error) => {
console.error('Vapi error:', error);
});try {
await vapi.start({
model: {
provider: 'openai',
model: 'gpt-4o',
messages: [
{
role: 'system',
content: 'You are a helpful AI assistant.',
},
],
},
voice: {
provider: '11labs',
voiceId: 'pNInz6obpgDQGcFmaJgB',
},
firstMessage: 'Hello! How can I help you today?',
});
} catch (error) {
console.error('Failed to start call:', error);
}// Mute/unmute
vapi.setMuted(true);
// Send a message
vapi.send({
type: 'add-message',
message: {
role: 'user',
content: 'Hello from React Native!',
},
});
// End the call
vapi.stop();// Get available audio devices
const devices = vapi.getAudioDevices();
console.log('Available devices:', devices);
// Set specific audio device
vapi.setAudioDevice(deviceId);
// Get current device
const currentDevice = vapi.getCurrentAudioDevice();vapi.on('error', (error) => {
if (error.code === 'PERMISSION_DENIED') {
// Handle permission errors
Alert.alert('Permission Required', 'Please grant microphone and camera permissions');
} else if (error.code === 'NETWORK_ERROR') {
// Handle network errors
Alert.alert('Network Error', 'Please check your internet connection');
}
});- Ensure you've added the required permissions to Info.plist/AndroidManifest.xml
- Request permissions at runtime on Android
# If you see version conflicts, use the exact version:
npm install --save-exact @daily-co/react-native-webrtc@118.0.3-daily.3# Clean and reinstall
cd ios && rm -rf Pods Podfile.lock && pod install && cd ..# Reset Metro cache
npx react-native start --reset-cache# Disable TurboModules
cd android && echo 'newArchEnabled=false' >> gradle.properties && cd ..# Clean iOS build
cd ios && xcodebuild clean && cd ..
# Clean Android build
cd android && ./gradlew clean && cd ..
# Reinstall dependencies
rm -rf node_modules && npm cache verify && npm installWarning: This SDK cannot be used with Expo Go. Use Expo Development Build or EAS Build.
- Install dependencies:
npx expo install @vapi-ai/react-native @daily-co/react-native-daily-js @react-native-async-storage/async-storage react-native-background-timer react-native-get-random-values
npm install --save-exact @daily-co/react-native-webrtc@118.0.3-daily.4- Update app.json:
{
"expo": {
"ios": {
"supportsTablet": true,
"bundleIdentifier": "com.anonymous.ReactNativeWithExpo52",
"infoPlist": {
"NSCameraUsageDescription": "Vapi Playground needs camera access to work",
"NSMicrophoneUsageDescription": "Vapi Playground needs microphone access to work",
"UIBackgroundModes": ["voip"]
}
},
"android": {
"permissions": [
"android.permission.RECORD_AUDIO",
"android.permission.MODIFY_AUDIO_SETTINGS",
"android.permission.INTERNET",
"android.permission.ACCESS_NETWORK_STATE",
"android.permission.CAMERA",
"android.permission.SYSTEM_ALERT_WINDOW",
"android.permission.WAKE_LOCK",
"android.permission.BLUETOOTH",
"android.permission.FOREGROUND_SERVICE",
"android.permission.FOREGROUND_SERVICE_CAMERA",
"android.permission.FOREGROUND_SERVICE_MICROPHONE",
"android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION",
"android.permission.POST_NOTIFICATIONS"
],
},
"plugins": [
"@config-plugins/react-native-webrtc",
"@daily-co/config-plugin-rn-daily-js",
[
"expo-build-properties",
{
"android": {
"minSdkVersion": 24
},
"ios": {
"deploymentTarget": "15.1"
}
}
]
]
}
}- Prebuild and run:
npx expo prebuild
npx expo run:ios # or run:androidnew Vapi(apiKey: string, apiBaseUrl?: string)start(assistant, overrides?)- Start a voice callstop()- End the current callsetMuted(muted: boolean)- Mute/unmute microphoneisMuted()- Check if currently mutedsend(message)- Send a message during callgetAudioDevices()- Get available audio devicessetAudioDevice(deviceId)- Set audio devicegetCurrentAudioDevice()- Get current audio device
call-start- Call has startedcall-end- Call has endedvolume-level- Volume level changedspeech-start- Speech detection startedspeech-end- Speech detection endedmessage- Received messageerror- Error occurred
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests
- Submit a pull request
MIT License Copyright (c) 2023 Vapi Labs Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- Documentation: Vapi Docs
- Issues: GitHub Issues
- Discord: Vapi Community