Intro

As you’re probably already tired of hearing, 2020 has been an unprecedented year for online video. With this surge of new users and use cases, comes an incredible diversity of devices, networks, and operating conditions. More and more people are engaging with real-time video products, and they are doing it in new and novel ways.

The other side of this proliferation is that those who are building real-time video products are bound to experience more complex debugging scenarios. Maybe you have a house full of college students doing e-learning over spotty WiFi, a busy parent checking in on their child’s remote school session from their phone, or large groups of people watching a live concert from all over the world. Developers need the ability to diagnose the real-world problems of their users so that they are empowered to fix them as quickly as possible.

What’s new?

In service of solving these problems, and accelerating developer time to value, we are very excited to announce the launch of the /logs API endpoint. In addition to our new dashboard features which provide similar insights, you will now have the ability to dive even deeper into the underlying data. It also means you can use this data in your existing systems of record for logging and metrics. To show what is possible with this data, we built Daily Call Explorer, a Google Colab hosted IPython Jupyter notebook.

Captain’s log

At the heart of our latest release is the /logs endpoint. It allows you to dig into call logs and metrics to truly understand participant experience. Call logs provide a record of the events that take place during a call. Call metrics are WebRTC stats that help you understand and characterize video call quality and performance.

To get started, all you need is an API key, which you will find on your Daily dashboard.

Let’s curl the endpoint to get some sample data:

curl --request GET \
  --header 'authorization: Bearer $YOUR_API_KEY \
  --url 'https://api.daily.co/v1/logs?mtgSessionId=7a99abff-0047-4b27-c6c1-49b4ec46f1de&userSessionId=4fde3659-71f6-4c28-9a90-e4c3f08ca611&includeMetrics=1'

Note: we’re providing mtgSessionId, userSessionId, and includeMetrics parameters. Read more about available parameters here.

The response will look something like this:

{
   "logs":[
      {
         "time":"2020-09-29T18:01:41.791Z",
         "clientTime":"2020-09-29T18:01:26.529Z",
         "message":"participant joined",
         "mtgSessionId":"7a99abff-0047-4b27-c6c1-49b4ec46f1de",
         "userSessionId":"4fde3659-71f6-4c28-9a90-e4c3f08ca611",
         "peerId":"6cfbb8ec-fdbe-49f4-8a7d-39167f5c7745",
         "domainName":"markstaging",
         "level":1,
         "code":8010
      },
      "..."
   ],
   "metrics":[
      {
         "time":"2020-09-29T18:20:07.094Z",
         "clientTime":"2020-09-29T18:20:05.446Z",
         "mtgSessionId":"7a99abff-0047-4b27-c6c1-49b4ec46f1de",
         "userSessionId":"4fde3659-71f6-4c28-9a90-e4c3f08ca611",
         "roomName":"logger",
         "domainName":"markstaging",
         "videoRecvPacketLoss":0,
         "userRecvBitsPerSecAvg":1038950,
         "userRecvBitsPerSecMax":1248527,
         "userRecvBitsPerSecMin":702322,
         "userSentBitsPerSecAvg":1059720,
         "userSentBitsPerSecMax":1087262,
         "userSentBitsPerSecMin":1039595,
         "metrics":{
            "6cfbb8ec-fdbe-49f4-8a7d-39167f5c7745":{
               "transport":{
                  "bitsSentPerSecAvg":1059720.499904,
                  "bitsSentPerSecMax":1087262.194208,
                  "bitsSentPerSecMin":1039595.375608,
                  "recvPacketsLostPct":0,
                  "bitsReceivedPerSecAvg":1038950.203992,
                  "bitsReceivedPerSecMax":1248527.009696,
                  "bitsReceivedPerSecMin":702321.618656
               },
               "inbound-cam-audio":{
                  "jitterAvg":0.0057,
                  "jitterMax":0.039,
                  "packetsLostPct":0,
                  "bitsReceivedPerSecAvg":13496.145309,
                  "packetsReceivedPerSecMax":50.029943,
                  "packetsReceivedPerSecMin":31.997887,
                  "jitterBufferDelayPerEmittedCountAvg":0.052572
               },
               "inbound-cam-video":{
                  "packetsLostPct":0,
                  "qpsumPerFrameMax":32.174712,
                  "qpsumPerFrameMin":32.133797,
                  "bitsReceivedPerSecAvg":932571.759686,
                  "decodeTimePerFrameAvg":0.003017,
                  "packetsReceivedPerSecMax":142.475773,
                  "packetsReceivedPerSecMin":79.994717,
                  "jitterBufferDelayPerEmittedCountAvg":0.048182
               },
               "outbound-cam-audio":{
                  "bitsSentPerSecAvg":14000.112027,
                  "packetsSentPerSecMax":50.029943,
                  "packetsSentPerSecMin":49.98208,
                  "remoteInbound-jitterAvg":0.00264,
                  "remoteInbound-jitterMax":0.002771,
                  "remoteInbound-packetsLostTotal":0,
                  "remoteInbound-roundTripTimeAvg":0.0042
               },
               "outbound-cam-video":{
                  "qpsumPerFrameMax":39.631361,
                  "qpsumPerFrameMin":39.469008,
                  "bitsSentPerSecAvg":987876.640172,
                  "packetsSentPerSecMax":130.953051,
                  "packetsSentPerSecMin":123.498025,
                  "encodeTimePerFrameAvg":0.004297,
                  "remoteInbound-jitterAvg":0.009012,
                  "remoteInbound-jitterMax":0.010833,
                  "remoteInbound-packetsLostTotal":0,
                  "remoteInbound-roundTripTimeAvg":0.0055
               }
            }
         },
         "isSFU":false
      },
      "..."
   ]
}

