video sdk logo

Login

iOS Live Streaming Tutorial

Ship interactive live streams from iOS apps in Swift. Hosts broadcast in a low-latency conference, viewers watch the HLS feed in AVPlayer, and co-hosts can be promoted mid-stream.
iOS interactive live streaming app built with VideoSDK showing a host broadcast and AVPlayer viewer screen

Trusted by 300+ global business & tech leaders

Go Live from Your iOS App with HLS and AVPlayer

Learn how to add HLS live streaming to an iOS app using the VideoSDK iOS SDK. This tutorial covers starting and stopping a stream, host and viewer modes, and HLS playback with AVPlayer.


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

Prerequisites

  • iOS 13.0+
  • Xcode 15.0+
  • Swift 5.0+

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

App Architecture

The application consists of two primary interfaces:

  1. Start Meeting View
  • Allows users to create a new meeting or join an existing one by selecting their mode (Host or Viewer/Audience)
  1. Meeting View
  • Provides Http Live Stream controls and adapts the UI dynamically based on the user's mode (Host or Viewer/Audience).

Getting Started With the Code!

Follow the steps to create the environment necessary to add video calls into your app. Also you can find the code sample for quickstart here.

Info: Important Changes iOS SDK in Version v2.2.0

  • The following modes have been deprecated:
    • CONFERENCE has been replaced by SEND_AND_RECV
    • VIEWER has been replaced by SIGNALLING_ONLY

Please update your implementation to use the new modes.

⚠️ Compatibility Notice: To ensure a seamless meeting experience, all participants must use the same SDK version. Do not mix version v2.2.0 + with older versions, as it may cause significant conflicts.

Step 1: Create New iOS Application

Step 1: Create a new application by selecting Create a new Xcode project

Step 2: Add Product Name and Save the project.

Xcode new project sheet showing the Product Name field for the VideoSDK iOS HLS quickstart

Step 2: VideoSDK Installation

There are two ways to install VideoSDK: Using Swift Package Manager (SPM) or Using CocoaPods.

1. Install Using Swift Package Manager (SPM)

To install VideoSDK via Swift Package Manager, follow these steps:

  1. Open your Xcode project and go to File > Add Packages.
  2. Enter the repository URL:
1  https://github.com/videosdk-live/videosdk-rtc-ios-spm
2
  1. Choose the version rule (e.g., "Up to Next Major") and add the package to your target.
  2. Import the library in Swift files:
1import VideoSDKRTC
2

For more details, refer to the official guide on SPM installation.

2. Install Using CocoaPods

To install VideoSDK using CocoaPods, follow these steps:

  1. Initialize CocoaPods: Run the following command in your project directory:
1pod init
2
  1. Update the Podfile: Open the Podfile and add the VideoSDK dependency:
1pod 'VideoSDKRTC', :git => 'https://github.com/videosdk-live/videosdk-rtc-ios-sdk.git'
2
  1. Install the Pod: Run the following command to install the pod:
1pod install
2

For more details, refer to the official guide on CocoaPods installation.

then declare the permissions in Info.plist :

1<key>NSCameraUsageDescription</key>
2<string>Camera permission description</string>
3<key>NSMicrophoneUsageDescription</key>
4<string>Microphone permission description</string>
5

Step 3: Project Structure

Project Structure
1quick_start_ios_hls
2   ├── quick_start_ios_hls.swift // Default
3   ├── Screens
4        ├── StartMeetingView.swift
5        └── Meeting
6            ├── Controller
7                └── MeetingViewController.swift
8            └── MeetingView.swift
9   ├── Views
10        ├── HLSPlayer.swift
11        └── ParticipantViewItem.swift
12   ├── Model
13        └── RoomStruct.swift
14   └── Info.plist // Default
15 Pods
16     └── Podfile
17

Step 4: Create Start Meeting View

The StartMeetingView acts as the entry point for users to initiate or participate in Http Live Streams with the following functionalities:

  • Create Meeting as Host: Start a new Http Live Stream in SEND_AND_RECV mode, providing full host privileges.

  • Join as Host: Enter an existing Http Live Stream with SEND_AND_RECV mode, granting full host controls.

  • Join as Viewer: Join an existing Http Live Stream with SIGNALLING_ONLY mode, without receiving & producing audio & video.

