VoltKit RTC
Free account requiredReact Native video calls, voice rooms and chat
Voice calls from ₹39 (≈ $0.41), Full HD video at ₹99 (≈ $1.04) per 1,000 participant-minutes, billed per second.
Put calls, voice rooms and chat in a React Native app with the hooks you know from the VoltKit React SDK and native video views. On Android the SDK runs the call audio on the loudspeaker, the earpiece or a headset, and keeps calls going in the background. It installs beside upstream react-native-webrtc: no fork, and nothing to add to MainApplication.
Your first project starts with 2,500 free participant-minutes, once per account, at any quality.
- Tested on Android, iOS in preview
- The hooks of @voltkit-rtc/react
- Expo development builds
- Billed in rupees
Code
Install, join and show video
Your backend mints a token for the room; the provider joins with it, and the hooks give your screen the room as state. Remote audio plays by itself, with no component to render.
$ npm install @voltkit-rtc/react-native @voltkit-rtc/react @voltkit-rtc/client react-native-webrtcfunction Call({ onRetry }: { onRetry: () => void }) {
const { state, info, error, leave } = useRoom();
const local = useLocalMedia();
const audio = useAudioOutput();
const videos = useRemoteTracks({ kind: "video" });
const [problem, setProblem] = useState<string | null>(null);
const report = (err: Error) => setProblem(err.message);
// … the joining and could-not-join screens
const canPublish = info?.role === "host" || info?.role === "cohost";
const camera = local.stream?.getVideoTracks()[0];
return (
<View style={styles.screen}>
{state === "reconnecting" && <Text>Reconnecting…</Text>}
{problem && <Text>{problem}</Text>}
<View style={styles.tiles}>
{camera && <VideoTrack track={camera} mirror={local.facingMode === "user"} style={styles.tile} />}
{videos.map((t) => (
<VideoTrack key={t.producerId} track={t.track} producerId={t.producerId} objectFit="cover" style={styles.tile} />
))}
</View>
<View style={styles.controls}>
{canPublish && !local.stream && (
<Button title="Start camera and microphone" onPress={() => local.publish().catch(report)} />
)}
{/* … mute, camera off, flip and the loudspeaker */}
<Button title="Leave" onPress={leave} />
</View>
</View>
);
}$ npm install @voltkit-rtc/react-native @voltkit-rtc/react @voltkit-rtc/client react-native-webrtcimport { Pressable, Text, View } from "react-native";
import { useAudioOutput } from "@voltkit-rtc/react-native";
const NAMES: Record<string, string> = { speaker: "Loudspeaker", earpiece: "Phone", wiredHeadset: "Headset", bluetooth: "Bluetooth", usb: "USB" };
export function OutputPicker() {
const audio = useAudioOutput();
if (!audio.supported) return null; // false on iOS (preview) and in the media audio mode
return (
<View>
{audio.outputs.map((device) => (
<Pressable key={device.deviceId} onPress={() => void audio.select(device.deviceId)}>
<Text style={{ fontWeight: device.deviceId === audio.current?.deviceId ? "bold" : "normal" }}>
{device.label || NAMES[device.type ?? ""] || device.deviceId}
</Text>
</Pressable>
))}
</View>
);
}$ npm install @voltkit-rtc/react-native @voltkit-rtc/react @voltkit-rtc/client react-native-webrtcimport type { ReactNode } from "react";
import { VoltkitProvider } from "@voltkit-rtc/react-native";
export function CallProvider({ wsUrl, token, children }: { wsUrl: string; token: string; children: ReactNode }) {
return (
<VoltkitProvider
wsUrl={wsUrl}
token={token}
callService={{ title: "Call with Asha", text: "Tap to return to the call", leaveLabel: "Hang up" }}
>
{children}
</VoltkitProvider>
);
}$ npm install @voltkit-rtc/serverconst express = require("express");
const { StreamClient } = require("@voltkit-rtc/server");
const rtc = new StreamClient({ baseUrl: process.env.VOLTKIT_RTC_URL, apiKey: process.env.VOLTKIT_RTC_SECRET });
const app = express();
app.use(express.json());
// POST /calls/:callId/token (your auth middleware sets req.user)
app.post("/calls/:callId/token", requireUser, async (req, res) => {
const call = await db.calls.find(req.params.callId);
if (!call || ![call.callerId, call.calleeId].includes(req.user.id)) return res.sendStatus(404);
await rtc.ensureRoom({ roomId: call.id, hostIdentity: call.callerId });
const role = req.user.id === call.callerId ? "host" : "cohost";
const { token, wsUrl, expiresAt } = await rtc.createToken({ roomId: call.id, identity: req.user.id, role });
if (!token || !wsUrl) return res.status(502).json({ error: "The RTC service returned an incomplete token; try again" });
res.set("Cache-Control", "no-store").json({ token, wsUrl, expiresAt });
});VoltkitProvider, useRoom, useLocalMedia and useRemoteTracks are the names of the React SDK, so a call screen written for the web moves over by changing the import and the views. useLocalMedia() adds switchCamera(), and VideoTrack draws with react-native-webrtc's own view.
Every export, prop and error code: the React Native SDK reference. The endpoint in other languages: issue tokens from your backend.
Built in
What the SDK handles, and what your app builds
The SDK carries the call; the screens, the sign-in and the rules about who calls whom are your app's.
What the SDK does
- Call audio on Android: a Bluetooth headset wins, then a wired or USB one, then the loudspeaker or the earpiece as you choose (audio routing)
- Camera and microphone permissions before any device opens; a refusal arrives as media-unavailable, saying which permission
- Reconnects after a network change or a dropped connection: the hooks show reconnecting without unmounting your screen
- Adaptive video: a VideoTrack with a producerId receives the size it is shown at, and pauses while it is hidden
- Roles signed into each token and enforced by the service, with raise hand, seats, kick and forced mute
- Chat on the same connection (in-app chat), and screen sharing through Android's own consent screen
What your app builds
- Your token endpoint and your sign-in
- The call screen, its layout and your navigation
- Ringing and push notifications for incoming calls
- The foreground service declaration for your app in Play Console
- Coins, payments and anything users buy
Background
Calls that keep going in the background on Android
Android silences a background app's microphone and can cut its network a few seconds after the app leaves the screen. The SDK's call service is a foreground service that keeps the call alive: the provider starts it when the call joins, while your app is on screen, and stops it when the call ends.
- Declared onceThe Expo config plugin declares the service, or a manifest block does in a bare React Native app. Without it, a call carries on only while the app is on screen.
- A notification with LeaveAn ongoing notification shows while the call runs (on Android 13 and later, once the user allows notifications; the service runs either way). Tapping it opens your app, and its Leave button ends the call.
- Microphone on, camera pausedThe microphone, the network and the SDK's timers keep running with the screen off. The camera pauses in the background unless you ask otherwise.
- Google PlayApps on Google Play declare the foreground service types the service uses in Play Console, under App content.
The service, its notification and the Play declaration: calls in the background.
Voice
Voice calls and voice chat rooms
The same SDK makes voice apps: a room with the microphone alone, the call audio on the earpiece or the loudspeaker, and roles from your backend.

