Tips for working with api.video analytics data

Tips for working with api.video analytics data

Get some tips about data structure and working with api.video analytics data. Code samples are in Python but you can apply the information about the data structures to any other language you want to use.

Erikka Innes

March 30, 2021

You may want to grab analytics data from api.video and then visualize it different ways. Today we'll take a look at the data you can use, what that data looks like, and the code snippets for data retrieval. api.video has three sets of analytics you can collect:

Everything is set up so you can pull details at a granular level - so for each request to the API, you would choose the video, live stream, or player you want details about, and send an individual request for information about that that asset. If you want to pull data for an individual asset, or multiple assets, the first thing you need to do is get a list of those assets.

You can also see a fun project using api.video analytics data over at Observable. We made a notebook that shows where all our live stream viewers watch from.

Get All Videos, Live Streams, or Players

The first step in using your analytics data, is to find out what you have available to analyze. You're going to want to know what videos, live streams, and players you have.

  1. Authenticate with your API key and get a token.
  2. Use the token with the List all videos, List all live streams, or List all players endpoint to get all listings for everything in that category.

The code for this part looks like this:

import requests
import json

# Get api.video token

url = "https://ws.api.video/auth/api-key"

payload = {"apiKey": "api key here"}
headers = {
    "Accept": "application/json",
    "Content-Type": "application/json"
}

response = requests.request("POST", url, json=payload, headers=headers)
response = response.json()
token = response.get("access_token")

# Retrieve the live-streams and write to file

url = "https://ws.api.video/live-streams"

querystring = {"currentPage":"1","pageSize":"25"}

headers = {
    "Accept": "application/json",
    "Authorization": token
}

response = requests.request("GET", url, headers=headers, params=querystring)

response = response.json()

with open("live_stream.json", "w") as live:
    json.dump(response, live)

# Retrieve the VODs and write to file

url = "https://ws.api.video/videos"

querystring = {"currentPage":"1","pageSize":"25"}

headers = {
    "Accept": "application/json",
    "Authorization": token
}

response = requests.request("GET", url, headers=headers, params=querystring)

response = response.json()

with open("vod.json", "w") as vod:
    json.dump(response, vod)

# Retrieve all players and write to file

url = "https://ws.api.video/players"

querystring = {"currentPage":"1","pageSize":"25"}

headers = {
    "Accept": "application/json",
    "Authorization": token
}

response = requests.request("GET", url, headers=headers, params=querystring)

response = response.json()

with open("players.json", "w") as players:
    json.dump(response, players)

In this sample, we went through every endpoint and got a complete list of assets. Then, so we don't have to keep going back to the API for this information, we output each set of details to a .json file. You probably won't want to necessarily save this, but for learning or browsing, it's great to be able to open the file and see this data you'll be working with. If you want to experiment with retrieving data from these files and converting to different formats, these can be helpful.

Data Structure for a Live Stream

If you were to retrieve a single live stream, it would contain the data shown here, and a pagination section in case you have so many entries you need to retrieve multiple pages of asset listings.

{
    "data": [
        {
            "liveStreamId": "li312mYKSgQ6xs7taUeSaEKr",
            "createdAt": "2020-01-31T10:17:47+00:00",
            "updatedAt": "2020-09-23T17:58:08+00:00",
            "streamKey": "32287931-229e-42cf-b5f9-e91bcc1f7332",
            "name": "Live Stream",
            "public": true,
            "record": true,
            "broadcasting": false,
            "assets": {
                "iframe": "<iframe src=\"https://embed.api.video/live/li312mYKSgQ6xs7taUeSaEKr\" width=\"100%\" height=\"100%\" frameborder=\"0\" scrolling=\"no\" allowfullscreen=\"true\"></iframe>",
                "player": "https://embed.api.video/live/li312mYKSgQ6xs7taUeSaEKr",
                "hls": "https://live.api.video/li312mYKSgQ6xs7taUeSaEKr.m3u8",
                "thumbnail": "https://live.api.video/li312mYKSgQ6xs7taUeSaEKr/thumbnail.jpg"
            },
            "playerId": "ptSQlUSqn5KIn9tGxlA88Q1"
        }
    ],
    "pagination": {
        "currentPage": 1,
        "currentPageItems": 15,
        "pageSize": 25,
        "pagesTotal": 1,
        "itemsTotal": 15,
        "links": [
            {
                "rel": "self",
                "uri": "/live-streams?currentPage=1&pageSize=25"
            },
            {
                "rel": "first",
                "uri": "/live-streams?currentPage=1&pageSize=25"
            },
            {
                "rel": "last",
                "uri": "/live-streams?currentPage=1&pageSize=25"
            }
        ]
    }
}