StartMeetingView.swift
1import SwiftUI
2
3// MARK: - Meeting Role Enum
4enum UserRole: String { case host = "Host", case viewer = "Viewer" }
5
6struct StartMeetingView: View {
7    //MARK: - Properties
8    @State private var meetingId: String = "<MeetingID goes here>"
9    @State private var navigateToMeeting = false
10    @State private var selectedRole: UserRole = .host
11    @State private var animateButtons = false
12    @State private var isLoading = false
13    
14    var body: some View {
15        NavigationStack {
16            ZStack {
17                // Background
18                LinearGradient(
19                    colors: [Color.black, Color.black.opacity(0.9)],
20                    startPoint: .top,
21                    endPoint: .bottom
22                )
23                .ignoresSafeArea()
24                
25                VStack(spacing: 30) {
26                    Image("logo")
27                        .resizable()
28                        .renderingMode(.original)
29                        .aspectRatio(contentMode: .fit)
30                        .frame(width: 175, height: 175)
31                        .cornerRadius(25)
32                        .shadow(color: .white.opacity(0.5), radius: 20)
33                    Spacer()
34                    // Create Meeting Button
35                    animatedButton(title: "Create Meeting", bgColor: .blue) {
36                        if (!isLoading) {
37                            Task {
38                                await createMeeting()
39                            }
40                        }
41                    }
42                    // Meeting ID TextField
43                    VStack(alignment: .leading, spacing: 8) {
44                        Text("Enter Meeting ID")
45                            .font(.headline)
46                            .foregroundColor(.white.opacity(0.8))
47                        
48                        ZStack {
49                            RoundedRectangle(cornerRadius: 14)
50                                .fill(Color.white)
51                                .frame(height: 55)
52                            
53                            TextField("", text: $meetingId)
54                                .foregroundColor(.black)
55                                .padding(.horizontal)
56                                .textInputAutocapitalization(.never)
57                        }
58                    }
59                    .padding(.horizontal)
60                    // Host + Viewer Buttons
61                    HStack(spacing: 5) {
62                        animatedButton(title: "Join as Host", bgColor: .green) {
63                            selectedRole = .host
64                            navigateToMeeting = true
65                        }
66                        animatedButton(title: "Join as Viewer", bgColor: .orange) {
67                            selectedRole = .viewer
68                            navigateToMeeting = true
69                        }
70                    }
71                    Spacer()
72                }
73                .padding()
74            }
75            .navigationDestination(isPresented: $navigateToMeeting) {
76                MeetingView(meetingId: meetingId, role: selectedRole)
77            }
78        }
79    }
80    
81    // MARK: - API: Create Meeting
82    func createMeeting() async {
83        guard let url = URL(string: "https://api.videosdk.live/v2/rooms") else { return }
84        isLoading = true
85        var request = URLRequest(url: url)
86        request.httpMethod = "POST"
87        request.addValue(AUTH_TOKEN, forHTTPHeaderField: "Authorization")
88        do {
89            let (data, _) = try await URLSession.shared.data(for: request)
90            let decoded = try JSONDecoder().decode(RoomsStruct.self, from: data)
91            await MainActor.run {
92                if let roomId = decoded.roomID {
93                    self.meetingId = roomId
94                    self.selectedRole = .host
95                    self.navigateToMeeting = true
96                }
97            }
98        } catch {
99            print("Meeting creation failed:", error)
100        }
101        isLoading = false
102    } 
103    
104    // MARK: - Reusable Animated Button
105    @ViewBuilder
106    func animatedButton(title: String, bgColor: Color, action: @escaping () -> Void) -> some View {
107        Button(action: {
108            withAnimation(.spring(response: 0.25, dampingFraction: 0.5)) {
109                action()
110            }
111        }) {
112            Text(title)
113                .font(.headline)
114                .foregroundColor(.white)
115                .padding(.horizontal, 5)
116                .frame(height: 55)
117                .frame(maxWidth: .infinity)
118                .background(
119                    RoundedRectangle(cornerRadius: 16)
120                        .fill(bgColor.opacity(0.85))
121                        .shadow(color: bgColor.opacity(0.6), radius: 10, x: 0, y: 4)
122                )
123        }
124        .scaleEffect(animateButtons ? 1 : 0.85)
125        .animation(.spring(response: 0.5, dampingFraction: 0.6), value: animateButtons)
126        .padding(.horizontal, 5)
127    }
128}
129

