Getting Started: iOS


This guide provides you with an overview of the key objects you'll use in the Programmable Video API to build your video application with the Twilio Programmable Video iOS SDK.

Note: If you haven’t already done so, take a look at the open source video collaboration app and quickstart apps. Then come back to this guide for more detail on how to add video to your own app.

WebRTCをお使いいただいた経験があるなら、Programmable Videoは完成度の高いオーディオおよびビデオアプリケーションの構築を容易にするために、WebRTCの下位レベルAPIの単純なラッパーを提供していることに気づかれるでしょう。 依然としてより下位レベルのプリミティブにアクセスできますが、入門には必要ありません。

加えて、Programmable VideoはWebRTCを使用して洗練されたアプリケーションを構築するために必要な不足したピース: グローバルSTUN/TURNリレー、大規模な電話会議および録音用のメディアサービス、そしてシグナリングのためのインフラが全て含まれています。

Video API概要

まずは、Programmable Video APIの概要からはじめましょう:

  • Roomはリアルタイムのオーディオ、ビデオ、そして画面共有セッションを表し、これはProgrammable Videoアプリケーションにおける基本となる構成要素になります。
  • In a Peer-to-peer Room, media flows directly between participants. Supports up to 10 participants in a mesh topology.
  • In a Group Room, media is routed through Twilio's Media Servers. Supports up to 50 participants.
  • Participants は、Roomに接続され、他のクライアントとオーディオまたは(および)ビデオのメディアと共有しているクライアントアプリケーションを表します。
  • Tracks は、Roomと共有されているオーディオとビデオのストリームを表します。
  • LocalTracks represent the audio and video captured from the local microphone and camera.
  • RemoteTracks represent the audio and video tracks from other participants connected to the Room.



To start using the iOS Programmable Video SDK in your apps, you need to perform a few basic tasks first.

1. Get the Programmable Video iOS SDK

The Twilio Video iOS SDK dynamic framework can be installed using Swift Package Manager, CocoaPods or manually, as you prefer.

Swift Package Manager

You can add Programmable Video for iOS by adding the https://github.com/twilio/twilio-video-ios repository as a Swift Package.

In your Build Settings, you will also need to modify Other Linker Flags to include -ObjC.

As of the latest release of Xcode, there is a known issue with consuming binary frameworks distributed via Swift Package Manager. The current workaround to this issue is to add a Run Script Phase to the Build Phases of your Xcode project. This Run Script Phase should come after the Embed Frameworks build phase. This new Run Script Phase should contain the following code:

find "${CODESIGNING_FOLDER_PATH}" -name '*.framework' -print0 | while read -d $'\0' framework
    codesign --force --deep --sign "${EXPANDED_CODE_SIGN_IDENTITY}" --preserve-metadata=identifier,entitlements --timestamp=none "${framework}"

source 'https://github.com/CocoaPods/Specs'

platform :ios, '12.2'

target 'TARGET_NAME' do
    pod 'TwilioVideo', '~> 5'

そして、pod install を実行してプロジェクトに依存関係をインストールします。


TwilioVideo.xcframework は既存のプロジェクトにドラッグ&ドロップできる動的なiOSフレームワークとして配布されています。

View all Video iOS Releases here or just download the latest Video dynamic framework here.

Once you've downloaded and unpacked the XCFramework, navigate to your Xcode project's General settings page. Drag and drop TwilioVideo.xcframework onto the Frameworks, Libraries, and Embedded Content section. Ensure that "Copy items if needed" is checked and press Finish. Ensure that "Embed & Sign" is selected.

In your Build Settings, you will also need to modify Other Linker Flags to include -ObjC.

Background Modes

To allow a connection to a Room to be persisted while an application is running in the background, you must select the Audio, AirPlay, and Picture in Picture background mode from the Capabilities project settings page.

User Permissions

Twilio Video requires user permission for features like sharing video from the camera or audio from the microphone. Consider how your applications might function with reduced functionality in case some permissions (like the camera) are declined.

