Segmenting your audience

For sure it’s interesting to look at global metrics like the total number of users and impressions, but it’s even more valuable to analyse these metrics for certain segments of your audience. Segmented metrics give you insights about who uses your service where and how.

In this article you’ll get an overview of how you can segment your audience using the Bitmovin Analytics API.

By location

A straightforward segment are users watching your videos in certain countries. Before we start, make sure you’ve set up the Bitmovin JavaScript client according to the Getting started guide.

If everything works, let’s count the impressions from Portugal:
You can pass any 2-letter country code to the country filter.

queryBuilder  
  .count('IMPRESSION_ID')  
  .between(fromDate, toDate)  
  .filter('COUNTRY', 'EQ', 'PT')  
  .filter('VIDEO_STARTUPTIME', 'GT', 0)
  .query()

If you’re interested in more specific results, we can also pass a region code:

queryBuilder  
  .count('IMPRESSION_ID')  
  .between(fromDate, toDate)  
  .filter('COUNTRY', 'EQ', 'US')  
  .filter('REGION', 'EQ', 'CA')  
  .filter('VIDEO_STARTUPTIME', 'GT', 0)
  .query()

This will count all the impressions from California. Note that region codes only make sense in the scope of a country, as the same code could be defined for a region of another country as well. Therefore you should always combine the region with a COUNTRY filter.

It’s even possible to query for single cities:

queryBuilder  
  .count('IMPRESSION_ID')  
  .between(fromDate, toDate)  
  .filter('COUNTRY', 'EQ', 'FR')  
  .filter('CITY', 'EQ', 'paris')  
  .filter('VIDEO_STARTUPTIME', 'GT', 0)
  .query()

Although not mandatory, it’s a good idea to query for the country as well. Otherwise your result will include impressions from the around 30 other cities named Paris around the world. Please only pass the english version of a city’s name and always convert it to lowercase.

By URL

If your video platform runs on several domains, you can also segment your users by the domain they visited:

queryBuilder  
  .count('IMPRESSION_ID')  
  .between(fromDate, toDate)  
  .filter('DOMAIN', 'EQ', 'bitmovin.com')  
  .filter('VIDEO_STARTUPTIME', 'GT', 0)
  .query()

This query is particularly useful when you test your service locally or on a separate staging domain, as you can filter out these impressions easily for your production metrics:

queryBuilder  
  .count('IMPRESSION_ID')  
  .between(fromDate, toDate)  
  .filter('DOMAIN', 'NE', 'localhost')  
  .filter('DOMAIN', 'NE', 'mystagingdomain.com')  
  .filter('VIDEO_STARTUPTIME', 'GT', 0)
  .query()

If your video platform is organised hierarchically and this hierarchy is reflected in your URLs, you can utilise it for your queries as well:

queryBuilder  
  .count('IMPRESSION_ID')  
  .between(fromDate, toDate)  
  .filter('PATH', 'CONTAINS', '/sports/')  
  .filter('VIDEO_STARTUPTIME', 'GT', 0)
  .query()

This query counts all video impression of videos accessed through a path containing /sports/ – including the slashes. So impressions of videos at https://mysite.com/videos/sports/soccer would be counted, but no impressions of videos at https://mysite.com/videos/news

You can use the same technique to exclude certain paths, for example your admin area:

queryBuilder  
  .count('IMPRESSION_ID')  
  .between(fromDate, toDate)  
  .filter('PATH', 'NOTCONTAINS', '/admin')
  .filter('VIDEO_STARTUPTIME', 'GT', 0)
  .query()

By device

Bitmovin Analytics tracks several attributes which give you important cues about the devices your audience uses to watch videos on.

Screen width and screen height are important indicators for the kind of device. For example, devices with less than 500 pixels width and less than 900 pixels height are most likely smartphones. Therefore we can count the number of impressions from smartphones like this:

queryBuilder  
  .count('IMPRESSION_ID')  
  .between(fromDate, toDate)  
  .filter('SCREEN_WIDTH', 'LT', 500)  
  .filter('SCREEN_HEIGHT', 'LT', 900) 
  .filter('VIDEO_STARTUPTIME', 'GT', 0)
  .query()

To narrow down the query to only Android phones, let’s filter for the operating system as well:

queryBuilder  
  .count('IMPRESSION_ID')  
  .between(fromDate, toDate)  
  .filter('SCREEN_WIDTH', 'LT', 500)  
  .filter('SCREEN_HEIGHT', 'LT', 900)  
  .filter('OPERATINGSYSTEM', 'EQ', 'Android')  
  .filter('VIDEO_STARTUPTIME', 'GT', 0)
  .query()

A full list of platforms supported and how your traffic is distributed:

queryBuilder  
  .count('IMPRESSION_ID')  
  .between(fromDate, toDate)  
  .groupBy('PLATFORM')  
  .filter('VIDEO_STARTUPTIME', 'GT', 0)
  .query()  
  .then(console.log)

// Response

 [
  ["web", 1000],
  ["android", 5000],
  ["androidTV", 1500],
  ["tvOS", 1000],
  ["iOS", 4000]
],

Identifying your iPhone users is even easier:

