React Native WebRTC Module
react-native-webrtc provides a comprehensive WebRTC implementation for React Native applications across Android, iOS, and tvOS. The library is currently stable at version 124.0.7 and follows a rapid release cadence, frequently updating to new WebRTC M-releases (e.g., M124). Key features include support for audio/video communication, data channels, and screen capture. A significant differentiator is its exclusive adoption of the Unified Plan as of version 106.0.0, requiring users of older Plan B to migrate or remain on previous releases. It also supports Simulcast since version 111.0.0 with software encode/decode factories enabled by default. While not officially supporting macOS or Windows, it offers a web shim for react-native-web and can be integrated into Expo projects via expo-dev-client and config plugins.
Common errors
-
Error: Permission denied
cause The application lacks necessary camera or microphone permissions for Android or iOS.fixOn Android, request `PermissionsAndroid.PERMISSIONS.CAMERA` and `PermissionsAndroid.PERMISSIONS.RECORD_AUDIO`. On iOS, ensure `NSCameraUsageDescription` and `NSMicrophoneUsageDescription` are present in `Info.plist`. -
TypeError: Cannot read property 'getUserMedia' of undefined
cause The `mediaDevices` object was not correctly imported or the native module for WebRTC is not properly linked/initialized, preventing access to media devices.fixEnsure `import { mediaDevices } from 'react-native-webrtc';` is present. Verify that you have run `npx react-native link` (if applicable) and followed all platform-specific native installation steps. -
Invariant Violation: requireNativeComponent: 'RTCVideoView' was not found in the UIManager.
cause The native component `RTCView` (internally `RTCVideoView` in some contexts) is not correctly linked or registered with the React Native bridge.fixConfirm that you have completed all native installation steps for both Android and iOS, including running `pod install` for iOS and rebuilding your Android project after installing the package.
Warnings
- breaking As of version 106.0.0, 'react-native-webrtc' exclusively supports the Unified Plan. Applications relying on the older Plan B must either migrate to Unified Plan or remain on a version prior to 106.0.0.
- breaking UVC camera support for Android was explicitly dropped in version 118.0.5. Devices using UVC cameras will no longer be compatible.
- gotcha The `minSdkVersion` set by your app may conflict with the library's internal `minSdkVersion` handling on Android, potentially leading to build issues or unexpected behavior. Version 124.0.5 includes changes to address this by not using the app's `minSdkVersion`.
- gotcha For iOS compatibility with React Native versions 0.73 and above, you must use `react-native-webrtc` version 124.0.3 or higher. Older versions may lead to build errors or runtime instability.
- gotcha As a native module, `react-native-webrtc` requires proper linking of native components (e.g., for `RTCView`) on bare React Native projects. Skipping this step often results in runtime errors.
Install
-
npm install react-native-webrtc -
yarn add react-native-webrtc -
pnpm add react-native-webrtc
Imports
- RTCPeerConnection
const RTCPeerConnection = require('react-native-webrtc').RTCPeerConnection;import { RTCPeerConnection } from 'react-native-webrtc'; - mediaDevices
import mediaDevices from 'react-native-webrtc';
import { mediaDevices } from 'react-native-webrtc'; - RTCView
import RTCVideoView from 'react-native-webrtc';
import { RTCView } from 'react-native-webrtc';
Quickstart
import React, { useEffect, useRef, useState } from 'react';
import { View, Text, Button, Platform, PermissionsAndroid, Alert } from 'react-native';
import {
RTCPeerConnection,
RTCIceCandidate,
RTCSessionDescription,
RTCView,
mediaDevices,
} from 'react-native-webrtc';
const configuration = { iceServers: [{ url: 'stun:stun.l.google.com:19302' }] };
export default function App() {
const [localStream, setLocalStream] = useState<any>(null);
const pc = useRef<RTCPeerConnection | null>(null);
useEffect(() => {
(async () => {
if (Platform.OS === 'android') {
await PermissionsAndroid.requestMultiple([
PermissionsAndroid.PERMISSIONS.CAMERA,
PermissionsAndroid.PERMISSIONS.RECORD_AUDIO,
]);
}
try {
const stream = await mediaDevices.getUserMedia({
audio: true,
video: {
mandatory: {
minWidth: '500',
minHeight: '300',
minFrameRate: '30',
},
facingMode: 'user',
},
});
setLocalStream(stream);
pc.current = new RTCPeerConnection(configuration);
pc.current.addStream(stream);
pc.current.onicecandidate = (event) => {
if (event.candidate) {
console.log('ICE Candidate:', event.candidate);
// In a real app, you would send this candidate to the remote peer
}
};
const offer = await pc.current.createOffer();
await pc.current.setLocalDescription(offer);
console.log('Local Offer:', offer.sdp);
// In a real app, you would send this offer to the remote peer
} catch (err: any) {
Alert.alert('Media Error', err.message);
}
})();
return () => {
if (localStream) {
localStream.release();
}
if (pc.current) {
pc.current.close();
}
};
}, []);
if (!localStream) {
return <Text>Loading local media...</Text>;
}
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Local Stream:</Text>
<RTCView streamURL={localStream.toURL()} style={{ width: 300, height: 200, backgroundColor: 'black' }} />
<Button title="Start Call (logic incomplete)" onPress={() => Alert.alert('Simulated Call', 'Offer sent (check console)')} />
</View>
);
}