A one-to-one voice call is a room with two people who publish only their microphones, and it can start on the earpiece, as a phone call does: one-to-one voice calls. An audio room adds a stage: listeners join as viewers, raise a hand, and the host brings them on stage, with seats your app lays out (group audio rooms, voice chat rooms).
Live rooms are the same rooms with cameras: hosts and guests on camera, and the audience in the room as viewers. The names are those of the browser, Flutter and Android SDKs, and chat travels on the same connection (chat docs).
Expo
Expo: development builds, not Expo Go
Expo Go cannot load react-native-webrtc's native code, so calls run in a development build: your own build of the app, made from the same project.
- 01InstallAdd the SDK, its peers, react-native-webrtc and expo-dev-client to the project with npx expo install.
- 02Add the pluginPut @voltkit-rtc/react-native in the plugins of app.json. It writes the permissions, the call service and the settings the SDK reads at startup.
- 03BuildRun npx expo run:android, or make an EAS development build, then start the app from it.
Opened in Expo Go, the SDK stops with an error that says it needs a development build, rather than failing later. The plugin's options, EAS profiles and permissions: React Native with Expo.
Migrate
Coming from react-native-agora
The concepts carry over: a channel is a room, and the token your backend mints says who joins which room with which role.
| react-native-agora | @voltkit-rtc/react-native |
|---|---|
| createAgoraRtcEngine() and initialize() | <VoltkitProvider wsUrl={wsUrl} token={token}> |
| joinChannel(token, channelId, uid, options) | The provider joins with the token your backend minted: the room, the identity and the role are in it |
| RtcSurfaceView | <VideoTrack track={track} /> |
| muteLocalAudioStream(true) | useLocalMedia().setMicEnabled(false) |
| setEnableSpeakerphone(true) | setSpeakerphoneOn(true) |
| renewToken(token) | Refreshed by the service during the call; a new token prop hands one over |
| leaveChannel() and release() | useRoom().leave() |
Agora's names as its React Native API reference lists them, read 2026-10-25. The whole table: migrate from Agora. Prices side by side: Agora alternative.
Pricing
What a call costs
One rate at a time per person, for the media they actually send or receive; video already includes HD audio. The SDK has no price of its own.
- Standard VoiceUp to 64 kbps₹39 (≈ $0.41) per 1,000 participant-minutes
- HD VoiceUp to 128 kbps₹49 (≈ $0.52) per 1,000 participant-minutes
- Full HD Video + HD AudioUp to 1080p/30, HD audio included₹99 (≈ $1.04) per 1,000 participant-minutes
2 people × 10 minutes = 20 participant-minutes
20 participant-minutes × 99 ÷ 1,000 = 1.98 credits, ₹1.98 (≈ $0.02) at today's rate
Full HD Video + HD Audio: 99 credits per 1,000 participant-minutes. Billed per second, so a 7½-minute call costs 7½ minutes.
2 people × 10 minutes = 20 participant-minutes
20 participant-minutes × 39 ÷ 1,000 = 0.78 credits, ₹0.78 (≈ $0.01) at today's rate
Standard Voice: 39 credits per 1,000 participant-minutes. Billed per second, so a 7½-minute call costs 7½ minutes.
Prices are in Indian rupees; dollar figures are approximate, at ₹95 per US dollar on 24 October 2026, for orientation only. You are billed in rupees.
UPI, GST and a calculator for your own sessions: pricing in India. Every rate, including the 60 fps upgrades: pricing.
SDKs
SDKs for your apps and your backend
React Native for Android apps, with iOS in preview; Flutter covers Android and iOS; the Android SDK is native Kotlin. The native iOS (Swift) SDK is in preview.
Your stack. Your next live app.JavaScript (browser)
JavaScript SDK guide$ npm install @voltkit-rtc/clientReact (browser)
React SDK guide$ npm install @voltkit-rtc/react @voltkit-rtc/clientReact Native (Android; iOS preview)
React Native SDK guide$ npm install @voltkit-rtc/react-native @voltkit-rtc/react @voltkit-rtc/client react-native-webrtcNode.js (server)
Node.js SDK guide$ npm install @voltkit-rtc/serverPython (server)
Python SDK guide$ pip install voltkit-rtc-serverGo (server)
Go SDK guide$ go get github.com/voltkit-rtc/voltkit-rtc-server-goPHP (server)
PHP SDK guide$ composer require voltkit/rtc-serverJava (server, Spring Boot)
Java SDK guideimplementation("in.voltkit:voltkit-rtc-server:0.1.1")Flutter (iOS and Android apps)
Flutter SDK guide$ flutter pub add voltkit_rtcAndroid (Kotlin apps)
Android SDK guideimplementation("in.voltkit:voltkit-rtc:0.9.10")Native iOS (Swift)
In preview, not released yet. The Flutter SDK covers iOS apps today; for early access, email contact@voltkit.in.
iOS preview notes
Limits
What it does not do yet
Version 0.1.0 is the first release. These are the edges to know before you plan a release on it.
- iOS is in preview: VoltKit has not compiled or run it on an iPhone, and audio routing, the call service and screen sharing are Android only.
- No Expo Go: calls need a development build.
- No ringing: no CallKit or ConnectionService. Your app rings the other person through its own push channel.
- No virtual backgrounds, beauty filters or noise-suppression processors.
- No in-app music: publishMusic is not available in React Native.
- No react-native-web build: on the web, use @voltkit-rtc/react.
What was tested, on which devices and versions: versions and compatibility.
More
Related
- Video calling in React NativeA step-by-step guide: the token endpoint, permissions, video tiles, the loudspeaker, calls in the background and reconnects.Read the guide
- Voice chat roomsAudio rooms with a stage, seats and raise hand, with chat beside them.Voice rooms
- Dating and friendship appsA room per match, voice first, video when both agree, call records by webhook.Calls for dating apps
The React Native SDK: questions
Does VoltKit have a React Native SDK?
Yes: @voltkit-rtc/react-native 0.1.0, on npm and MIT licensed. It runs the client of the browser SDK, @voltkit-rtc/client, on upstream react-native-webrtc, with the hooks of @voltkit-rtc/react, native video views, and audio routing and background calls on Android. It is tested on Android; iOS is in preview.
Does it work with Expo?
Yes, in a development build, not in Expo Go: Expo Go cannot load react-native-webrtc's native code. Add the package's config plugin to app.json and build with npx expo run:android or an EAS development build. The plugin writes the permissions, the call service and the settings the SDK reads at startup, so you edit no native file.
Does it work on iOS?
iOS is in preview. The package's JavaScript is written for react-native-webrtc's own iOS code, but VoltKit has not compiled or run it on an iPhone, and audio routing, the call service and screen sharing are Android only. Flutter apps run on iOS today with voltkit_rtc; to try the React Native SDK on iOS with us, email contact@voltkit.in.
How do I route audio to the speaker, earpiece or a Bluetooth headset?
On Android the SDK runs the call audio while a call is connected: a Bluetooth headset wins, then a wired or USB one, then the loudspeaker or the earpiece as you choose. setSpeakerphoneOn(true) is the loudspeaker button, and useAudioOutput() lists the outputs and the one in use, for a picker; an output picked by hand wins over a headset. Calls start on the loudspeaker; for a voice call held to the ear, pass audio={{ speakerphone: false }} to the provider. No Bluetooth permission is needed.
Does a call keep going when the app is in the background?
On Android, yes, with the SDK's call service: a foreground service that the Expo plugin declares, or a manifest block in a bare React Native app. The provider starts it when the call joins, while the app is on screen, and it keeps the microphone, the network and the SDK's timers running with the screen off, behind an ongoing notification with a Leave button (on Android 13 and later, once the user allows notifications; the service runs either way). The camera pauses in the background unless you ask otherwise. Apps on Google Play declare the service's foreground service types in Play Console.
Where does the token come from?
From your backend. It checks who the user is, decides the room and the role, and returns a short-lived token and the wsUrl, minted with one of the server SDKs, for Node.js, Python, Go, PHP and Java, or with the REST API. The app asks for them right before joining; the API secret never goes into the app.
Can I move from react-native-agora?
Yes. The main calls map almost one to one: a channel is a room, the token your backend mints carries the room and the user's role, RtcSurfaceView becomes VideoTrack, muteLocalAudioStream becomes setMicEnabled, setEnableSpeakerphone becomes setSpeakerphoneOn, and leaveChannel becomes leave. The migration guide's React Native section has the whole table.
What does a 1:1 video call cost?
A 10-minute 1:1 video call is 20 participant-minutes: at Full HD that is 1.98 credits, ₹1.98 (≈ $0.02) at today's rate, charged to your wallet per second. Each person is billed at the rate of the media they send or receive, so a call without video is billed at the voice rate.
Add calls to your React Native app
Create a free account, make an RTC project, and follow the React Native guide to put two phones in one call.
Talk to us:contact@voltkit.inWhatsApp