You will notice two distinct top-level properties here: logs and metrics (included because of the includeMetrics=1 parameter).

Let’s look at those in a bit more detail. First up: logs.

Each of the items will have the following properties:

time UTC time of collection
clientTime. UTC time of client reports
message Short description of a discrete event or error
mtgSessionId Session’s unique ID
userSessionId User’s unique session ID
peerId Peer connection’s `userSessionId`
domainName Domain hosting the call
level Log level (error:0, info:1, debug:2)
code Optional (used for internal storage)

Going into the specifics of each message type is outside the scope of this post but you can read more here if you’re curious.

Metrics reporting for duty

Next up, let’s look at metrics.

Each json blob in the array will have the following properties:

time UTC time of collection
clientTime UTC time client reports
userSessionId User’s unique session ID
mtgSessionId Session’s unique ID
roomName Room name
DomainName Domain hosting the call
VideoRecPacketLoss % packet loss (worst value from all pairs)
userRecvBitsPerSecAvg Avg receive transport bitrate (bps)
userRecvBitsPerSecMax Max receive transport bitrate (bps)
userRecvBitsPerSecMin Min receive transport bitrate (bps)
userSentBitsPerSecAvg Avg send transport bitrate (bps)
userSentBitsPerSecMax Max send transport bitrate (bps)
userSentBitsPerSecMin Min send transport bitrate (bps)
metrics JSON blob
isSFU Call mode (boolean) (SFU or P2P)

Note for the child metrics blob there will be a slightly different structure depending on the call mode. The example response above represents p2p mode. You can see a sample SFU mode response here.

Now that you’re familiar with all of the data at your disposal, let’s look at how we can use it.

Become an explorer

As an example of a way to harness the call metrics information for yourself, we've built a sample app — the Daily Call Explorer, a Google Colab hosted IPython Jupyter notebook.

You can use this sample app to see your track level information between participants and their candidate-pair. Open the Daily Call Explorer and follow the instructions at the top to get started.

To make sure it works for everyone, we’ve made it read-only. If you’d like to change the code to inspect or extend the tool, please make a copy of the notebook using File→Save a copy….

We will be adding track level data to the Daily Dashboard in the future, but this notebook will continue to serve as a great introduction to using our API to find highly detailed logs and metrics about your calls.

Troubleshooting

If for some reason you’re not seeing logs and call stats for a particular user, it’s possible that their browser is using an older bundle of our call machine code. To confirm, they should see logging and telemetry enabled in the console when the call starts. If they are not seeing this, have them clear their cache and try again, and if that still doesn’t work then please reach out.

What’s next?

We hope that access to all of this logging and metrics data empowers you to continuously improve your customer experiences. Perhaps you can integrate it into your existing logging and metrics infrastructure. If you’re just getting started there, we will have content coming soon to guide you through that process.