Tracking JW Player Events with SiteCatalyst

I recently had a client with a Drupal site who wanted to be able to track whether or not his site members were watching videos on his site completely, and also wanted to know at what point site members were leaving the videos. The client currently uses SiteCatalyst for analytics, and is using the JW Media Player. After a lot of research, I came across this blog post, which gave some terrific insight regarding how to connect events in the JW Media Player to Omniture. However, the code samples did not apply to SiteCatalyst. The author of the blog post suggested using the s.tl() function in the SiteCatalyst code to track events. After a lot more research, I finally came up with a solution that tracks when users play a video, pause a video, watch a video until the end, and if the user navigates away from the video before it has completed. The current time of the video is also tracked for each of these events. Using this methodology, one could easily extend the tracking to include other events such as seek and playlist events. My code is below.

// Detect if the user navigates away from the video
window.onbeforeunload = confirmExit;
var currentPosition = 0;
var currentVolume = 0;
var currentMute = false;
var currentState = "NONE";
var defaultState = "NONE";
var clipduration = 0;
var player = null;
var s = null;
 
function playerReady() {
  player = document.getElementById('swfobject-1');
  addListeners(player);
} 
 
function addListeners(player) {
  if (player) {
    addAllModelListeners(player);
  }
  else {
    setTimeout("addListeners("+player+")",100);
  }
}
 
function addAllModelListeners(player) {
  if (typeof player.addModelListener == "function") {
    player.addModelListener("BUFFER", "doNothing");
    player.addModelListener("ERROR", "doNothing");
    player.addModelListener("LOADED", "doNothing");
    player.addModelListener("META", "doNothing");
    player.addModelListener("STATE", "stateListener");
    player.addModelListener("TIME", "positionListener");
  }
}
 
function doNothing(obj) { 
  //nothing
}
 
function positionListener(obj) {
  currentPosition = obj.position;
  clipduration = obj.duration;
}
 
function stateListener(obj) {
  s = s_gi('sitecatalyst_id');
  currentState = obj.newstate;
  switch(obj.newstate) {
    case 'PLAYING':
      s.linkTrackVars="prop1,eVar1,events";
      s.linkTrackEvents="video_play";
      s.prop1=secondsToMinutes(currentPosition);
      s.eVar1=secondsToMinutes(currentPosition);
      s.events="video_play";
      s.tl(this,'o','Play Video');
      break;
    case 'PAUSED':         
      s.linkTrackVars="prop1,eVar1,events";
      s.linkTrackEvents="video_pause";
      s.prop1=secondsToMinutes(currentPosition);
      s.eVar1=secondsToMinutes(currentPosition);
      s.events="video_pause";
      s.tl(this,'o','Pause Video');
      break;
    case 'COMPLETED':
      s.linkTrackVars="prop1,eVar1,events";
      s.linkTrackEvents="video_complete";
      s.events="video_complete";
      s.tl(this,'o','Video Complete');
      break;
  }
}
 
function confirmExit() {
  if(currentState != 'COMPLETED') {
    s.linkTrackVars="prop1,eVar1,events";
    s.linkTrackEvents="video_leave";
    s.prop1=secondsToMinutes(currentPosition);
    s.eVar1=secondsToMinutes(currentPosition);
    s.events="video_leave";
    s.tl(this,'o','Leave Video');
    currentState = '';
  }
}
 
// Helper function to convert seconds to mm:ss format
function secondsToMinutes(seconds) {
  // Parse the minutes
  minVar = parseInt(Math.floor(seconds/60));
  minVar = minVar <10 ? '0' + minVar : minVar;
  // Parse the seconds
  secVar = parseInt(seconds % 60);              
  // The balance of seconds
  secVar = secVar <10 ? '0' + secVar : secVar;
  return minVar + ':' + secVar;
}

Resources:

Comments

Post new comment

  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • Lines and paragraphs break automatically.

More information about formatting options

About Erich

Erich is a web developer and a native New Englander who is passionate about life, the universe, and everything.

He is currently a senior Drupal developer at Harvard University, working on the IQSS OpenScholar project.  Prior to joining the team at Harvard, he was the engineering manager at CommonPlaces e-Solutions, in Hampstead, NH, contributing as the lead engineer on the Greenopolis.com and Twolia.com.

Erich is active in the Drupal community, having contributed modules and patches to the community. He presented at DrupalCon in Szeged Hungary, and co-presented at DrupalCon 2009 in Washington, DC.

Erich lives in New Hampshire with his wife, two sons, and two weimaraners.  When not writing code, Erich enjoys landscaping and woodworking.

Faceted search

Categories

Content type

Project types

Artwork Type

Artwork Tags

Recent comments

ebeyrent's tweets

Activity Stream

September 2, 2010

September 1, 2010

  • Twitter ebeyrent tweeted "@cpliakas LOL @webkenny as @acquia product" 11:23am #

August 31, 2010

  • Twitter ebeyrent tweeted "Dear @msnbc, I want to see the hurricane report, not a goddamn advertisement!! #thisisseriousshit" 12:08pm #
  • Twitter ebeyrent tweeted "Need a good D6 starter theme, looking at Blueprint, Fusion, and Omega. Any other recommendations? Preferences? #drupal" 11:35am #

August 30, 2010

  • Twitter ebeyrent tweeted "Having fun upgrading a D5 site to D6. #drupal" 3:05pm #
  • Twitter ebeyrent tweeted "@DrupalSnark Believe it or not, this was actually from a DrupalCamp presentation at Yale this weekend..." 11:38am #
  • Twitter ebeyrent tweeted "Today is an exciting and bittersweet milestone. My oldest son enters first grade..." 6:31am #

August 28, 2010

  • Twitter ebeyrent tweeted "Following @jjeff's presentation was like walking into the opera wearing my clown shoes. #drupalcampct" 4:38pm #
  • Twitter ebeyrent tweeted "Overlay module in #drupal 7 is awful. Don't use it. #drupalwtf" 4:31pm #
  • Twitter ebeyrent tweeted "Profile module in #drupal 7 doesn't use fields. Still. Don't use it. #drupalwtf" 4:29pm #
  • Twitter ebeyrent tweeted "Slides from the "Hack-proof Your Drupal App" presentation at #drupalcampct are online: http://bit.ly/9q9yRK" 4:19pm #
  • Twitter ebeyrent tweeted "@jjeff consults the orb at #drupalcampct" 2:42pm #
  • Twitter ebeyrent tweeted "Listening to @jjeff's presentation at #drupalcampct" 2:21pm #