Skip to main content
Get up and running with a working video call using the LiveKit Swift SDK. This guide will walk you through connecting to a room, publishing your camera and microphone, and displaying remote participants.

Prerequisites

Before starting, make sure you have:
If you don’t have a LiveKit server yet, you can create a free account at LiveKit Cloud to get started.

Create a Room View Controller

Here’s a complete example that connects to a room, publishes your camera and microphone, and displays both local and remote video:
import LiveKit
import UIKit

class RoomViewController: UIViewController {

    lazy var room = Room(delegate: self)

    lazy var remoteVideoView: VideoView = {
        let videoView = VideoView()
        view.addSubview(videoView)
        // Position the remote video to fill the view
        videoView.frame = view.bounds
        videoView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        return videoView
    }()

    lazy var localVideoView: VideoView = {
        let videoView = VideoView()
        view.addSubview(videoView)
        // Position local video in bottom-right corner
        let size = CGSize(width: 120, height: 160)
        videoView.frame = CGRect(
            x: view.bounds.width - size.width - 20,
            y: view.bounds.height - size.height - 20,
            width: size.width,
            height: size.height
        )
        return videoView
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .black

        let url = "wss://your-server.livekit.cloud"
        let token = "your_jwt_token"

        Task {
            do {
                try await room.connect(url: url, token: token)
                print("Connected to room: \\(room.name ?? \"\")")

                // Publish camera & microphone
                try await room.localParticipant.setCamera(enabled: true)
                try await room.localParticipant.setMicrophone(enabled: true)
            } catch {
                print("Failed to connect: \\(error)")
            }
        }
    }
}

extension RoomViewController: RoomDelegate {

    func room(_: Room, participant _: LocalParticipant, didPublishTrack publication: LocalTrackPublication) {
        // Display local video track
        guard let track = publication.track as? VideoTrack else { return }
        DispatchQueue.main.async {
            self.localVideoView.track = track
        }
    }

    func room(_: Room, participant _: RemoteParticipant, didSubscribeTrack publication: RemoteTrackPublication) {
        // Display remote video track
        guard let track = publication.track as? VideoTrack else { return }
        DispatchQueue.main.async {
            self.remoteVideoView.track = track
        }
    }

    func room(_: Room, participant: RemoteParticipant, didJoin _: Bool) {
        print("Participant joined: \\(participant.identity)")
    }

    func room(_: Room, participant: RemoteParticipant, didLeave _: Bool) {
        print("Participant left: \\(participant.identity)")
    }
}

Step-by-Step Breakdown

Let’s break down what’s happening in this example:
1

Create the Room

lazy var room = Room(delegate: self)
The Room object is your main interface to LiveKit. It manages the connection, participants, and tracks.
2

Set up Video Views

lazy var remoteVideoView: VideoView = { ... }()
lazy var localVideoView: VideoView = { ... }()
VideoView is a UIKit component that renders video tracks. You need one view for each video stream you want to display.
3

Connect to the Room

try await room.connect(url: url, token: token)
Connect to your LiveKit server using your server URL and JWT token. The token contains room name and participant identity.
4

Publish Camera and Microphone

try await room.localParticipant.setCamera(enabled: true)
try await room.localParticipant.setMicrophone(enabled: true)
Start publishing your camera and microphone tracks. These methods create, configure, and publish the tracks automatically.
5

Handle Delegate Events

func room(_: Room, participant _: LocalParticipant, didPublishTrack publication: LocalTrackPublication)
func room(_: Room, participant _: RemoteParticipant, didSubscribeTrack publication: RemoteTrackPublication)
Implement RoomDelegate methods to receive events when tracks are published or subscribed. Assign tracks to video views to render them.

Important Notes

Thread Safety: VideoView is a UI component and must be accessed from the main thread. The SDK’s delegates are called on a background thread, so always use DispatchQueue.main.async when updating UI.
Audio Playback: Subscribed audio tracks are played automatically. You don’t need to do anything special to hear remote participants.
Auto-Subscribe: By default, the SDK automatically subscribes to all published tracks from remote participants. You can disable this with ConnectOptions(autoSubscribe: false).

Running Your App

  1. Add permissions to your Info.plist:
    <key>NSCameraUsageDescription</key>
    <string>Camera access is required for video calls</string>
    <key>NSMicrophoneUsageDescription</key>
    <string>Microphone access is required for voice calls</string>
    
  2. Get your server URL and token from the LiveKit dashboard
  3. Run your app and test it with another client (web, iOS, or Android)

Next Steps

Core Concepts

Learn about rooms, participants, and tracks

Camera & Microphone

Configure camera and audio capture options

Screen Sharing

Add screen sharing to your app

API Reference

Explore the complete API

Troubleshooting

Make sure your token is valid and not expired. Tokens are JWTs that contain room name, participant identity, and expiration time. Generate a new token from your LiveKit dashboard.
Check that you’ve added the required NSCameraUsageDescription and NSMicrophoneUsageDescription keys to your Info.plist. If the user denied permissions, you’ll need to ask them to grant them in Settings.
Make sure:
  • The remote participant is publishing video
  • You’ve implemented the didSubscribeTrack delegate method
  • You’re assigning the track to a VideoView on the main thread
  • The VideoView is added to your view hierarchy and visible
Audio tracks are played automatically, but make sure:
  • The device volume is not muted
  • Your app hasn’t disabled audio playback via AudioManager
  • The remote participant is publishing an audio track
For more help, see our Troubleshooting guide or join our Slack community.

Build docs developers (and LLMs) love