Output

VideoSDK iOS HLS quickstart start meeting screen with create meeting, join as host and join as viewer buttons

Also add the StartMeetingView in main app as shown below

quick_start_ios_hls.swift
1import SwiftUI
2
3@main
4struct quick_start_ios_hls: App {
5    var body: some Scene {
6        WindowGroup {
7            StartMeetingView()
8        }
9    }
10}
11

Before proceeding, let's understand the two modes of a HTTP Live Stream:

1. SENDANDRECV (For Host or Co-host):

  • Designed primarily for the Host or Co-host.
  • Allows sending and receiving media.
  • Hosts can broadcast their audio/video and interact directly with the audience.

2. SIGNALLING_ONLY (For Viewer/Audience):

  • Tailored for the Viewer/Audience.
  • Doesn't enabled receiving media shared by the Host also.
  • Audience members can not view or listen, also cannot share their own media.

Step 5: Initialize and Join the Http Live Stream

In this step, Inside MeetingViewController we will setup initializeMeeting and related functions for it. You will require Auth token, you can generate it using either using videosdk-server-api-example or generate it from the Video SDK Dashboard for developer.

MeetingViewController will implement various event listeners such as MeetingEventListener, ParticipantEventListener.

MeetingViewController.swift
1import Foundation
2import SwiftUI
3import Combine
4import VideoSDKRTC
5internal import Mediasoup
6
7// MARK: - MeetingViewController
8class MeetingViewController: ObservableObject {
9    
10    @Published var participants: [Participant] = []
11    @Published var hlsState: HLSState = .HLS_STOPPED
12    
13    @Published var isMicOn: Bool = true
14    @Published var isWebcamOn: Bool = true
15    @Published var meeting: Meeting? = nil
16    @Published var participantVideoTracks: [String: RTCVideoTrack] = [:]
17    @Published var participantMicStatus: [String: Bool] = [:]
18    @Published var playbackURL: String? = nil
19    private var cancellables = Set<AnyCancellable>()
20    let meetingId: String
21    let role: UserRole
22    
23    init(meetingId: String, role: UserRole) {
24        self.meetingId = meetingId
25        self.role = role
26        
27        // Auto-start meeting logic when created
28        initializeMeeting()
29    }
30    // MARK: - Meeting Initialization
31    func initializeMeeting() {
32        VideoSDK.config(token: AUTH_TOKEN)
33        
34        let videoMediaTrack = try? VideoSDK.createCameraVideoTrack(
35            encoderConfig: .h720p_w1280p,
36            facingMode: .front,
37            multiStream: true
38        )
39        meeting = VideoSDK.initMeeting(
40            meetingId: meetingId,
41            participantName: "John doe",
42            micEnabled: self.isMicOn,
43            webcamEnabled: self.isWebcamOn,
44            customCameraVideoStream: videoMediaTrack,
45            multiStream: true,
46            mode: self.role == .viewer ? .SIGNALLING_ONLY : .SEND_AND_RECV
47        )
48        
49        // Add event listeners and join the meeting
50        meeting?.addEventListener(self)
51        meeting?.join()
52    }
53    
54    // MARK: - HLS Handling
55    func startHLS() {
56        DispatchQueue.main.async {
57            self.meeting?.startHLS()
58        }
59    }
60    
61    func stopHLS() {
62        DispatchQueue.main.async {
63            self.meeting?.stopHLS()
64        }
65    }
66    
67    // MARK: - Media Toggles
68    func toggleMic() {
69        if (isMicOn) {
70            DispatchQueue.main.async {
71                self.meeting?.muteMic()
72            }
73        } else {
74            DispatchQueue.main.async {
75                self.meeting?.unmuteMic()
76            }
77        }
78        isMicOn.toggle()
79    }
80    
81    func toggleWebcam() {
82        if (isWebcamOn) {
83            DispatchQueue.main.async {
84                self.meeting?.disableWebcam()
85            }
86        } else {
87            DispatchQueue.main.async {
88                self.meeting?.enableWebcam()
89            }
90        }
91        isWebcamOn.toggle()
92    }
93    
94    // MARK: - Leave Meeting
95    func leaveMeeting() {
96        if (role == .host) {
97            if (self.hlsState == .HLS_STARTED || self.hlsState == .HLS_PLAYABLE || self.hlsState == .HLS_STARTING) {
98                self.meeting?.stopHLS()
99            }
100        }
101        self.meeting?.leave()
102    }
103}
104
105extension MeetingViewController: MeetingEventListener {
106    func onMeetingJoined() {
107        guard let localParticipant = self.meeting?.localParticipant else { return }
108        let isExist = participants.first { $0.id == localParticipant.id } != nil
109        if (!isExist  && (localParticipant.mode != .SIGNALLING_ONLY && localParticipant.mode != .VIEWER)) {
110            participants.append(localParticipant)
111        }
112        // add event listener
113        localParticipant.addEventListener(self)
114    }
115    //...
116}
117
118extension MeetingViewController: ParticipantEventListener {
119    func onStreamEnabled(_ stream: MediaStream, forParticipant participant: Participant) {
120        if let track = stream.track as? RTCVideoTrack {
121            DispatchQueue.main.async {
122                if case .state(let mediaKind) = stream.kind, mediaKind == .video {
123                    self.participantVideoTracks[participant.id] = track
124                }
125            }
126        }
127        
128        if case .state(let mediaKind) = stream.kind, mediaKind == .audio {
129            self.participantMicStatus[participant.id] = true // Mic enabled
130        }
131    }
132
133    func onStreamDisabled(_ stream: MediaStream, forParticipant participant: Participant) {
134        DispatchQueue.main.async {
135            if case .state(let mediaKind) = stream.kind, mediaKind == .video {
136                self.participantVideoTracks.removeValue(forKey: participant.id)
137            }
138        }
139        if case .state(let mediaKind) = stream.kind, mediaKind == .audio {
140            // Update microphone state for this participant
141            self.participantMicStatus[participant.id] = false // Mic disabled
142
143        }
144    }
145}
146