Data Structure for a Video

As with live streams, if you were to retrieve a single video, it would contain the data shown here. Notice there's a ton of videos - 608 to be exact, and the pagination section provides details for grabbing additional pages of data so you can get an exhaustive list of all assets if you need it.

{
    "data": [
       {
            "videoId": "vi54QrBFkhpNoUVObqkZVYF",
            "title": "Test create video",
            "description": "",
            "public": true,
            "panoramic": false,
            "mp4Support": true,
            "publishedAt": "2020-02-19T14:47:48+00:00",
            "createdAt": "2020-02-19T14:47:48+00:00",
            "updatedAt": "2020-02-19T14:47:48+00:00",
            "tags": [],
            "metadata": [],
            "source": {
                "type": "upload",
                "uri": "/videos/vi54QrBFkhpNoUVObqkZVYF/source"
            },
            "assets": {
                "iframe": "<iframe src=\"https://embed.api.video/vod/vi54QrBFkhpNoUVObqkZVYF\" width=\"100%\" height=\"100%\" frameborder=\"0\" scrolling=\"no\" allowfullscreen=\"true\"></iframe>",
                "player": "https://embed.api.video/vod/vi54QrBFkhpNoUVObqkZVYF",
                "hls": "https://cdn.api.video/vod/vi54QrBFkhpNoUVObqkZVYF/hls/manifest.m3u8",
                "thumbnail": "https://cdn.api.video/vod/vi54QrBFkhpNoUVObqkZVYF/thumbnail.jpg"
            }
        }
    ],
    "pagination": {
        "currentPage": 1,
        "currentPageItems": 25,
        "pageSize": 25,
        "pagesTotal": 25,
        "itemsTotal": 608,
        "links": [
            {
                "rel": "self",
                "uri": "/videos?currentPage=1&pageSize=25"
            },
            {
                "rel": "first",
                "uri": "/videos?currentPage=1&pageSize=25"
            },
            {
                "rel": "next",
                "uri": "/videos?currentPage=2&pageSize=25"
            },
            {
                "rel": "last",
                "uri": "/videos?currentPage=25&pageSize=25"
            }
        ]
    }
}

Data Structure for a Player

For players you get details about how each one is customized. It has the same pagination feature as the other data structures. Because you don't use this information to retrieve session details, it's more for informational purposes only if you wanted to know about the players you have.

{
   "data": [
        {
            "playerId": "ptSQlUSqn5KIn9tGxlA88Q1",
            "createdAt": "2020-08-25T14:27:08+00:00",
            "updatedAt": "2020-08-26T17:42:55+00:00",
            "assets": {
                "logo": "https://cdn.api.video/player/ptSQlUSqn5KIn9tGxlA88Q1/logo.png",
                "link": "https://twitter.com/uwbuckybadger"
            },
            "shapeMargin": 0,
            "shapeRadius": 0,
            "shapeAspect": "flat",
            "shapeBackgroundTop": "rgba(50, 50, 50, .7)",
            "shapeBackgroundBottom": "rgba(50, 50, 50, .8)",
            "text": "rgba(218,223,225, 1)",
            "link": "rgba(100,101,105, 1)",
            "linkHover": "rgba(249,249,249, 1)",
            "linkActive": "rgba(197,5,12,1)",
            "trackPlayed": "rgba(155,0,0, .95)",
            "trackUnplayed": "rgba(218,223,225, .35)",
            "trackBackground": "rgba(218,223,225, .2)",
            "backgroundTop": "rgba(197,5,12, .7)",
            "backgroundBottom": "rgba(247,247,247, .7)",
            "backgroundText": "rgba(197,5,12, 1)",
            "enableApi": true,
            "enableControls": true,
            "forceAutoplay": true,
            "hideTitle": false,
            "forceLoop": true
        }
    ],
    "pagination": {
        "currentPage": 1,
        "currentPageItems": 5,
        "pageSize": 25,
        "pagesTotal": 1,
        "itemsTotal": 5,
        "links": [
            {
                "rel": "self",
                "uri": "/players?currentPage=1&pageSize=25"
            },
            {
                "rel": "first",
                "uri": "/players?currentPage=1&pageSize=25"
            },
            {
                "rel": "last",
                "uri": "/players?currentPage=1&pageSize=25"
            }
        ]
    }
}

Retrieve Sessions

