video sdk logo

Login

React Native Live Streaming Tutorial

Ship interactive live streams to iOS and Android from one React Native codebase. Hosts broadcast in low latency, viewers watch the HLS feed in a native player, and co-hosts can be promoted without leaving the stream.
React Native Live Streaming Tutorial

Trusted by 300+ global business & tech leaders

Go Live from Your React Native App with HLS

Learn how to add HLS live streaming to a React Native app using the VideoSDK React Native SDK. This tutorial covers starting and stopping a stream, host and viewer modes, and HLS playback in a native mobile player.


Info: For low-latency interactive live streaming (under 100ms), follow this documentation.

Prerequisites

Before proceeding, ensure that your development environment meets the following requirements:

  • Video SDK Developer Account (Not having one, follow Video SDK Dashboard)
  • Basic understanding of React Native
  • Node.js >= 22.11.0
  • NPM v10+ (comes installed with newer Node versions)
  • Android Studio or Xcode installed

Important: One should have a VideoSDK account to generate token. Visit VideoSDK dashboard to generate token

App Architecture

The App will contain the following screens:

  1. Join Screen : This screen allows the SPEAKER to create a studio or join a predefined studio, and SIGNALLING_ONLY to join a predefined studio.

  2. Speaker Screen : This screen contains the list of speakers and studio controls, such as enabling/disabling the microphone and camera, and leaving the studio.

  3. Viewer Screen : This screen includes a live stream player where viewers can watch the stream.

VideoSDK React Native ILS app architecture showing the join screen, speaker screen and viewer screen

Getting Started with the Code!

Create App

Create a new React Native App using the below command.

Terminal
1npx @react-native-community/cli init AppName
2

For React Native setup, you can follow the Official Documentation.

Install VideoSDK and Dependencies