Step 6: Create ParticipantViewItem View

The ParticipantViewItem file manages the participant view for particular participant which is showed in the participants which is host in the meeting.

ParticipantViewItem.swift
1import VideoSDKRTC
2import SwiftUI
3internal import Mediasoup
4
5struct ParticipantContainerView: View {
6    let participant: Participant
7
8    @ObservedObject var controller: MeetingViewController
9    
10    var body: some View {
11        ZStack {
12            participantView(participant: participant, controller: controller)
13            
14            VStack {
15                Spacer()
16                HStack {
17
18                    // Participant name
19                    Text(participant.displayName)
20                        .foregroundColor(.white)
21                        .padding(.horizontal, 8)
22                        .padding(.vertical, 4)
23                        .background(Color.black.opacity(0.5))
24                        .cornerRadius(4)
25                    
26                    // Mic status indicator
27                    Image(systemName: controller.participantMicStatus[participant.id] ?? false ? "mic.fill" : "mic.slash.fill")
28                        .foregroundColor(controller.participantMicStatus[participant.id] ?? false ? .green : .red)
29                        .padding(4)
30                        .background(Color.black.opacity(0.5))
31                        .clipShape(Circle())
32
33                    
34                    Spacer()
35                }
36                .padding(8)
37            }
38        }
39        .background(Color.black.opacity(0.9)) // Background color
40        .cornerRadius(10) // Rounded corners
41        .shadow(color: Color.gray.opacity(0.7), radius: 10, x: 0, y: 5) // Shadow effect
42        .overlay(
43            RoundedRectangle(cornerRadius: 10) // Rounded border
44                .stroke(Color.gray.opacity(0.9), lineWidth: 1)
45        )
46
47    }
48    
49    private func participantView(participant: Participant, controller: MeetingViewController) -> some View {
50        ZStack {
51            ParticipantView(participant: participant, controller: controller)
52        }
53    }
54}
55
56/// VideoView for participant's video
57class VideoView: UIView {
58    var videoView: RTCMTLVideoView = {
59        let view = RTCMTLVideoView()
60        view.videoContentMode = .scaleAspectFill
61        view.backgroundColor = UIColor.black
62        view.clipsToBounds = true
63        view.transform = CGAffineTransform(scaleX: 1, y: 1)
64
65        return view
66    }()
67    
68    init(track: RTCVideoTrack?, frame: CGRect) {
69        super.init(frame: frame)
70        backgroundColor = .clear
71        
72        // Set videoView frame to match parent view
73        videoView.frame = bounds
74        
75        DispatchQueue.main.async {
76            self.addSubview(self.videoView)
77            self.bringSubviewToFront(self.videoView)
78            track?.add(self.videoView)
79        }
80    }
81    
82    required init?(coder: NSCoder) {
83        fatalError("init(coder:) has not been implemented")
84    }
85    
86    override func layoutSubviews() {
87        super.layoutSubviews()
88        // Update videoView frame when parent view size changes
89        videoView.frame = bounds
90    }
91}
92
93/// ParticipantView for showing and hiding VideoView
94struct ParticipantView: View {
95    let participant: Participant
96    @ObservedObject var controller: MeetingViewController
97    
98    var body: some View {
99        ZStack {
100            if let track = controller.participantVideoTracks[participant.id] {
101                VideoStreamView(track: track)
102            } else {
103                Color.white.opacity(1.0)
104                Text("No media")
105                    .font(.largeTitle)
106                    .foregroundStyle(.black)
107            }
108        }
109    }
110}
111
112struct VideoStreamView: UIViewRepresentable {
113    let track: RTCVideoTrack
114    
115    func makeUIView(context: Context) -> VideoView {
116        let view = VideoView(track: track, frame: .zero)
117        return view
118    }
119    
120    func updateUIView(_ uiView: VideoView, context: Context) {
121        track.add(uiView.videoView)
122        uiView.videoView.videoContentMode = .scaleAspectFill
123    }
124}
125

