Building an iOS Video Chat App with In-Call Statistics

When you’re building a real-time engagement application, a ton of metrics need to be monitored to deliver a smooth experience to the end user. There can be many challenges when debugging a suboptimal user experience: high CPU usage, low internet bandwidth, dropped frames, and so on. The in-call statistics can be used to monitor, maintain, and improve the user experience.

In this tutorial, we’ll add in-call stats to an iOS app, using the Agora UIKit CocoaPod to simplify the process. If you’re new to the Agora SDK, you can learn how to build a project from scratch by using the quickstart blog or the short UIKit guide. We’ll look at how to access and display statistics for local and remote videos, and how to access other important call aspects, like bandwidth and CPU usage.



Create an iOS project in Xcode, and then install the AgoraUIKit_iOS CocoaPod. Your Podfile should look like this:

target 'Agora-Call-Stats' do
pod 'AgoraUIKit_iOS', '~> 1.5'

The latest AgoraUIKit release at the time of writing is v1.5.1

Run pod init, and open the .xcworkspace file to get started.

Add authorisation for the app to use the camera and microphone. To do this, open the Info.plist file at the root of your Xcode project and add NSCameraUsageDescription and NSMicrophoneUsageDescription.

For more information on requesting authorisation for media capture, check out this article from Apple.

Setting up Agora Video Calling

As is explained in the Agora Quickstart Guide, we must initialise the Agora engine, enable video, and join a channel:

There’s a little more we need to do to display videos. With AgoraUIKit_iOS, we can utilise the AgoraSingleVideoView class, which takes care of most of the video functionality for us.

All the video feeds will be stored in videoFeeds, which is a map of [UInt: AgoraSingleVideoView], where UInt is the RTC ID associated with the user (0 for local user). Add this property to your ViewController declaration.

This method will create an instance of AgoreSingleVideoView given a user ID, set up local or remote video for that user, and store it in videoFeeds

Now we need to add the local user’s feed once we have joined the channel. And we need to catch incoming streams using the delegate method remoteVideoStateChangedOfUid:

We’ll add self.addUserVideo(with: 0) to the joinSuccess callback from the call to joinChannel.

The final step in setting up the initial video calling is organising the video feeds so we can see ourselves and the remote users. For simplicity, we will only display videos in a 2x2 grid:

Accessing In-Call Stats

We will use two delegate methods to get stats for the local and remote videos: localVideoStats and remoteVideoStats.

Your delegate extension may look like this now:

We will define updateStats soon. But first I’ll add the stats.statsViewText custom property in my sample. This property returns a few status properties as a String:

extension AgoraRtcRemoteVideoStats {
var statsViewText: String {
Received Bitrate: \(self.receivedBitrate)
Packet Loss Rate: \(self.packetLossRate)
Active Time: \(self.totalActiveTime)
Output Frame Rate: \(self.decoderOutputFrameRate)
Frame Dimensions: \(self.width)x\(self.height)
extension AgoraRtcLocalVideoStats {
var statsViewText: String {
Encoded Bitrate: \(self.encodedBitrate)
Sent Target Bitrate: \(self.sentTargetBitrate)
Packet Loss Rate: \(self.txPacketLossRate)
Capture Frame Rate: \(self.captureFrameRate)
Frame Dimensions: \(self.encodedFrameWidth)x\(self.encodedFrameHeight)

These are just some of the properties I have chosen to present, but there are many more. See the class references AgoraRtcLocalVideoStats and AgoraRtcRemoteVideoStats for a list of all properties.

Now for the updateStats method:

The camera feeds in the screenshot have been blurred to make the text more legible in this example.

If you want to add similar stats to your own app, you might want to display the text in different ways. For example, you may want to monitor the received bitrate value and show a small icon on a user when the value goes below a certain threshold. This would let everyone else know that there may be some issue with that remote user’s internet connection.

More Stats

A few more options for stats are offered as part of the Agora Video Streaming SDK, including local/remote audio stats and channel stats.

Channel stats can be found in the reportRtcStats delegate method, which returns a stats class AgoraChannelStats. Using this stats object, you can check for the CPU usage of your app, the total system CPU usage, the last-mile delay, the memory usage of your app, and many more properties.


You can try out the code in a prebuilt sample on GitHub:


That is how we can listen, monitor, and display the in-call statistics for our video experience. You can even build functions to log or react to change in these values to deliver an exceptional user experience.

Other Resources

For more information about building applications using Agora Video and Audio Streaming SDKs, take a look at the Agora Video Call Quickstart Guide and Agora API Reference.

I also invite you to join the Developer Slack community.




Excited about all things Augmented Reality! Developer Evangelist at

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

How to sort null values last with Laravel Eloquent

Smoke Testing vs Sanity Testing

Beyond the Basics: Protect your code and business logic with Runtime Encryption Plugins

VM Image Lifecycle Management & Patching

Ruby Plotting with Galaaz: An example of tightly coupling Ruby and R in GraalVM

Making use of boto3 “out-of-the-box” DynamoDB Serializers

I Have Been a Polyglot Programmer For Most of My Career


Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Max Cobb

Max Cobb

Excited about all things Augmented Reality! Developer Evangelist at

More from Medium

Add Touch ID & Face ID in Swift

Build an Animated Custom Tab Bar in Your iOS Apps

Set Up a Basic Bar Chart Using FLCharts (Swift)

FLCharts for iOS written in Swift

How to preview UIViewControllers using SwiftUI