CrazyEgg.com – How does it track Visitor Clicks?

No worries, I’m not gonna post review #213 about what CrazyEgg.com does. I think there are already enough of them out there, a few good ones:

Solution Watch: Crazy Egg Launched – Visualize Visitor Clicks
Bloghelper: Crazy Egg = Click Tracking + Heat Maps for Your Blog
Devlounge: A Sneak Preview at Crazyegg!
Techcrunch: See What Your Website Visitors Are Doing With Crazy Egg

When I saw CrazyEgg.com the first time, I was all engineer and what I wanted to know was, how the hell do they do this?

 

<script type="text/javascript"> //<![CDATA[ document.write('<script'+' src="http://crazyegg.com/pages'+' /scripts/4382.js?'+(new Date()).getTime()+ '" type="text/javascript"></scr'+'ipt>'); //]]> </script>

The above code is the only thing one needs to include into the page. Translated this leeds to this:

http://crazyegg.com/pages/scripts/4382.js?1234567

I the file I downloaded in raw form is here. Not very readable, but after some formating I have a better version here.

A little bit later and I had the version below. Now I hope most of the names make sense and help understand the code:

var _cep=[]; var _ceL={}; var _ceLT=new Date(); var _ceET=null; var _ceAID=new Array(); //creates a unique id for elements that have no id tag function CreateUniqueID(_1) { var _2=false; var _3=""; for(i=0; i<_ceAID.length;i++) { if(_1==_ceAID[i].name) { _2=true; break; } } if(_2) { _ceAID[i].count+=1; count=_ceAID[i].count; } else { _ceAID.push({name:_1,count:1}); count=1; } return (_1+count); } //We wanna have a good name for all the //elements that we have on the heatmap //afterwards. //An anchorElements element is either a Link //or an Image function CreateNameForElement(anchorElement) { imgCollection = anchorElement.getElementsByTagName("img"); //check if the object that the user clicked on is //an image, if yes, we can either use the alt //tag, the title or some other tags. if(imgCollection.length>0) { img=imgCollection[0]; if(img.alt) { link_text=img.alt; } else { if(img.title) { link_text=img.title; } else { if(img.longDesc) { link_text=img.longDesc; } else { link_text=img.src; } } } } //if it is not an image, lets see if we can use //the inner text or a title or something else { if(anchorElement.innerText) { link_text=anchorElement.innerText; } else { if(anchorElement.text) { link_text=anchorElement.text; } else { if(anchorElement.title) { link_text=anchorElement.title; } else { link_text=anchorElement.href; } } } } if(link_text=="") { link_text="No Text Found"; } return link_text; } //checks if the links points to a different site function IsSameSite(linkHostname, locationHostname) { same=(linkHostname.indexOf(locationHostname)>= || locationHostname.indexOf(linkHostname)>=0) ? true : false; return same; } //for all pics on the page we set a link to //crazyegg.com //for links, we replace them with links to //crazyegg.com //QUESTION? not sure how they track html controls //like buttons? function PlaceLinksToCrazyEgg() { var anchorElements = document.getElementsByTagName("a"); for(var i=0; i<anchorElements.length; i++) { anchorElement = anchorElements.item(i); // QUESTION? looks like we do not replace //absolute links? if(anchorElement.href.indexOf("http")==0) { link_id="CEID_"; link_text=""; if(anchorElement.id=="") { link_id += IsSameSite(anchorElement.hostname, location.hostname) ? anchorElement.pathname : nchorElement.href; link_id = link_id.replace(/W/g,"_"). link_id = link_id.replace(/_+/g,"_"); link_id = link_id.replace(/_$/,""); link_id = CreateUniqueID(link_id); } else { link_id = anchorElement.id; } link_text = CreateNameForElement(anchorElement); _cep.push( { "text":link_text, "href":anchorElement.href, "target":anchorElement.target, "id":link_id,"name":anchorElement.name }); var _9="?"; _9+="pid=83913&"; _9+="token=124678787&"; _9+="text="+escape(link_text)+"&"; _9+="href="+escape(_7[i].href)+"&"; _9+="element_id="+escape(link_id); anchorElement.oldHref= anchorElement.href; anchorElement.href= "http://crazyegg.com/track/"+_9; FixStatusBar(anchorElement); } } } //this way the status bar still shows the old url and //not to crazyegg.com function FixStatusBar(_a) { var _b=_a.onmouseover; if(typeof _a.onmouseover!="function") { _a.onmouseover=ShowLinkInStatusBar; } } function ShowLinkInStatusBar() { window.status=this.oldHref; this.onmouseout=function() { window.status=""; return true; } return true; } // QUESTION? No idea what this does function ceHC(_c) { var _d=""; _d+="pid=83913&"; _d+="token=124678787&"; _d+="text="+_ceL.text+"&"; _d+="href="+escape(_ceL.href); } // QUESTION? No idea what this does function ceMoveOn() { switch(_ceL.target) { case "": self.location=_ceL.href; break; case "_new": ceNewWindow= window.open(_ceL.href); break; case "_blank": ceNewWindow= window.open(_ceL.href); break; } } PlaceLinksToCrazyEgg();

Code formatted by Code Formatter Plugin for Windows Live Writer.

Code from above in Text format here, it’s easier to read.

The result of this exercise:

  • They replace all links with links to crazyegg.com and append an unique id. This is how they can track on which links visitors click. Makes sense.
  • They also add links to pictures. Very cool, never even thought of how many visitors helplessly click on my unlinked pics.

What I cannot figure out are the following things:

  • How do they forward the post to my own webserver afterwards? I don’t think a simple redirect would work or does it? Even for POST commands?
  • How do they track clicks on Form elements? (They do, if you check a heatmap with Input elements for example).

Maybe the ceMoveOn() function does have something to do with this….

Anyone out there that solved the puzzle?




Ähnliche Beiträge


Leave a Reply

Your email address will not be published. Required fields are marked *



*