YouTube Player Tracking Plugin v0.2w - Omniture SiteCatalyst

Ever wanted Omniture SiteCatalyst to track your embedded YouTube videos on your site? Not a bad idea and not too difficult to solve...

Update 2016-02-10: The new version with HTML5 support will be released in the next 1-2 weeks. Stay tuned and thanks for your interest!
 

Important note: The v0.2 plugin (and before) got broken by an "unintentional side effect of a recent change to the way the API escapes values". (see here - thanks to the unknown user for reporting it). Since I did not receive a word on when the update will be live, here's a workaround-plugin.
The current Youtube player encodes the callback we need to get informed about event changes. Part of it is the player ID. This means currently only a-z & 0-9 are allowed for the playerapiid to get the workaround working. If your playerapiid includes _ or . it will keep failing and you have to either rename your ID or wait for a fix from Youtube.

If you want to get an update once this is officially resolved or any other updates are released, drop me a short email.

Update Feb-03: the API from YouTube only got partly changed back. This means v0.2 and before will keep breaking. You MUST update to this workaround version to get it working.
If you're already using the v0.3beta, send me an email.

Note to v15 Users: Since v15 media tracking is syntax-compatible to v14, the plugins work for both SiteCatalyst versions. But please make sure to have a correct media plugin for your H-Code, configure it properly and test your implementation.

 

Automatic Tracking - using the plugin:

The steps you need to do:

  1. Add the Omniture Media tracking module to your s_code.js (or similar). You need to have code version of H.15.1 or newer. You'll get this Media module from your Account Manager, Implementation Consultant or ClientCare.
    A sample SC14 configuration could be:
     
    s.loadModule("Media");
    s.Media.autoTrack=false;
    s.Media.trackWhilePlaying=true;
    s.Media.trackSeconds=30;
    s.Media.trackVars="None";
    s.Media.trackEvents="None";

    which would send the tracking information every 30s to Omniture, not track any custom props/eVars and not track any other players like Windows Media Player, QuickTime Player or RealPlayer. Check the Omniture implementation manual for your desired configuration.
    If you're using SiteCatalyst v15 make sure you have the updated media plugin and use the corresponding configuration for it.

  2. make sure you embed the video with the API turned on e.g. http://www.youtube.com/v/8pB5sRsX5OU?fs=1&rel=0&enablejsapi=1&playerapiid=myytplayer

    If you use SWFObject (which I strongly suggest):

    <div id="ytcontainer"></div>
    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject.js"></script>
    <script type="text/javascript">
        swfobject.embedSWF("http://www.youtube.com/v/8pB5sRsX5OU?fs=1&rel=0&enablejsapi=1&playerapiid=myytplayer",
            "ytcontainer", "425", "356", "8", null, null,
            {allowscriptaccess:"always",allowfullscreen:"true"}, {id:"myytplayer"});
    </script>


    where ytcontainer is your <div>-tag you want to have the player in. You can/should host the swfobject.js on your server, so change the code above appropriately.

  3. put the following plugin into your s_code.js (or similar). Should be placed somewhere after your config section and before the "DO NOT ALTER ANYTHING BELOW THIS LINE !" warning.

    /*
    * Plugin: YouTube Tracking v0.2w - track embedded YouTube Player
    * Author: Andreas Dierl - http://adlytics.de/adytt
    */
    var adytt={pl:[]};adytt.p=function(){var k=function(a,b){var c=a.indexOf('?');var d=a.indexOf('#');
    if(c<0){return""}var e=a.substr(c+1);if(d>0){e=a.substring(c+1,d)}var f=e.split('&');var i;for(i=0;
    i<f.length;i++){var g=f[i].split('=');g[0]=unescape(g[0]);if(g[0]===b){g[1]=unescape(g[1]);
    if(g[1].indexOf('"')>-1){var h=/"/g;g[1]=g[1].replace(h,'\\"')}if(g[1].indexOf('+')>-1){var j=/\+/g;
    g[1]=g[1].replace(j,' ')}return g[1]}}return""};var l=function(a,b,c){if(typeof a==='object'&&a!==null)
    {if(a.attachEvent){a['e'+b+c]=c;a[b+c]=function(){a['e'+b+c](window.event)};a.attachEvent('on'+b,a[b+c])}
    else{a.addEventListener(b,c,false)}}};this.p=null;this.id="";this.op=false;this.pl=false;this.po=0;
    this.du=0;this.bl=0;this.tp=false;this.i=function(a){var b=0;if(typeof s!=="object"){b=3}if(!b)
    {this.p=document.getElementById(a);if(this.p){if(a.match(/^[a-z0-9]+$/i)){window['adyttsc'+a]=function(o)
    {adytt.pl[a].st(o)};this.p.addEventListener("onStateChange","adyttsc"+a)}else{this.p.addEventListener
    ("onStateChange","adytt.pl['"+a+"'].st")}var c=this;l(window,"unload",function(e){if(c.op)
    {if(typeof c.sc==='function'){c.sc(c.po,true)}}})}}else{}};this.sc=function(a,b){if(this.pl)
    {s.Media.stop(this.id,a);this.pl=false;this.tp=false}if(b&&this.op){s.Media.close(this.id);this.op=false;
    clearInterval(this.tf)}};this.st=function(a){this.tp=false;switch(a){case 0:this.sc(this.du,true);break;
    case 1:this.du=Math.floor(this.p.getDuration());if(!this.op){var b=this.p.getVideoUrl();
    this.id="YT|"+k(b,'v');if(typeof adytt.getID==='function'){this.id=adytt.getID({url:b})}
    s.Media.open(this.id,this.du,"YouTube Embedded Player",{id:this.id});var c=this;this.tf=setInterval
    (function(){c.ti()},500);this.op=true}this.tp=true;break;case 2:this.sc(Math.floor(this.po),false);break;
    case 3:this.bl=this.p.getVideoBytesLoaded();this.po=this.p.getCurrentTime();if(this.bl===-1)
    {this.sc(Math.floor(this.po),true)}else{this.sc(Math.floor(this.po),false)}break;case-1:break;
    case 5:this.sc(Math.floor(this.po),false);break}};this.ti=function(){if(!document.getElementById(this.p.id))
    {this.sc(this.po,true)}else if(this.p&&(this.p.getPlayerState()===1||this.tp)){this.po=this.p.getCurrentTime();
    this.bl=this.p.getVideoBytesLoaded();if(this.tp&&this.bl>0&&!this.pl){this.pl=true;this.tp=false;
    s.Media.play(this.id,Math.floor(this.po))}}}};function onYouTubePlayerReady(a){a=decodeURIComponent(a);
    if(adytt.pl[a]){adytt.pl[a].sc(Math.floor(adytt.pl[a].po),true);delete adytt.pl[a]}
    adytt.pl[a]=new adytt.p();adytt.pl[a].i(a)}
    //adytt.getID = function(o) { return o.url; };