わかりやすい名前 Privacy Usage Description Key iOS Version Recommendation
Camera NSCameraUsageDescription すべて Request permissions using AVCaptureDevice.requestAccess(for:completionHandler:) before calling TwilioVideoSDK.connect(options:delegate:) with a TVICameraSource.
Microphone NSMicrophoneUsageDescription すべて Request permissions using AVAudioSession.requestRecordPermission() before calling TwilioVideoSDK.connect(options:delegate:) when Participants publish or subscribe to audio tracks with TVIDefaultAudioDevice. (*)
Local Network NSLocalNetworkUsageDescription 14.0 + This permission is not recommended unless your app is already using NWConnection APIs on the local network. Twilio Video only requests permissions after you connect to a Peer-to-Peer Room with TVILocalNetworkPrivacyPolicyAllowAll on iOS 14.

The iOS SDK supports iOS 12.2 or higher. It is built for arm64 and x86_64 architectures with Bitcode slices for arm64 devices.

Supported Xcode versions and Bitcode

The TwilioVideo.framework is built with Xcode 13. The framework can be consumed with previous versions of Xcode. However, re-compiling Bitcode when exporting for Ad Hoc or Enterprise distribution requires the use of Xcode 13.x.

2. Get an API Key


For the purposes of this guide, we will create our API Key from the Twilio Console.

  • Go to the API Keys section under Account in the Twilio Console.
  • Click on “Create a New API Key”, add a friendly name and save your Key and Secret.

3. Generate an Access Token

To execute the code samples below, you'll need to generate an Access Token. An Access Token is a short-lived credential used to authenticate your client-side application to Twilio.

You can generate an Access Token using either the Twilio CLI or a Twilio helper library. For application testing purposes, the Twilio CLI provides a quick way to generate Access Tokens that you can then copy/paste into your application.

To use the CLI, you will need to install the Twilio CLI and log in to your Twilio account from the command line; see the CLI Quickstart for instructions. Then, you can install the Token CLI plugin with the following command:

twilio plugins:install @twilio-labs/plugin-token

To generate an Access Token, run the following command. --identity is a required argument and should be a string that represents the user identity for this Access Token.

twilio token:video --identity=<identity>

In a production application, your back-end server will need to generate an Access Token for every user in your application. Visit the User Identity and Access Token guide to learn more. You can find examples of how to generate an Access Token for a participant using Twilio's helper libraries in the User Identity and Acces Token guide.


Call TwilioVideo.connect() to connect to a Room from your iOS application. Once connected, you can send and receive audio and video streams with other Participants who are connected to the Room.

