Quick start
Expo (recommended)
Section titled “Expo (recommended)”WebRTC is a native module, so use a development build; Expo Go cannot place calls. Preview mode still works in Expo Go and on the web.
npx jsr add @azeer-ui-widget/react-native-phonenpx expo install react-native-webrtc @config-plugins/react-native-webrtc react-native-svg react-native-safe-area-context{ "expo": { "ios": { "infoPlist": { "UIBackgroundModes": ["audio", "voip"] } }, "android": { "permissions": ["RECORD_AUDIO", "MODIFY_AUDIO_SETTINGS"] }, "plugins": [ ["@config-plugins/react-native-webrtc", { "microphonePermission": "Calls need your microphone so the other person can hear you." }] ] }}npx expo run:android # or npx expo run:iosPair react-native-webrtc and the config plugin versions as listed in the plugin’s compatibility table.
Bare React Native
Section titled “Bare React Native”npx jsr add @azeer-ui-widget/react-native-phonenpm install react-native-webrtc react-native-svgcd ios && pod installAdd NSMicrophoneUsageDescription to Info.plist, and RECORD_AUDIO plus MODIFY_AUDIO_SETTINGS to AndroidManifest.xml. The phone requests the permission at runtime the first time someone dials or answers.
Your first phone
Section titled “Your first phone”import { useMemo } from "react";import { SafeAreaProvider, useSafeAreaInsets } from "react-native-safe-area-context";import { SipPhone, type SipConfig } from "@azeer-ui-widget/react-native-phone";
function Phone({ password }: { password: string }) { // Keep the config stable: a new object intentionally re-registers. const config = useMemo<SipConfig>( () => ({ websocketUrl: "wss://pbx.example.com:8089/ws", uri: "sip:1001@pbx.example.com", authorizationUsername: "1001", password, }), [password], ); return ( <SipPhone config={config} autoConnect variant="screen" insets={useSafeAreaInsets()} theme={{ appearance: "system" }} onIncomingCall={(call) => console.info("Incoming", call.caller.number)} onDisconnected={(call) => console.info("Ended", call.endReason)} /> );}
export default function App() { return ( <SafeAreaProvider> <Phone password={/* from your sign-in flow */ ""} /> </SafeAreaProvider> );}Never hardcode SIP passwords or put them in EXPO_PUBLIC_* variables: those are bundled into the app. Fetch credentials after sign-in and keep them in memory.
Try it without an account
Section titled “Try it without an account”const preview = { enabled: true as const };<SipPhone preview={preview} variant="screen" />;Preview simulates registration, ringing, answer, hold, transfer, and audio activity with no network or microphone. Use client.simulateIncoming() to rehearse incoming calls. It runs in Expo Go, on devices, and in the web playground.