Output

VideoSDK iOS HLS quickstart meeting screen showing the participant grid without host controls

Step 7: Implementing Media Toggles and Start/Stop HLS

Host Controls: Include buttons to toggle the microphone, webcam and HLS, allowing users to mute/unmute their microphone and enable/disable their camera and start/stop the HLS entirely.

Header UI: Includes button for leave the meeting and meetingId also displayed in the Header UI.

MeetingView.swift
1import SwiftUI
2import VideoSDKRTC
3
4struct MeetingView: View {
5    
6    @StateObject private var controller: MeetingViewController
7    @Environment(\.dismiss) var dismiss
8    
9    init(meetingId: String, role: UserRole) {
10        _controller = StateObject(
11            wrappedValue: MeetingViewController(meetingId: meetingId, role: role)
12        )
13    }
14    
15    // Grid layout
16    private let columns = [
17        GridItem(.flexible(), spacing: 10),
18        GridItem(.flexible(), spacing: 10),
19    ]
20    
21    var body: some View {
22        ZStack {
23            Color.black.ignoresSafeArea()
24            
25            VStack(spacing: 20) {
26                
27                // HEADER
28                header
29                
30                if controller.role == .host {
31                    // HLS State
32                    Text("Current HLS State : \(controller.hlsState.rawValue)")
33                        .foregroundColor(.white)
34                        .font(.headline)
35                    
36                    // Participants Grid
37                    ScrollView {
38                        LazyVGrid(columns: columns) {
39                            ForEach(controller.participants, id: \.id) { participant in
40                                ParticipantContainerView(
41                                    participant: participant,
42                                    controller: controller
43                                )
44                                .frame(height: 200, alignment: .center)
45                                
46                            }
47                        }
48                    }
49                    
50                    Spacer()
51                } else {
52                    if ((controller.hlsState == .HLS_STARTED || controller.hlsState == .HLS_PLAYABLE) && controller.playbackURL != nil) {
53                        HLSVideoPlayer(
54                            url: URL(string: controller.playbackURL ?? "")!,
55                            width: .infinity,
56                            height: .infinity
57                        )
58                        .cornerRadius(12)
59                        .padding()
60                       
61                        Spacer()
62                    } else {
63                        Spacer()
64                        Text("Waiting for host\nto start the live streaming")
65                            .font(.title)
66                            .foregroundStyle(.white)
67                            .bold(true)
68                            .multilineTextAlignment(.center)
69                        Spacer()
70                    }
71                }
72                
73                // Host Controls
74                if controller.role == .host {
75                    hostControls
76                }
77            }
78        }
79        .navigationBarBackButtonHidden(true)
80        .navigationBarHidden(true)
81    }
82    
83    // MARK: Header UI
84    private var header: some View {
85        HStack {
86            Text("Meeting : \(controller.meetingId)")
87                .foregroundColor(.white)
88                .font(.title3.bold())
89            
90            Spacer()
91            
92            Button {
93                controller.leaveMeeting()
94                dismiss()
95            } label: {
96                Text("Leave")
97                    .font(.headline)
98                    .padding(.horizontal, 18)
99                    .padding(.vertical, 10)
100                    .background(Color.blue)
101                    .foregroundColor(.white)
102                    .cornerRadius(10)
103            }
104        }
105        .padding(.horizontal)
106        .padding(.top)
107    }
108    
109    // MARK: Host bottom controls
110    private var hostControls: some View {
111        HStack(spacing: 14) {
112            
113            if (controller.hlsState == .HLS_STARTING || controller.hlsState == .HLS_STARTED || controller.hlsState == .HLS_PLAYABLE) {
114                    controlButton(title: "Stop HLS") {
115                        controller.stopHLS()
116                    }
117            } else {
118                controlButton(title: "Start HLS") {
119                    controller.startHLS()
120                }
121            }
122            
123            controlButton(title: "Toggle Webcam") {
124                controller.toggleWebcam()
125            }
126            
127            controlButton(title: "Toggle Mic") {
128                controller.toggleMic()
129            }
130        }
131        .padding(.bottom, 20)
132    }
133    
134    // MARK: Reusable UI Elements
135    func controlButton(title: String, action: @escaping () -> Void) -> some View {
136        Button(action: action) {
137            Text(title)
138                .font(.headline)
139                .padding(.horizontal, 14)
140                .padding(.vertical, 12)
141                .background(Color.blue)
142                .foregroundColor(.white)
143                .cornerRadius(10)
144        }
145    }
146}
147

