AARON SMITH’S CODE ENDEAVOR

Tracking With Guttershark

[UPDATE] This is all old code, there have been numerous updates in the GS repo. And there are examples in the repository. Use those instead.

I thought I’d take a minute to show how I implement tracking with guttershark. I’ve used this a lot and it always works. I wrote this tracking manager a while ago with the intentions of figuring out these problems:

  • Provide some sort of assertions mechanism so the manager will first assert some condition, then fire or not fire.
  • Fire different information based on if the assertion is true or false.
  • Provide dynamic data in combination with tracking information from xml. Like the index of an image let’s say.

First thing’s first, here’s an example xml snippet:

<?xml version="1.0" encoding="utf-8"?>
<tracking>
	<track id="tag1">
		<webtrends>tag1,tag2,tag3</webtrends>
	</track>
	<track id="tag2">
		<webtrends>tag1,tag2,tag3</webtrends>
	</track>
</tracking>

Currently the tracking manager only supports webtrends and hitbox. I haven’t written any projects that require anything else yet. There are hooks in the tracking manager for ganalytics, omniture, and atlas; so anyone else could implement it and share it with me to be put in GS.

The tracking manager will fire whatever tracking type you have defined in a track node. Here’s an example xml file with both webtrends and hitbox:

<?xml version="1.0" encoding="utf-8"?>
<tracking>
	<track id="tag1">
		<webtrends>tag1,tag2,tag3</webtrends>
		<hitbox>
		    <lpos>asdf</lpos>
		    <lid>ghjk</lid>
		</hitbox>
	</track>
	<track id="tag2">
		<webtrends>tag1,tag2,tag3</webtrends>
	</track>
</tracking>

So the tracking node “tag1″ would fire both webtrends and hitbox. This also shows that depending on the tracking type, the tracking manager will parse the xml differently.

Let’s take the webtrends tag for example. The tracking manager will split the content on a comma (”,”), and use index 0 as “dcsuri”, index 1 as “ti”, and index 2 as “cg_n”. Those are webtrends variables passed to their dcsMultiTrack function.

So let’s take a look at getting this to fire. Here’s a document class that would do it:

package 
{
	import gs.core.DocumentController;
	import gs.core.Preloader;
	import gs.util.MathUtils;
 
	import flash.display.MovieClip;
	import flash.events.Event;
	import flash.events.MouseEvent;
 
	public class Main extends DocumentController
	{
 
		public var clip:MovieClip;
 
		override protected function flashvarsForStandalone():Object
		{
                        //the model file contains the tracking.xml file asset
			return {model:"model.xml"};
		}
 
		override protected function onModelReady():void
		{
			preloader=new Preloader();
                        //preloader will load the tracking.xml asset
			preloader.addItems(model.getAssetsForPreload());
			preloader.addEventListener(Event.COMPLETE,onPreloadComplete);
			preloader.start();
		}
 
		override protected function initTracking():void
		{
			super.initTracking(); //tracking is initialized in DocumentController
                        //tell the tracking manager to fire the "tag1" track when clip is clicked.
			tracking.register(clip,MouseEvent.CLICK,"tag1");
		}
	}
}

Because this is using the guttershark framework there’s one hidden thing. Guttershark will load a model.xml file which contains our tracking.xml file asset.

Here’s what that model.xml file looks like:

<?xml version="1.0" encoding="utf-8"?>
<model>
	<assets>
		<asset libraryName="tracking" src="tracking.xml" preload="true" />
	</assets>
</model>

All the model xml does is define a tracking asset which is an xml file. The guttershark document controller will find that asset, and initialize a tracking manager for us. It’s actually really straightforward. All the DocumentController does is expose hooks and sets up some default things that I use all the time. Read the source for DocumentController for more info. Anyway, back to the tracking.

With everything that we’ve setup so far. A tracking call would be fired for “tag1″ when you click on the movie clip. This is where it starts to get interesting.

Let’s say we didn’t want the tracking to fire if clip is disabled. Here’s how you can do that:

...
override protected function initTracking():void
{
    super.initTracking();
    var options:Object = {
        assertProp:"enabled"
    };
    tracking.register(clip,MouseEvent.CLICK,"tag1",options);
    clip.enabled=false;
}
...

The tracking manager internally will end up using “if(clip["enabled"]) fire()”. The tracking manager can also use a method:

...
override protected function initTracking():void
{
    super.initTracking();
    var options:Object = {
        assertMethod:shouldFire
    };
    tracking.register(clip,MouseEvent.CLICK,"tag1",options);
    clip.enabled=false;
}
private function shouldFire():Boolean
{
    return (clip.alpha > .25) ? true : false;
}
...

With that update, the tracking event would only fire if the clip’s alpha is greater than .25.

That covers some of the basic assertions.

What if we wanted to choose which tag to fire depending on if the assertion is true or false? First let’s make an update to the xml:

<?xml version="1.0" encoding="utf-8"?>
<tracking>
	...
        <track id="clipWasShown">
		<webtrends>tag1,tag2,tag3</webtrends>
	</track>
	<track id="clipWasHidden">
		<webtrends>tag1,tag2,tag3</webtrends>
	</track>
	...
</tracking>

And here’s how I’d update the actionscript to accommodate this.

...
override protected function initTracking():void
{
    super.initTracking();
    var options:Object = {
        assertProp:"visible",
        whenTrue:"clipWasShown",
        whenFalse:"clipWasHidden"
    };
    tracking.register(clip,MouseEvent.CLICK,null,options);
}
...

That’s really just another useful option in the tracking manager arsenal.

Now for the last problem, dynamic data. Let’s say we wanted to include the index of some slideshow, which indicates which picture their looking at. And let’s say we want it appended to the “cg_n” variable that get’s sent to webtrends.

Here’s how you can implement dynamic data:

...
private var index:int = 0;
private function next():void
{
    index++;
    render();
}
 
private function prev():void
{
    index--;
    render();
}
 
override protected function initTracking():void
{
    super.initTracking();
    var options:Object = {
         dynamicData:slideShowIndex
    };
    tracking.register(clip,MouseEvent.CLICK,"tag1",options);
    clip.enabled=false;
}
 
private function slideShowIndex():Array
{
    return [null,null,index];
}
...

So in this case, the tracking manager expects an array for the “dynamic data” for webtrends. And will append whatever is in the array to the tags from xml before firing.

The dynamic data just happens to be implemented this way for webtrends. But if it’s a different tracking type you would return whatever the tracking manager is expecting. So for example, the “hitbox” tracking would require a function like this:

private function slideShowIndex():Object
{
    return {lpos:index};
}

That’s pretty much it. As mentioned, I don’t have omniture, ganalytics, or atlas implemented, but there are hooks in the tracking manager. So if anyone out there needs to implement then please share.

I like using the tracking manager this way because it limits the amount of code I have to write to actually fire tracking. And keeps the real tracking tags out of your code.

There’s one other thing to mention - whenever you’re working with someone from an analytics department who is creating the tags for you. Make sure they know to always put dynamic data at the end of the tags. It’s easier to implement ;)

There are a couple examples in the guttershark repository.

  

1 Comment so far

  1. Guillaume Malartre February 21st, 2010 9:41 am

    I’m currently inserting ganalytics inside a large flex project (buzzmath.com) and this hooking layer seems the way to go for quick reorientation of analytics services.

    Thanks for sharing! Interesting read again!

Leave a reply