The next part of retrieving your data is to grab session information. Because the analytics endpoints are set up to be granular, you need the unique live stream, video, or player ID to use with the associated endpoint. Then you can retrieve details about all sessions for that endpoint. Live stream and video sessions come back using the same structure. Players are different (as you'll see).

The code to retrieve details about one asset for video or live stream would be:

import requests
import json

# Get api.video token

url = "https://ws.api.video/auth/api-key"

payload = {"apiKey": "api key here"}
headers = {
    "Accept": "application/json",
    "Content-Type": "application/json"
}

response = requests.request("POST", url, json=payload, headers=headers)
response = response.json()
token = response.get("access_token")

# Retrieve all session details for one live stream

url = "https://ws.api.video/analytics/live-streams/liveStreamId"

querystring = {"currentPage":"1","pageSize":"25"}

headers = {
    "Accept": "application/json",
    "Authorization": token
}

response = requests.request("GET", url, headers=headers, params=querystring)

response = response.json()

with open("live_stream_session_data.json", "w") as ls:
    json.dump(response, ls)

# Retrieve all session details for one video

url = "https://ws.api.video/analytics/videos/videoId"

querystring = {"currentPage":"1","pageSize":"25"}

headers = {
    "Accept": "application/json",
    "Authorization": token
}

response = requests.request("GET", url, headers=headers, params=querystring)

response = response.json()

with open("vod_session_data.json", "w") as vod:
    json.dump(response, vod)

# Retrieve all details of events that occurred in one session for a player

url = "https://ws.api.video/analytics/sessions/sessionId/events"

headers = {
    "Accept": "application/json",
    "Authorization": token
}

response = requests.request("GET", url, headers=headers, params=querystring)

response = response.json()

with open("player_session_data.json", "w") as player:
    json.dump(response, player)

Data Structure for Live Stream and Video

Live streams and videos bring back information with the same format. Something to remember is when the information comes back, it will not include the title of your live stream or video, or its type. If you were to get back one single session for a live stream or video, it would come back like this:

{
    "data": [
        {
            "session": {
                "sessionId": "ps2ThzKCMbrmT9ntv1AC4mVV",
                "loadedAt": "2021-02-05T14:46:34+00:00",
                "endedAt": "2021-02-05T14:46:37+00:00"
            },
            "location": {
                "country": "United Kingdom",
                "city": "Hitchin"
            },
            "referrer": {
                "url": "https://go.api.video/",
                "medium": "unknown",
                "source": "unknown",
                "searchTerm": "unknown"
            },
            "device": {
                "type": "computer",
                "vendor": "unknown",
                "model": "Other"
            },
            "os": {
                "name": "Mac OS X",
                "shortname": "Mac OS X",
                "version": "11.0.1"
            },
            "client": {
                "type": "unknown",
                "name": "Chrome",
                "version": "88.0.4324"
            }
        }
    ],
    "pagination": {
        "currentPage": 1,
        "currentPageItems": 8,
        "pageSize": 25,
        "pagesTotal": 1,
        "itemsTotal": 8,
        "links": [
            {
                "rel": "self",
                "uri": "/analytics/videos/vi1UQBDAMqAPCRxB3dmw1thc?currentPage=1&pageSize=25"
            },
            {
                "rel": "first",
                "uri": "/analytics/videos/vi1UQBDAMqAPCRxB3dmw1thc?currentPage=1&pageSize=25"
            },
            {
                "rel": "last",
                "uri": "/analytics/videos/vi1UQBDAMqAPCRxB3dmw1thc?currentPage=1&pageSize=25"
            }
        ]
    }
}

Data Structure for Player

Because you are reviewing session details on a player for a particular video or live stream, you may want to note this in your data at some point. The returned data for a session doesn't include details about what video or live stream it's for beyond repeating the session ID in the pagination URLs.

{
    "data": [
        {
            "type": "ready",
            "emittedAt": "2021-02-05T14:46:34+00:00",
            "at": 0
        },
        {
            "type": "play",
            "emittedAt": "2021-02-05T14:46:36+00:00",
            "at": 0
        },
        {
            "type": "pause",
            "emittedAt": "2021-02-05T14:46:37+00:00",
            "at": 1
        }
    ],
    "pagination": {
        "currentPage": 1,
        "currentPageItems": 3,
        "pageSize": 25,
        "pagesTotal": 1,
        "itemsTotal": 3,
        "links": [
            {
                "rel": "self",
                "uri": "/analytics/sessions/ps2ThzKCMbrmT9ntv1AC4mVV/events?currentPage=1&pageSize=25"
            },
            {
                "rel": "first",
                "uri": "/analytics/sessions/ps2ThzKCMbrmT9ntv1AC4mVV/events?currentPage=1&pageSize=25"
            },
            {
                "rel": "last",
                "uri": "/analytics/sessions/ps2ThzKCMbrmT9ntv1AC4mVV/events?currentPage=1&pageSize=25"
            }
        ]
    }
}

Tips for Handling Data

This section includes some tips for handling your analytics data.