Demo Page:
To see this plugin with out of the box s_code and media plugin from Omniture check the demo page

Notes:
- The current Youtube player encodes the callback we need to get informed about event changes. Part of it is the player ID. This means currently only a-z & 0-9 are allowed for the playerapiid to get the workaround working. If your playerapiid includes _ or . it will keep failing and you have to either rename your ID or wait for a fix from Youtube.
- when using traditional object tag, make sure you don't have two tags with the same ID, but make sure the tag has an ID that matches the playerapiid parameter.
- default naming is YT|VideoID, e.g. "YT|8pB5sRsX5OU". Unfortunately YouTube does not make the video name available via API. So you need to classifiy the videos later in SiteCatalyst. (Update: help is coming)
- if you want to change the default naming, simply uncomment the adytt.getID function (last line of the plugin), change the code and return the name you want.
- The plugin adds an events handler to the window.onunload event to catch users that just leave the page. It tries to close the video and send the call to Omniture before leaving the page.
- Use the code above at your own risk. Always test before putting to production environments.

If you really don't want to follow my recommendation to use SWFObject, this way to implement the video manually seems to be the most-browser compatible. Make sure the plugin is loaded before the YouTube Player initializes!
<object id="myytplayer" width="425" height="344" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000">
    <param name="movie" value="http://www.youtube.com/v/8pB5sRsX5OU?fs=1&rel=0&enablejsapi=1&playerapiid=myytplayer"></param>
    <param name="allowFullScreen" value="true"></param>
    <param name="allowscriptaccess" value="always"></param>
    <embed id="myytplayer2" src="http://www.youtube.com/v/8pB5sRsX5OU?fs=1&rel=0&enablejsapi=1&playerapiid=myytplayer2" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"></embed>
</object>

 

-OR-  Manual Tracking - writing your own code:

On the YouTube JavaScript Player API Reference page you can find the neccesary information to get the player talk to you.

The steps you need to do:

  1. Follow Step 1 & 2 from Automatic Tracking to have the player ready and have the Media Plugin in your s_code.js file (or similar).

  2. have a call back for the YouTube API:
    function onYouTubePlayerReady(playerId) {
    ...
    }


    The playerId will give you the ID to reference the player.
     
  3. Get the player:
    ytplayer = document.getElementById(playerId);
     
  4. and have a function to listen to the state changes:
    ytplayer.addEventListener("onStateChange", "ytStateChange");
    ...
    function ytStateChange(newState) {
    ...
    }

     
  5. In the ytStateChange function you have to place your Omniture calls for s.Media.open(), s.Media.play(), s.Media.stop() and s.Media.close

 

Would be nice if you'd drop me a line if this works for you.
This plugin is published under the license of postcardware as long as you don't remove the header.

Have fun with video measurement!
Andreas

Version History:
2010-01-23 - 0.1
initial postcardware version
2010-06-10 - 0.1b
added decodeURIComponent for init
2010-10-05 - 0.1c
rewritten play/pause/.. handling, since API meant to say state=playing but bytesloaded=-1
2011-02-09 - 0.2
multiplayer version
2012-01-24 - 0.2w
workaroung for YT player bug when encoding callback function

 

[Home]  [Contact]  [Impressum]