Output

VideoSDK iOS HLS quickstart meeting screen with the host controls for HLS, webcam and mic

Step 8: Extending Meeting Event Listeners

In this step, we extend the MeetingEventListener implementation in MeetingViewController by adding additional event listeners for enhanced meeting functionality. These include onParticipantJoined and onParticipantLeft to handle participant updates, onMeetingStateChanged to manage meeting state transitions, and onHlsStateChanged to track HLS state, allowing us to utilize them as needed.

MeetingViewController.swift
1class MeetingViewController: ObservableObject {
2//...
3 extension MeetingViewController: MeetingEventListener {
4    //...
5    func onParticipantJoined(_ participant: Participant) {
6        let isExist = participants.first { $0.id == participant.id } != nil
7        if (!isExist && (participant.mode != .SIGNALLING_ONLY && participant.mode != .VIEWER)) {
8            participants.append(participant)
9        }
10        // add listener
11        participant.addEventListener(self)
12    }
13    
14    func onParticipantLeft(_ participant: Participant) {
15        participants = participants.filter({ $0.id != participant.id })
16    }
17    
18    func onMeetingStateChanged(meetingState: MeetingState) {
19        switch meetingState {
20        case .DISCONNECTED:
21                participants.removeAll()
22            default:
23            print("meeting state: \(meetingState.rawValue)")
24        }
25    }
26    
27    func onHlsStateChanged(state: HLSState, hlsUrl: HLSUrl?) {
28        hlsState = state
29        switch (state) {
30        case .HLS_PLAYABLE:
31            playbackURL = hlsUrl?.playbackHlsUrl ?? ""
32        default:
33            print("HLS State: \(state.rawValue)")
34        }
35    }
36 }
37    //...
38}
39

Output

VideoSDK iOS HLS quickstart meeting screen showing the live HLS state after the stream starts

Final Output

We are done with implementation of HLS Live Streaming in iOS Appplication using Video SDK. To explore more features go through Basic and Advanced features.

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