Video Completion Funnel

The purpose of this guide is to show you how you can use Keen to measure video play depth using a funnel query. We also show how to use some simple math to determine “how much was seen” or “how far” into the video viewers made it on average.

This guide is focused specifically on analyzing play depth events. Checkout our Video Tracking Guide for details on how to track other video engagements like play, pause, etc. Keen allows you to record data on plays, usage data, and other engagements on various video platforms such as: Facebook, YouTube, Video.js, Vimeo, and HTML5.

Video Completion Funnels

A video completion funnel provides an estimation of how engaging a given piece of video content is.

This guide shows how to model such events for sending to Keen, and how to build a funnel query to gather the results.

In most players, the way to determine “how far” into the video we are is through some simple math:

For example, if the video is 350 seconds long, then the exact second-level bechmark of the…

  • 0% completion occurs at 0s into the video
  • 25% completion is Math.floor(0.25*350) = 87s into the video
  • 50% completion is Math.floor(0.5*350) = 175s into the video
  • 75% completion is Math.floor(0.75*350) = 262s into the video
  • 100% completion is 350s into the video

Each time the player advances, we compare the current second to the benchmarks above, and fire a special event to Keen.

This is different in every player, so we’ll skip the instrumentation guide and get straight to the data model for these special new view_benchmark events:

// You'll want to make sure all your events have a content identifier, such as video.id.
// This is just an example variable name -- your player or your CMS likely has access to a string or integer identifier
// for the video currently in the player, so swap that in here for MY_VIDEO_ID:

client.extendEvents(function(){
  return {
    video: {
      'id':  MY_VIDEO_ID,   
    }
  }
})


// when the video starts playing, fire this event, as in our other examples:
client.recordEvent('video-interaction', {
  event_type: 'view_benchmark',
  benchmark: '0_percent'
});  

// when the player hits 25% of the way through the video, fire this one:
client.recordEvent('video-interaction', {
  event_type: 'view_benchmark',
  benchmark: '25_percent'
});  

// when the player hits 50% of the way through the video, fire this one:
client.recordEvent('video-interaction', {
  event_type: 'view_benchmark',
  benchmark: '50_percent'
 });  

// when the player hits 75% of the way through the video, fire this one:
client.recordEvent('video-interaction', {
  event_type: 'view_benchmark',
  benchmark: '75_percent'
});  

// when the video finishes playing, fire this one:
client.recordEvent('video-interaction', {
  event_type: 'view_benchmark',
  benchmark: '100_percent'
});

Now that the right benchmark data is being captured by Keen, you can use our Funnel API to build a query and our Dataviz SDK to visualize the results of that query, like so:


const client = new KeenAnalysis({
  projectId: 'PROJECT_ID',
  readKey: 'READ_KEY'
});

const chart = new KeenDataviz({
  // Required:
  container: '#MY_CHART_ELEMENT_ID', // querySelector
  type: 'funnel', //chart type
  // Optional:
  title: 'Video completion funnel: "Star Wars parody" timeframe: this_week',
  funnel: {
    percents: {
      show: true,
    },
  }
});

client
  .query({
    analysis_type: 'funnel',
    timeframe: 'this_week',
    steps: [
      {
        "actor_property": "video.id",
        "event_collection": "view_benchmark",
        filters: [
          {
            "operator": "eq",
            "property_name": "benchmark",
            "property_value": "0_percent"
          }
        ],
      },
      {
        "actor_property": "video.id",
        "event_collection": "view_benchmark",
        filters: [
          {
            "operator": "eq",
            "property_name": "benchmark",
            "property_value": "25_percent"
          }
        ],
      },
      {
        "actor_property": "video.id",
        "event_collection": "view_benchmark",
        filters: [
          {
            "operator": "eq",
            "property_name": "benchmark",
            "property_value": "50_percent"
          }
        ],
      },
      {
        "actor_property": "video.id",
        "event_collection": "view_benchmark",
        filters: [
          {
            "operator": "eq",
            "property_name": "benchmark",
            "property_value": "75_percent"
          }
        ],
      },
      {
        "actor_property": "video.id",
        "event_collection": "view_benchmark",
        filters: [
          {
            "operator": "eq",
            "property_name": "benchmark",
            "property_value": "100_percent"
          }
        ],
      },
    ]
  })
  .then(function(res) {
    // Handle the result
    chart
      .render(res);
  })
  .catch(function(err) {
    // Handle the error
    chart
      .message(err.message);
  });

And it will look something like this: