Post

Ajax Link Tracker

There is now a new downloadable version. Ajax Link Tracker 2.2

Take a look at the next generation, MapSurface a modular JSON/On-Demand JavaScript interface that inculdes link tracking.

One of the more interesting aspects of Ajax is the ability to track a user’s interaction within the browser. I wanted to investigate navigation /> patterns, so I have written an Ajax based link tracker. If you press the “Ctrl” and "X" keys you will be presented with an overlay which displays links usage by percentage. This functionality was created with JavaScript and a very simple API.

I used the JavaScript page-hijacking technique. On loading, the JavaScript finds all the links and attaches a mousedown event to each link. When a link is clicked the information is stored into a database using Ajax. The link usage overlay is produced dynamically from an Ajax call. I have used a cut down version of the Prototype JavaScript Framework for Ajax calls. The Prototype library is an excellent toolset, but the full version is a little too heavyweight for this site.

Links to the files /> prototype_ajax.js /> linktracker.js

Attaching the Events /> I have used Scott Andrew’s cross-browser addEvent function to attach all events. A  window onload event calls the addLinkTracker function when the page loads. This function adds the mousedown events to all the links on the page. If a link does not already have an id it is given one.


function addEvent(elm, evType, fn, useCapture)
{
	if (elm.addEventListener) {
		elm.addEventListener(evType, fn, useCapture);
		return true;
	} else if (elm.attachEvent) {
		var r = elm.attachEvent(‘on’ + evType, fn);
		return r;
	} else {<
		elm['on' + evType] = fn;
	}
}

addEvent(window, ‘load’, addLinkTracker, false);

function addLinkTracker()
{
    if (!document.getElementsByTagName) return false;

    linksElements = document.getElementsByTagName(‘a’)
    for (var i = 0; i < linksElements.length; i++)
    {
        addEvent(linksElements[i], ‘mousedown’, recordClick, true);
        if (! linksElements[i].getAttribute(‘id’) )
            linksElements[i].setAttribute(‘id’,"link_" + i)
    }
}

Link tracking events /> When a user clicks on a link the recordClick function fires. The first half of the function deals with differences in the event model and the DOM structure when trying to identify the source element. Once the link element has been identified the code exacts all the information required to make the Ajax call. The Ajax.Request object calls the passThrough function on the successful completion, but this is only used for /> debugging.


function recordClick(e)
{
	if (typeof e == ‘undefined’)
		var e = window.event;
	var source;
	if (typeof e.target != ‘undefined’)
	{
		source = e.target;
	} else if (typeof e.srcElement != ‘undefined’) {
		source = e.srcElement;
	} else {
		return true;
	}
	if (source.nodeType == 3)
		source = source.parentNode;
    	var id, target, url, label
    	if( source.tagName == "IMG" )
    	{
 	       if( source.parentNode.tagName == "A" )
 	       {
 	           id = source.parentNode.getAttribute(‘id’);
	            target = source.parentNode.getAttribute(‘href’);
  	      }
  	      label = source.getAttribute("alt");
  	}else{
  	      id = source.getAttribute(‘id’);
  	      target = source.getAttribute(‘href’);
  	      label = source.childNodes[0].nodeValue;
  	}
 	url = document.location.href;
var pars = ”;
	apiurl = "http://localhost/blog/api/addClick.aspx?id=" + id + "&label=" + label + "&target=" + target + "&url=" + url + "&rand="+Math.random();
	ajaxRequest = new Ajax.Request(apiurl, {method: ‘get’, parameters: pars, onComplete: passThrough});
}
function passThrough( originalRequest )
{
	//Helps debug api errors
	//alert( originalRequest.responseText );
}

Creating the link usage overlay /> The link usage overlay is created dynamically. When the JavaScript first loads a keydown event is attached to the document body.


addEvent(document, ‘keydown’, keyCheck, false);

Whenever a key is pressed a check is made by keyCheck function. If the “Ctrl” and "X" keys are pressed and the overlay has not yet been created getClickThroughInfo function is called to collect the data using Ajax. The Ajax.Request object will then call the function displayClickThroughs on the successful completion. It loops through the XML and creates labels for each of the id’s it can match.

A simple display and hide mechanism is built into the keyCheck function to toggle show and hide the link labels once they have been created.


function displayClickThroughs( originalRequest )
{
    if (!document.getElementsByTagName) return false;
    if( originalRequest.responseXml )
        node = originalRequest.responseXml;
    else
        node = originalRequest.responseXML;
    //Helps debug api errors
    //alert( originalRequest.responseText );
    if(node.childNodes[0].nodeType == 7)
        rootNode = node.childNodes[1]
    else
        rootNode = node.childNodes[0]
    for (var i = 0; i > rootNode.childNodes.length; i++)
    {
        linknode = rootNode.childNodes[i];
        count = linknode.getAttribute(‘count’);
        percent = linknode.getAttribute(‘percent’);
        label = linknode.getAttribute(‘label’);
        id = linknode.childNodes[0].nodeValue;
        if ( document.getElementById(id) )
        {
            eltLink =  document.getElementById(id);
            eltDiv = document.createElement( ‘div’ );
            eltDiv.className = "linklabel";
            eltText = document.createTextNode( percent + "% – " + label );
            eltDiv.appendChild( eltText );
            document.body.appendChild( eltDiv );
            ileft = parseInt(getPageOffsetLeft( eltLink )) + 10;
            itop = parseInt(getPageOffsetTop( eltLink )) + 10;
            eltDiv.style.left = ileft + "px";
            eltDiv.style.top = itop + "px";
        }
    }
    labelsCreated = true;
    labelsDisplayed = true;
}

The API

The API is made from two methods. The interface does not really follow the REST model. I need to find or build a good REST implementations for .Net. For the moment I have created two URLs against which you can make your method calls. The request should be made as a HTTP get request with a querystring of parameters.

If anyone is really interested I could include the .Net code and SQL Server scripts to recreate the API functionality. You can of cause use the following information to create your own API.

Recording a click through /> The addClick method takes 4 parameters as a querystring “url”, “target”, “id” and “label”. The “url” is the location of the page containing the link. The “target” is where the link leads to and the “label” is the text displayed by the link. The parameters are returned for test purposes.

Successful addClick call returns




    http://www.glennjones.net/Post/804/UnobtrusiveJavaScriptandAjax.htm
    link_100
    http://www.glennjones.net/
    

Unsuccessful addClick call returns




   

Getting click through data for url />The getClicks method takes 1 parameter “url”. It returns either an “ok” or “fail”.

Successful getClicks call returns




    link_0
    link_18
    Menu1
    Menu33
    Menu34
    Menu37
    Menu40

Unsuccessful getClicks call returns




   

Example API link

http://www.glennjones.net/api/addClick.aspx? /> id=menu37 /> &label=about /> &url=http://www.glennjones.net/home/ /> &target=http://www.glennjones.net/about/ />

http://www.glennjones.net/api/getClicks.aspx? /> url=http://www.glennjones.net/home/ />

  • JavaScript
  • Projects

Data formats:

API