Install the VideoSDK along with @react-native-clipboard/clipboard (used to copy the meeting id) and react-native-safe-area-context (used to render the app within the device's safe area). Ensure that you are in your project directory before running this command.

NPM
1npm install "@videosdk.live/react-native-sdk"  "@videosdk.live/react-native-incallmanager" "@react-native-clipboard/clipboard" "react-native-safe-area-context"
2
Yarn
1yarn add "@videosdk.live/react-native-sdk"  "@videosdk.live/react-native-incallmanager" "@react-native-clipboard/clipboard" "react-native-safe-area-context"
2

Project Structure

Directory Structure
1  root
2   ├── node_modules
3   ├── android
4   ├── ios
5   ├── App.js
6   ├── api.js
7   ├── index.js
8

Project Configuration

Android Setup

1. Add the required permissions in the AndroidManifest.xml file.

AndroidManifest.xml
1<manifest
2  xmlns:android="http://schemas.android.com/apk/res/android"
3  package="com.cool.app"
4>
5    <!-- Give all the required permissions to app -->
6    <uses-permission android:name="android.permission.INTERNET" />
7    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
8    <!-- Needed to communicate with already-paired Bluetooth devices. (Legacy up to Android 11) -->
9    <uses-permission
10        android:name="android.permission.BLUETOOTH"
11        android:maxSdkVersion="30" />
12    <uses-permission
13        android:name="android.permission.BLUETOOTH_ADMIN"
14        android:maxSdkVersion="30" />
15
16    <!-- Needed to communicate with already-paired Bluetooth devices. (Android 12 upwards)-->
17    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
18
19    <uses-permission android:name="android.permission.CAMERA" />
20    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
21    <uses-permission android:name="android.permission.RECORD_AUDIO" />
22    <uses-permission android:name="android.permission.WAKE_LOCK" />
23</manifest>
24

2. Link the necessary VideoSDK Dependencies

android/app/build.gradle
1  dependencies {
2   implementation project(':rnwebrtc')
3  }
4
android/settings.gradle
1include ':rnwebrtc'
2project(':rnwebrtc').projectDir = new File(rootProject.projectDir, '../node_modules/@videosdk.live/react-native-webrtc/android')
3
MainApplication.kt
1import live.videosdk.rnwebrtc.WebRTCModulePackage
2
3class MainApplication : Application(), ReactApplication {
4
5  override val reactHost: ReactHost by lazy {
6    getDefaultReactHost(
7      context = applicationContext,
8      packageList =
9        PackageList(this).packages.apply {
10          // Packages that cannot be autolinked yet can be added manually here, for example:
11          // add(MyReactNativePackage())
12          add(WebRTCModulePackage())
13        },
14    )
15  }
16
17  override fun onCreate() {
18    super.onCreate()
19    loadReactNative(this)
20  }
21}
22

Note: This MainApplication.kt matches the template of recent React Native versions — verified against the React Native 0.87 template that npx @react-native-community/cli init currently produces. On an older React Native version, add WebRTCModulePackage() to the package list in your project's existing MainApplication file instead — for example inside getPackages() in the Java template.

3. Include the following line in your proguard-rules.pro file (optional: if you are using Proguard)

android/app/proguard-rules.pro
1-keep class org.webrtc.** { *; }
2
3

4. In your build.gradle file, update the minimum OS/SDK version to 24.

build.gradle
1buildscript {
2  ext {
3      minSdkVersion = 24
4  }
5}
6

iOS Setup

1. IMPORTANT: Ensure that you are using CocoaPods version 1.10 or later

To update CocoaPods, you can reinstall the gem using the following command:

Terminal
1$ sudo gem install cocoapods
2

2. Manually link react-native-incall-manager (if it is not linked automatically).

Select Your_Xcode_Project/TARGETS/BuildSettings, in Header Search Paths, add "$(SRCROOT)/../node_modules/@videosdk.live/react-native-incall-manager/ios/RNInCallManager"

3. Change the path of react-native-webrtc using the following command:

Podfile
1pod 'react-native-webrtc', :path => '../node_modules/@videosdk.live/react-native-webrtc'
2

Note: Your Podfile's default platform :ios, min_ios_version_supported line already satisfies react-native-webrtc's minimum iOS requirement.

4. Install pods.

You need to install the pods by running the following command:

Terminal
1pod install
2

5. Declare permissions in Info.plist :

Add the following lines to your info.plist file located at (project folder/ios/projectname/info.plist):

ios/projectname/info.plist
1<key>NSCameraUsageDescription</key>
2<string>Camera permission description</string>
3<key>NSMicrophoneUsageDescription</key>
4<string>Microphone permission description</string>
5

Register Service

Register VideoSDK services in your root index.js file for the initialization service.

index.js
1import { AppRegistry } from "react-native";
2import App from "./App";
3import { name as appName } from "./app.json";
4import { register } from "@videosdk.live/react-native-sdk";
5
6register();
7
8AppRegistry.registerComponent(appName, () => App);
9

Step 1: Get started with API.js

Prior to moving on, you must create an API request to generate a unique meetingId. You will need an authentication token, which you can create either through the videosdk-rtc-api-server-examples or directly from the VideoSDK Dashboard for developers.

api.js
1// Generate your token at https://app.videosdk.live/api-keys and paste it below.
2export const authToken = "";
3
4// API call to create meeting
5export const createMeeting = async ({ token }) => {
6  try {
7    const res = await fetch(`https://api.videosdk.live/v2/rooms`, {
8      method: "POST",
9      headers: {
10        authorization: `${token}`,
11        "Content-Type": "application/json",
12      },
13      body: JSON.stringify({}),
14    });
15
16    if (!res.ok) {
17      throw new Error(`Failed to create meeting: ${res.status}`);
18    }
19
20    //Destructuring the roomId from the response
21    const { roomId } = await res.json();
22    return roomId;
23  } catch (error) {
24    console.error("createMeeting failed", error);
25    throw error;
26  }
27};
28

Step 2: Wireframe App.js with all the components

To build up wireframe of App.js, you need to use VideoSDK Hooks and Context Providers. VideoSDK provides MeetingProvider, MeetingConsumer, useMeeting and useParticipant hooks.

First you need to understand Context Provider and Consumer. Context is primarily used when some data needs to be accessible by many components at different nesting levels.

  • MeetingProvider: This is the Context Provider. It accepts value config and token as props. The Provider component accepts a value prop to be passed to consuming components that are descendants of this Provider. One Provider can be connected to many consumers. Providers can be nested to override values deeper within the tree.
  • MeetingConsumer: This is the Context Consumer. All consumers that are descendants of a Provider will re-render whenever the Provider’s value prop changes.
  • useMeeting: This is the meeting hook API. It includes all the information related to meeting such as join, leave, toggle mic or webcam etc.
  • useParticipant: This is the participant hook API. It is responsible for handling all the events and props related to one particular participant such as name, webcamStream, micStream etc.

From v1.0.0, all these methods are asynchronous and return a Promise, so await them and handle failures with try / catch. For details, see the Migration Guide.

The Meeting Context provides a way to listen for any changes that occur when a participant joins the meeting or makes modifications to their microphone, camera, and other settings.

Begin by making a few changes to the code in the App.js file.

App.js
1import React, { useState, useMemo, useRef, useEffect } from "react";
2import {
3  TouchableOpacity,
4  Text,
5  TextInput,
6  View,
7  FlatList,
8} from "react-native";
9import {
10  MeetingProvider,
11  useMeeting,
12  useParticipant,
13  MediaStream,
14  RTCView,
15  Constants,
16} from "@videosdk.live/react-native-sdk";
17import Clipboard from "@react-native-clipboard/clipboard";
18import { createMeeting, authToken } from "./api";
19import { SafeAreaProvider, SafeAreaView } from "react-native-safe-area-context";
20
21// Responsible for either scheduling a new meeting or joining an existing one as a host or as a viewer.
22function JoinScreen({ getMeetingAndToken, setMode }) {
23  return null;
24}
25
26// Responsible for managing participant video stream
27function ParticipantView(props) {
28  return null;
29}
30
31// Responsible for managing meeting controls such as toggle mic / webcam and leave
32function Controls() {
33  return null;
34}
35
36// Responsible for Speaker side view, which contains Meeting Controls(toggle mic/webcam & leave) and Participant list
37function SpeakerView() {
38  return null;
39}
40
41// Responsible for Viewer side view, which contains video player for streaming HLS and managing HLS state (HLS_STARTED, HLS_STOPPING, HLS_STARTING, etc.)
42function ViewerView() {
43  return null;
44}
45
46// Responsible for managing two views (Speaker & Viewer) based on provided mode (`SEND_AND_RECV` & `SIGNALLING_ONLY`)
47function Container(props) {
48  return null;
49}
50
51function AppContent() {
52  const [meetingId, setMeetingId] = useState(null);
53
54  //State to handle the mode of the participant i.e. SEND_AND_RECV or SIGNALLING_ONLY
55  const [mode, setMode] = useState("SEND_AND_RECV");
56
57  //Getting MeetingId from the API created earlier
58  const getMeetingAndToken = async (id) => {
59    if (!authToken) {
60      console.error("PLEASE PROVIDE TOKEN IN api.js FROM app.videosdk.live");
61      return;
62    }
63    const meetingId =
64      id == null ? await createMeeting({ token: authToken }) : id;
65    setMeetingId(meetingId);
66  };
67
68  return authToken && meetingId ? (
69    <MeetingProvider
70      config={{
71        meetingId,
72        micEnabled: true,
73        webcamEnabled: true,
74        name: "C.V. Raman",
75        //This will be the mode of the participant SEND_AND_RECV or SIGNALLING_ONLY
76        mode: mode,
77        defaultCamera: "front",
78      }}
79      token={authToken}
80    >
81      <Container />
82    </MeetingProvider>
83  ) : (
84    <JoinScreen getMeetingAndToken={getMeetingAndToken} setMode={setMode} />
85  );
86}
87
88function App() {
89  return (
90    <SafeAreaProvider>
91      <AppContent />
92    </SafeAreaProvider>
93  );
94}
95
96export default App;
97

Step 3: Implement Join Screen

Join screen will work as medium to either schedule a new meeting or to join an existing one as a host or as a viewer.

This functionality will have 3 buttons:

1. Join as Host: When this button is clicked, the person will join the meeting with the entered meetingId as HOST.

2. Join as Viewer: When this button is clicked, the person will join the meeting with the entered meetingId as SIGNALLING_ONLY.

3. Create Studio Room: When this button is clicked, the person will join a new meeting as HOST.

JoinScreen Component
1function JoinScreen({ getMeetingAndToken, setMode }) {
2  const [meetingVal, setMeetingVal] = useState("");
3
4  const JoinButton = ({ value, onPress }) => {
5    return (
6      <TouchableOpacity
7        style={{
8          backgroundColor: "#1178F8",
9          padding: 12,
10          marginVertical: 8,
11          borderRadius: 6,
12        }}
13        onPress={onPress}
14      >
15        <Text style={{ color: "white", alignSelf: "center", fontSize: 18 }}>
16          {value}
17        </Text>
18      </TouchableOpacity>
19    );
20  };
21  return (
22    <SafeAreaView
23      style={{
24        flex: 1,
25        backgroundColor: "black",
26        justifyContent: "center",
27        paddingHorizontal: 6 * 10,
28      }}
29    >
30      <TextInput
31        value={meetingVal}
32        onChangeText={setMeetingVal}
33        placeholder={"XXXX-XXXX-XXXX"}
34        placeholderTextColor={"grey"}
35        style={{
36          padding: 12,
37          borderWidth: 1,
38          borderColor: "white",
39          borderRadius: 6,
40          color: "white",
41          marginBottom: 16,
42        }}
43      />
44      <JoinButton
45        onPress={() => {
46          getMeetingAndToken(meetingVal);
47        }}
48        value={"Join as Host"}
49      />
50      <JoinButton
51        onPress={() => {
52          setMode("SIGNALLING_ONLY");
53          getMeetingAndToken(meetingVal);
54        }}
55        value={"Join as Viewer"}
56      />
57      <Text
58        style={{
59          alignSelf: "center",
60          fontSize: 22,
61          marginVertical: 16,
62          fontStyle: "italic",
63          color: "grey",
64        }}
65      >
66        ---------- OR ----------
67      </Text>
68
69      <JoinButton
70        onPress={() => {
71          getMeetingAndToken();
72        }}
73        value={"Create Studio Room"}
74      />
75    </SafeAreaView>
76  );
77}
78

Output

VideoSDK React Native ILS quickstart join screen with join as host, join as viewer and create studio room buttons

Step 4: Implement Container Component

Next step is to create a container to manage Join screen, SpeakerView and ViewerView components based on the mode.

You need to determine the mode of the localParticipant, if its SEND_AND_RECV, display the SpeakerView component otherwise show the ViewerView component.

Container Component
1function Container() {
2  const { join, localParticipant } = useMeeting({
3    onError: (error) => {
4      console.log(error.message);
5    },
6  });
7
8  return (
9    <View style={{ flex: 1 }}>
10      {localParticipant?.mode == Constants.modes.SEND_AND_RECV ? (
11        <SpeakerView />
12      ) : localParticipant?.mode == Constants.modes.SIGNALLING_ONLY ? (
13        <ViewerView />
14      ) : (
15        <View
16          style={{
17            flex: 1,
18            justifyContent: "center",
19            alignItems: "center",
20            backgroundColor: "black",
21          }}
22        >
23          <Text style={{ fontSize: 20, color: "white" }}>
24            Press Join button to enter studio.
25          </Text>
26          <Button
27            btnStyle={{
28              marginTop: 8,
29              paddingHorizontal: 22,
30              padding: 12,
31              borderWidth: 1,
32              borderColor: "white",
33              borderRadius: 8,
34            }}
35            buttonText={"Join"}
36            onPress={async () => {
37              try {
38                await join();
39              } catch (error) {
40                console.error("Failed to join meeting", error);
41              }
42            }}
43          />
44        </View>
45      )}
46    </View>
47  );
48}
49
50// Common Component which will also be used in Controls Component
51const Button = ({ onPress, buttonText, backgroundColor, btnStyle }) => {
52  return (
53    <TouchableOpacity
54      onPress={onPress}
55      style={{
56        ...btnStyle,
57        backgroundColor: backgroundColor,
58        padding: 10,
59        borderRadius: 8,
60      }}
61    >
62      <Text style={{ color: "white", fontSize: 12 }}>{buttonText}</Text>
63    </TouchableOpacity>
64  );
65};
66

Output

VideoSDK React Native ILS quickstart screen prompting the user to press the join button to enter the studio

Step 5: Implement SpeakerView

Next step is to create SpeakerView and Controls components to manage features such as join, leave, mute and unmute.

  1. You have to retrieve all the participants using the useMeeting hook and filter them based on the mode set to SEND_AND_RECV ensuring that only Speakers are displayed on the screen.
SpeakerView
1function SpeakerView() {
2  // Get the Participant Map and meetingId
3  const { meetingId, participants } = useMeeting({});
4
5  // For getting speaker participant, filter out `SEND_AND_RECV` mode participant
6  const speakers = useMemo(() => {
7    const speakerParticipants = [...participants.values()].filter(
8      (participant) => {
9        return participant.mode == Constants.modes.SEND_AND_RECV;
10      }
11    );
12    return speakerParticipants;
13  }, [participants]);
14
15  return (
16    <SafeAreaView style={{ backgroundColor: "black", flex: 1 }}>
17      {/* Render Header for copy meetingId and leave meeting*/}
18      <HeaderView />
19
20      {/* Render Participant List */}
21      {speakers.length > 0 ? (
22        <FlatList
23          data={speakers}
24          renderItem={({ item }) => {
25            return <ParticipantView participantId={item.id} />;
26          }}
27        />
28      ) : null}
29
30      {/* Render Controls */}
31      <Controls />
32    </SafeAreaView>
33  );
34}
35
36function HeaderView() {
37  const { meetingId, leave } = useMeeting();
38  return (
39    <View
40      style={{
41        flexDirection: "row",
42        marginTop: 12,
43        justifyContent: "space-evenly",
44        alignItems: "center",
45      }}
46    >
47      <Text style={{ fontSize: 24, color: "white" }}>{meetingId}</Text>
48      <Button
49        btnStyle={{
50          borderWidth: 1,
51          borderColor: "white",
52        }}
53        onPress={() => {
54          Clipboard.setString(meetingId);
55          alert("MeetingId copied successfully");
56        }}
57        buttonText={"Copy MeetingId"}
58        backgroundColor={"transparent"}
59      />
60      <Button
61        onPress={async () => {
62          try {
63            await leave();
64          } catch (error) {
65            console.error("Failed to leave meeting", error);
66          }
67        }}
68        buttonText={"Leave"}
69        backgroundColor={"#FF0000"}
70      />
71    </View>
72  );
73}
74
75function Container(){
76  ...
77
78  const mMeeting = useMeeting({
79    onMeetingJoined: async () => {
80      // Pin the local participant if he joins in SEND_AND_RECV mode
81      if (mMeetingRef.current.localParticipant.mode === "SEND_AND_RECV") {
82        try {
83          await mMeetingRef.current.localParticipant.pin();
84        } catch (error) {
85          console.error("Failed to pin the local participant", error);
86        }
87      }
88    },
89    onError: (error) => {
90      console.log(error.message);
91    },
92  });
93
94  // Create a ref to meeting object so that when used inside the
95  // Callback functions, meeting state is maintained
96  const mMeetingRef = useRef(mMeeting);
97  useEffect(() => {
98    mMeetingRef.current = mMeeting;
99  }, [mMeeting]);
100
101  return <>...</>;
102}
103
  1. You need to then create the ParticipantView to display the participant's media. To play the media, use the webcamStream and micStream from the useParticipant hook.
ParticipantView
1function ParticipantView({ participantId }) {
2  const { webcamStream, webcamOn } = useParticipant(participantId);
3  return webcamOn && webcamStream ? (
4    <RTCView
5      streamURL={new MediaStream([webcamStream.track]).toURL()}
6      objectFit={"cover"}
7      style={{
8        height: 300,
9        marginVertical: 8,
10        marginHorizontal: 8,
11      }}
12    />
13  ) : (
14    <View
15      style={{
16        backgroundColor: "grey",
17        height: 300,
18        justifyContent: "center",
19        alignItems: "center",
20        marginVertical: 8,
21        marginHorizontal: 8,
22      }}
23    >
24      <Text style={{ fontSize: 16 }}>NO MEDIA</Text>
25    </View>
26  );
27}
28
  1. You have to add the Controls component which will allow the speaker to toggle their media and start/stop HLS.
Controls Component
1function Controls() {
2  const { toggleWebcam, toggleMic, startHls, stopHls, hlsState } = useMeeting(
3    {}
4  );
5
6  const _handleHLS = async () => {
7    try {
8      if (!hlsState || hlsState === "HLS_STOPPED") {
9        await startHls({
10          layout: {
11            type: "GRID",
12            priority: "PIN",
13            gridSize: 4,
14          },
15          theme: "DARK",
16          orientation: "portrait",
17        });
18      } else if (hlsState === "HLS_STARTED" || hlsState === "HLS_PLAYABLE") {
19        await stopHls();
20      }
21    } catch (error) {
22      console.error("Failed to toggle HLS", error);
23    }
24  };
25
26  return (
27    <View
28      style={{
29        padding: 24,
30        flexDirection: "row",
31        justifyContent: "space-between",
32      }}
33    >
34      <Button
35        onPress={async () => {
36          try {
37            await toggleWebcam();
38          } catch (error) {
39            console.error("Failed to toggle webcam", error);
40          }
41        }}
42        buttonText={"Toggle Webcam"}
43        backgroundColor={"#1178F8"}
44      />
45      <Button
46        onPress={async () => {
47          try {
48            await toggleMic();
49          } catch (error) {
50            console.error("Failed to toggle mic", error);
51          }
52        }}
53        buttonText={"Toggle Mic"}
54        backgroundColor={"#1178F8"}
55      />
56      {hlsState === "HLS_STARTED" ||
57      hlsState === "HLS_STOPPING" ||
58      hlsState === "HLS_STARTING" ||
59      hlsState === "HLS_PLAYABLE" ? (
60        <Button
61          onPress={() => {
62            _handleHLS();
63          }}
64          buttonText={
65            hlsState === "HLS_STARTED"
66              ? `Live Starting`
67              : hlsState === "HLS_STOPPING"
68              ? `Live Stopping`
69              : hlsState === "HLS_PLAYABLE"
70              ? `Stop Live`
71              : `Loading...`
72          }
73          backgroundColor={"#FF5D5D"}
74        />
75      ) : (
76        <Button
77          onPress={() => {
78            _handleHLS();
79          }}
80          buttonText={`Go Live`}
81          backgroundColor={"#1178F8"}
82        />
83      )}
84    </View>
85  );
86}
87

Output Of SpeakerView Component

VideoSDK React Native ILS quickstart speaker screen with the participant list and studio controls

Step 6: Implement ViewerView

When the HOST (SEND_AND_RECV mode participant) initiates the live streaming, viewers will be able to watch it.

To implement the player view, you have to use react-native-video. It will be helpful for playing the HLS stream.

Begin by adding this package.

NPM
1npm install react-native-video
2
Yarn
1yarn add react-native-video
2

With react-native-video installed, you can now get the hlsUrls and isHlsPlayable from the useMeeting hook which will be used to play the HLS in the player.

ViewerView
1// imports react-native-video
2import Video from "react-native-video";
3
4function ViewerView({}) {
5  const { hlsState, hlsUrls } = useMeeting();
6
7  return (
8    <SafeAreaView style={{ flex: 1, backgroundColor: "black" }}>
9      {hlsState == "HLS_PLAYABLE" ? (
10        <>
11          {/* Render Header for copying the meetingId and leaving meeting*/}
12          <HeaderView />
13
14          {/* Render VideoPlayer that will play `playbackHlsUrl`*/}
15          <Video
16            controls={true}
17            source={{
18              uri: hlsUrls.playbackHlsUrl,
19            }}
20            resizeMode={"contain"}
21            style={{
22              flex: 1,
23              backgroundColor: "black",
24            }}
25            onError={(e) => console.log("error", e)}
26          />
27        </>
28      ) : (
29        <SafeAreaView
30          style={{ flex: 1, justifyContent: "center", alignItems: "center" }}
31        >
32          <Text style={{ fontSize: 20, color: "white" }}>
33            HLS is not started yet or is stopped
34          </Text>
35        </SafeAreaView>
36      )}
37    </SafeAreaView>
38  );
39}
40

Output of ViewerView Component

VideoSDK React Native ILS quickstart viewer screen playing the live stream

Tip: Stuck anywhere? Check out this example code on GitHub

Summarize with

ChatGPTClaudePerplexityGoogleGrok
Prefer VideoSDK on Google

Table of Contents

Start Building Now With $20 Free Balance

No credit card required to start.

Documentation →Github Repo →

Share This Article

TwitterLinkedInFacebookHacker News

Get started for free today

Grab your API keys and start building with free $20 included in your account. Need enterprise-grade security or custom workloads? Talk to an expert!

Book a demo

Video SDK Logo

United States

28 Geary St, Suite 650,
San Francisco, CA 94108, United States

India flag

India

18th Floor, 1812, The Junomoneta Tower,
Adajan-Hazira Rd, Surat, Gujarat 395009, India

Video SDK Logo
Video SDK Logo
Video SDK Logo
Video SDK Logo
SOLUTIONS

Video KYC

Video Banking

Virtual Claim

Video MER

Telehealth

Astrology

Gaming

Dating

Live Commerce

Auto Proctoring

Interview-as-a-service

Virtual Events

Live Audio Streaming

Ed-Tech

PRODUCTS

AI-Agents

Real-time Audio & Video SDK

Interactive Live Streaming SDK

Real-time Transcription SDK

Character SDK

Open Source Examples

SUCCESS STORIES

Examedi

Coderschool

TYHO

ForagerOne

Immigo

DEVELOPERS

Documentation

Code Samples

Developer Updates

Developer Hub

TOP ARTICLES

What is WebRTC?

Build a React Native Video Calling App

Build a Flutter Video Calling App

RESOURCES

The Protocol by Video SDK

AI Apps

Creator Program

LEGAL

Terms Of Service

Privacy Policy

Cookie Notice

CCPA Notice

Subprocessors

DPA

RSS

COMPANY

Contact Us

Pricing

Support

Blog

Press Kit