@IBAction func createARoom(sender: AnyObject) {
    let connectOptions = ConnectOptions(token: accessToken) { (builder) in
        builder.roomName = "my-room"
    room = TwilioVideoSDK.connect(options: connectOptions, delegate: self)

// MARK: RoomDelegate

func roomDidConnect(room: Room) {
    print("Did connect to Room")

    if let localParticipant = room.localParticipant {
        print("Local identity \(localParticipant.identity)")

        // Set the delegate of the local particiant to receive callbacks
        localParticipant.delegate = self

Roomへの接続時には、アクセストークンを渡すことが必要です。 またオプションで、下記を渡すこともできます:

  • Local audio, video or data tracks, to begin sharing pre-created local media with other Participants in the Room upon connecting.
  • ルーム名: 参加したいルームの名前を動的に指定できます。 (メモ: ルーム名をアクセストークンにエンコードできます。 こうすることでユーザーはトークンで指定されたRoomにのみ接続できます。)
  • ICEトランスポートポリシー: テスト用途として、強制的にTURNリレー経由で通話を行えるようになります。

Roomの名前には、参加したいRoomを指定します。 その名前のRoomがまだ存在していない場合、接続に先立って作成されます。 ルームがすでにアクティブな場合はルームに接続され、同じルームに接続されている他の参加者からの通知を受信します。 ルーム名はアカウント内で一意でなければなりません。

また、Rooms REST APIを使用してRoomに接続することも可能です。 さらなる詳細については、REST API Roomsリソースを参照してください。

Example: Create a Room called DailyStandup

 curl -XPOST 'https://video.twilio.com/v1/Rooms' \
 -u '{API Key SID}:{API Secret}' \
 -d 'UniqueName=DailyStandup'

注 : Type属性を指定しない場合、Twilioは既定でGroupルームを作成します。


You can also set the room type from the Room Settings page in the Twilio Video Console. Twilio will use the room type set on Room Settings page, when you create a room from the client-side or the REST API.

メモ: Twilioは、Room設定ページの既定としてRoomタイプをGroupに設定します。

StatusCallback URLが設定されている場合、Roomが作成されると、Twilioはroom-created Webhookイベントを呼び出します。 クライアント側からRoomを作成したい場合、Room設定ページからStatusCallback URLを設定できます。 REST APIでRoomを作成する場合、Room作成時にStatusCallback URLを指定することが必要です。

 curl -XPOST 'https://video.twilio.com/v1/Rooms' \
 -u '{API Key SID}:{API Secret}' \
 -d 'UniqueName=DailyStandup' \
 -d 'StatusCallback=https://hooks.yoursite.com/room-events' \
 -d 'StatusCallbackMethod=POST' \
 -d 'Type=group'

Enabling Room Recordings

Recordings can be enabled only on Group Rooms. Set Recordings to Enabled to record participants when they connect to a Group Room. Recordings can also be enabled on Group Rooms through via the Rest API at Room creation time by setting the RecordParticipantsOnConnect property to true.

curl -XPOST 'https://video.twilio.com/v1/Rooms' \
-u '{API Key SID}:{API Secret}' \
-d 'UniqueName=DailyStandup' \
-d 'Type=group' \
-d 'RecordParticipantsOnConnect=true' \
-d 'StatusCallback=http://example.org'


If you'd like to join a Room you know already exists, you handle that exactly the same way as creating a room: just pass the Room name to the connect method. Once in a Room, you'll receive a room:participantDidConnect: callback for each Participant that successfully joins. Querying the remoteParticipants getter will return any existing Participants who have already joined the Room.

@IBAction func joinRoom(sender: AnyObject) {
    let connectOptions = ConnectOptions(token: accessToken) { (builder) in
        builder.roomName = "existing-room"
    room = TwilioVideoSDK.connect(options: connectOptions, delegate: self)

// MARK: RoomDelegate

func roomDidConnect(room: Room) {
    print("Did connect to room")

    if let localParticipant = room.localParticipant {
        print("Local identity \(localParticipant.identity)")

        // Set the delegate of the local particiant to receive callbacks
        localParticipant.delegate = self

Set up local media


iOSアプリケーションでは、TVILocalAudioTrackを作成することでオーディオの取り込みを開始し、TVIVideoCapturerと関連づけられたTVILocalVideoTrackを作成することでビデオの取り込みを開始します。 iOS Video SDKはカメラおよび画面共有の双方に対して、カスタマイズ可能なビデオ取り込みを提供します。

// Create an audio track
var localAudioTrack = LocalAudioTrack()

// Create a data track
var localDataTrack = LocalDataTrack()

// Create a CameraSource to provide content for the video track
var localVideoTrack : LocalVideoTrack?

// Create a video track with the capturer.
if let camera = CameraSource(delegate: self) {
    localVideoTrack = LocalVideoTrack(source: camera)

Specify tracks at connect time

When the client joins a Room, the client can specify which Tracks they wish to share with other Participants. Imagine we want to share the audio and video Tracks we created earlier.

let connectOptions = ConnectOptions(token: accessToken) { (builder) in
    builder.roomName = "my-room"

    if let audioTrack = localAudioTrack {
        builder.audioTracks = [ audioTrack ]
    if let dataTrack = localDataTrack {
        builder.dataTracks = [ dataTrack ]
    if let videoTrack = localVideoTrack {
        builder.videoTracks = [ videoTrack ]

var room = TwilioVideoSDK.connect(options: connectOptions, delegate: self)

Connect as a publish-only Participant

For some use cases (such as a ReplayKit broadcast extension) you may wish to connect as a publish-only Participant that is not subscribed to any Tracks. If you are connecting to a Group Room, you may disable automatic subscription behavior via ConnectOptions.

let connectOptions = ConnectOptions(token: accessToken) { (builder) in
    builder.isAutomaticSubscriptionEnabled = false
    builder.roomName = "my-room"

    if let audioTrack = localAudioTrack {
        builder.audioTracks = [ audioTrack ]

var room = TwilioVideo.connect(options: connectOptions, delegate: self)



When you join a Room, Participants may already be present. You can check for existing Participants in the roomDidConnect: callback by using the remoteParticipants getter. To receive RemoteParticipantDelegate callbacks you will need to set the RemoteParticipant.delegate property for each connected Remote Participant.

room = TwilioVideo.connect(options: connectOptions, delegate: self)

// MARK: RoomDelegate

func roomDidConnect(room: Room) {
    // The Local Participant
    if let localParticipant = room.localParticipant {
        print("Local identity \(localParticipant.identity)")

        // Set the delegate of the local participant to receive callbacks
        localParticipant.delegate = self

    // Connected participants already in the room
    print("Number of connected Participants \(room.remoteParticipants.count)")

    // Set the delegate of the remote participants to receive callbacks
    for remoteParticipant in room.remoteParticipants {
      remoteParticipant.delegate = self

func participantDidConnect(room: Room, participant: RemoteParticipant) {
    print ("Participant \(participant.identity) has joined Room \(room.name)")

    // Set the delegate of the remote participant to receive callbacks
    participant.delegate = self

func participantDidDisconnect(room: Room, participant: RemoteParticipant) {
    print ("Participant \(participant.identity) has left Room \(room.name)")


When Participants connect to or disconnect from a Room that you're connected to, you'll be notified via an event listener: Similar to Room Events, Twilio will fire Participant events if the StatusCallback webhook URL is set when the Room is created. These events help your application keep track of the participants who join or leave a Room.

// MARK: RoomDelegate

// First, we set a Participant Delegate when a Participant first connects:
func participantDidConnect(room: Room, participant: RemoteParticipant) {
    print("Participant connected: \(participant.identity)")
    participant.delegate = self



// MARK: RemoteParticipantDelegate

 * In the Participant Delegate, we can respond when the Participant adds a Video
 * Track by rendering it on screen.
func didSubscribeToVideoTrack(videoTrack: RemoteVideoTrack,
                              publication: RemoteVideoTrackPublication,
                              participant: RemoteParticipant) {

    print("Participant \(participant.identity) added a video track.")

    if let remoteView = VideoView.init(frame: self.view.bounds,
                                       delegate:self) {

        self.remoteView = remoteView

// MARK: VideoViewDelegate

// Lastly, we can subscribe to important events on the VideoView
func videoViewDimensionsDidChange(view: VideoView, dimensions: CMVideoDimensions) {
    print("The dimensions of the video track changed to: \(dimensions.width)x\(dimensions.height)")



Sometimes you need to make sure you're looking fantastic before entering a Room. We get it. The iOS SDK provides a means to render a local camera preview outside the context of an active Room:

// Use CameraSource to produce video from the device's front camera.

if let camera = CameraSource(delegate: self),
    let videoTrack = LocalVideoTrack(source: camera) {

    // VideoView is a VideoRenderer and can be added to any VideoTrack.
    let renderer = VideoView(frame: view.bounds)

if let camera = TVICameraCapturer(source: .frontCamera),
    let videoTrack = TVILocalVideoTrack(capturer: camera) {

    // TVIVideoView is a TVIVideoRenderer and can be added to any TVIVideoTrack.
    let renderer = TVIVideoView(frame: view.bounds)

    // Add renderer to the video track

    self.localVideoTrack = videoTrack
    self.camera = camera
} else {
    print("Couldn't create CameraCapturer or LocalVideoTrack")


現在参加しているルームから切断できます。 他の参加者は participantDisconnected イベントを受信します。

// To disconnect from a Room, we call:

// This results in a callback to RoomDelegate#roomDidDisconnect(room: Room, error: Error?)

// MARK: RoomDelegate

func roomDidDisconnect(room: Room, error: Error?) {
    print("Disconnected from room \(room.name)")

Room reconnection

The Video SDK will raise notifications when a Room is reconnecting due to a network disruption. A Room reconnection is triggered due to a signaling or media reconnection event. To capture when a reconnection is triggered or that it has reconnected:

// MARK: RoomDelegate

// Error will be either TwilioVideoSDK.Error.signalingConnectionError or TwilioVideoSDK.Error.mediaConnectionError
func roomIsReconnecting(room: Room, error: Error) {
    print("Reconnecting to room \(room.name), error = \(String(describing: error))")

func roomDidReconnect(room: Room) {
    print("Reconnected to room \(room.name)")

Reconnections in a Peer-to-Peer Room

In a Peer-to-Peer Room, each Participant has media connections to all the other Participants in the Room. If all media connections between the LocalParticipant and all other Participants are broken, then the LocalParticipant's Room will enter the reconnecting state until media connectivity with at least one Participant is re-established.

Reconnections and the UIApplication lifecycle

There are certain instances when an application is put into the background that both the signaling and media connection are closed, which will cause the reconnecting delegate method to be invoked:

  • When connected to a Peer-to-Peer Room with no Remote Participants.
  • When connected to a Peer-to-Peer Room with other Remote Participants and no shared audio tracks.
  • When connected to a Group Room with no shared audio tracks.

Server-side control

The Programmable Video REST API allows you to control your video applications from your back-end server via HTTP requests. To learn more check out the Programmable Video REST API docs.


We love feedback and questions especially those with helpful debugging information so we can diagnose and respond quickly. When submitting issues or support tickets, it would be great if you add the following:

  • Description - A description of the issue
  • Steps to reproduce - List the steps necessary to reproduce the issue
  • Code - Include any applicable code snippets that would assist in reproduction and troubleshooting
  • Expected Behavior - What you expect to happen
  • Actual Behavior - What actually happens
  • Reproduces How Often - What percentage of the time does it reproduce?
  • Logs - Any log output when the issue occurs. See below for enabling debug level logging.
  • Video iOS SDK - The version(s) of the Video iOS SDK where this issue is apparent
  • Xcode - The version(s) of Xcode where this issue is apparent
  • iOS Version - The version(s) of iOS where this issue is apparent
  • iOS Device - The iOS device(s) where this issue is apparent
  • Room SID - Room SIDs can be useful for tracing backend issues

After gathering the above information, you can get help in a few ways:

For issues related to the Twilio Video iOS SDK itself:

For issues related to the Twilio Video iOS Quickstarts:

Enabling Debug Logging

To enable debug level logging, add the following code in your application:



We all do sometimes; code is hard. Get help now from our support team, or lean on the wisdom of the crowd by visiting Twilio's Stack Overflow Collective or browsing the Twilio tag on Stack Overflow.



        Please select the reason(s) for your feedback. The additional information you provide helps us improve our documentation:

        Sending your feedback...
        🎉 Thank you for your feedback!
        Something went wrong. Please try again.

        Thanks for your feedback!

        Refer us and get $10 in 3 simple steps!


        Get link

        Get a free personal referral link here


        Give $10

        Your user signs up and upgrade using link


        Get $10

        1,250 free SMSes
        OR 1,000 free voice mins
        OR 12,000 chats
        OR more