React Native WebRTC Module

124.0.7 · active · verified Sun Apr 19

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

Warnings

Install

Imports

Quickstart

Demonstrates how to obtain local audio/video media, initialize an RTCPeerConnection, and display the local video stream using RTCView, including basic Android permission handling.

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>
  );
}

view raw JSON →