queryBuilder  
  .count('IMPRESSION_ID')  
  .between(fromDate, toDate)  
  .filter('DEVICE_TYPE', 'EQ', 'iPhone')  
  .filter('VIDEO_STARTUPTIME', 'GT', 0)
  .query()

You can also use the DEVICE_TYPE with Android to query for specific devices:

queryBuilder  
  .count('IMPRESSION_ID')  
  .between(fromDate, toDate)  
  .filter('DEVICE_TYPE', 'EQ', 'Moto Z Play')  
  .filter('VIDEO_STARTUPTIME', 'GT', 0)
  .query()

For a full list of devices your audience uses to watch videos, group the impressions by device type:

queryBuilder  
  .count('IMPRESSION_ID')  
  .between(fromDate, toDate)  
  .groupBy('DEVICE_TYPE')  
  .filter('VIDEO_STARTUPTIME', 'GT', 0)
  .query()  
  .then(console.log)

// Response

[  
  ["iPad", 30],  
  ["PlayStation 4", 43],  
  ["Pixel", 1],  
  ["Samsung SM-T280", 1],  
  ["Samsung SMART-TV", 1],  
  ["Nexus 5", 5],  
  ["iPhone", 58],  
  ["LG-K220", 8],  
  ["Asus Z00LD", 12],  
  ["Lenovo P2a42", 8],  
  ["Moto G Play", 1],  
  ["Other", 13535],  
  ["HTC Desire 816G dual sim", 2],
],  

By browser

Another way to segment your users is by browser. You can query for video impressions in Chrome like this:

queryBuilder  
  .count('IMPRESSION_ID')  
  .between(fromDate, toDate)  
  .filter('BROWSER', 'CONTAINS', 'Chrome')  
  .filter('VIDEO_STARTUPTIME', 'GT', 0)
  .query()

Why did we use CONTAINS instead of EQ? Depending on the device, browsers may have different names. Chrome is called “Chrome”, “Chrome Mobile iOS” or “Chrome Mobile”, Firefox is called “Firefox” or “Firefox Mobile”, Safari is called “Safari”, “Mobile Safari” or “Mobile Safari UI/WKWebView”, and so on. Unless you’re interested in these details, you should use a CONTAINS query with the general browser name.

It’s even possible to query for a specific browser version:

queryBuilder  
  .count('IMPRESSION_ID')  
  .between(fromDate, toDate)  
  .filter('BROWSER', 'CONTAINS', 'Chrome')  
  .filter('BROWSER_VERSION_MAJOR', 'EQ', '62')  
  .filter('VIDEO_STARTUPTIME', 'GT', 0)
  .query()

To find out all browsers people use to watch videos on your platform, group by the browser in your query:

queryBuilder  
  .count('IMPRESSION_ID')  
  .between(fromDate, toDate)  
  .groupBy('BROWSER')  
  .filter('VIDEO_STARTUPTIME', 'GT', 0)
  .query()  
  .then(console.log)

// Response

[
  ["Opera", 233],  
  ["Chrome", 9875],  
  ["Safari", 579],  
  ["UC Browser", 4],  
  ["Chrome Mobile iOS", 10],  
  ["Mobile Safari UI/WKWebView", 8],  
  ["Chrome Mobile", 123],  
  ["Samsung Internet", 10],  
  ["Edge", 250],  
  ["Other", 43],  
  ["Mobile Safari", 68],  
  ["IE", 62],  
  ["Vivaldi", 3],  
  ["Firefox Mobile", 2],  
  ["Firefox", 1821],  
  ["Chromium", 47],
]

By player size

When you offer your users to watch videos in full screen, do they really do it? All it takes to find out is a single query:

queryBuilder  
  .count('IMPRESSION_ID')  
  .between(fromDate, toDate)  
  .filter('SIZE', 'EQ', 'FULLSCREEN')  
  .filter('VIDEO_STARTUPTIME', 'GT', 0)
  .query()

To count only windowed impressions, use

queryBuilder  
  .count('IMPRESSION_ID')  
  .between(fromDate, toDate)  
  .filter('SIZE', 'EQ', 'WINDOW')  
  .filter('VIDEO_STARTUPTIME', 'GT', 0)
  .query()

If you add both total numbers, most likely the sum will be higher than the total number of impressions. That’s because usually users can toggle between windowed and full screen mode. If they toggle while watching a video, the impression will be counted as both windowed and full screen.

To be more specific, you can also query for the video window dimensions directly:

queryBuilder  
  .count('IMPRESSION_ID')  
  .between(fromDate, toDate)  
  .filter('VIDEO_WINDOW_WIDTH', 'EQ', 800)  
  .filter('VIDEO_WINDOW_HEIGHT', 'EQ', 450)  
  .filter('VIDEO_STARTUPTIME', 'GT', 0)
  .query()

By many other attributes

There is a plethora of other possibilities to segment your audience. For example, you could get only impressions from videos sent to Chromecast with .filter('IS_CASTING', 'EQ', 1) or impressions of live streams with .filter('IS_LIVE', 'EQ', 1).

For an extensive list of filter options, please consult the Bitmovin Analytics API docs.