Pressure is nothing more than the shadow of great opportunity. - Michael Johnson

Unobtrusive click tracking with DOM scripting

4 years, 6 months ago

Update: A newer version of the tracking described in this post is available here.

Since launching my web site back in October last year I've become increasingly interested in monitoring its performance. I usually check my site stats once or twice a day using AWStats which allows me to view page impressions, user visits, country of origin and a whole raft of other data. But something is still missing... I have no idea which links visitors click on so it's really hard to gain a measure of which blog entries are interesting to people particularly as they don't need to visit the individual blog page to read the whole post. This would be a really interesting feature to have.

With that in mind I thought it might be cool to implement a URL redirect system and share my solution here. It struck me pretty quickly that I didn't want to have to set up redirect URLs for each link I add to the site and I certainly don't want to present these to any search engine spiders which might visit. Having just read Jermey Keith's excellent book, DOM Scripting, I thought I'd see if I could write an unobtrusive JavaScript function to dynamically add a redirect URL to all anchor href's on a page. Visitors clicking on a link would then be directed, via this redirect URL which would log the click, to the original URL specified in the anchor href.

So here's my solution...

JavaScript URL Replace Class

  1. var linkTracking = {}
  2. linkTracking.redirectUrl = '/redirect.php';
  3. linkTracking.init = function() {
  4. if (!document.getElementsByTagName) {
  5. return false;
  6. }
  7. var links = document.getElementsByTagName('a');
  8. for (var i = 0; i < links.length; i++) {
  9. linkTracking.modifyLink(links[i]);
  10. }
  11. return true;
  12. }
  13. linkTracking.modifyLink = function(link) {
  14. if (link.getAttribute('href')) {
  15. var url = link.getAttribute('href');
  16. var title = link.childNodes[0].nodeValue;
  17. if (link.getAttribute('title')) {
  18. title = link.getAttribute('title');
  19. }
  20. link.setAttribute('href', linkTracking.redirectUrl + '?url=' + escape(url) + '&title=' + escape(title));
  21. }
  22. }

After first checking for browser support of "getElementsByTagName", this class uses DOM methods to retrieve all anchor tags in the current page. It then loops through them and retrieves the current href, title and display text values for each one. Finally it resets the href attribute adding the redirect URL onto the front of the anchor's normal href value.

We want this function to run once all the page elements have loaded. We can do this by calling the class "init" method with Simon Willison's excellent "addLoadEvent" function:

  1. addLoadEvent(linkTracking.init);

Finally we include the class and Simon's "addLoadEvent" function in the page head with the following lines:

  1. <script type="text/javascript" src="/js/add-load-event.js"></script>
  2. <script type="text/javascript" src="/js/link-tracking.js"></script>

PHP Redirect Script

Next we need to create the PHP script referenced by the redirect URL. This will take care of logging the click and redirecting the user to the site they actually intended to visit. The code for this (minus the DB connection details) is shown below:

  1. <?php
  2. if (isset($_GET['url']) && isset($_GET['title'])) {
  3. require('includes/db.inc.php');
  4. $oDb = new Database();
  5. $sUrl = $oDb->EscapeQuotes($_GET['url']);
  6. $sTitle = $oDb->EscapeQuotes($_GET['title']);
  7. $oDb->Run("insert into click_logs (url, title, click_date) values ('$sUrl', '$sTitle', now())");
  8. $oDb->Close();
  9. header("Location: $sUrl");
  10. } else {
  11. echo 'URL or title not set.';
  12. }
  13. ?>

First the script makes sure that it has been passed a URL and title. It then logs details of the click in a MySql database table and finally the "header" command redirects the vistor to the correct URL. This script references a DB connection object (which I wrote and use for all DB access on my site). It's essentially a wrapper to the PHP MySql functions. I'll be releasing the code for this once I've had a chance to tidy it up a bit but in the meantime you could easily replace these calls with the normal PHP MySql commands.

The MySql Table Structure

The structure of the table used to store visitor clicks is shown below:

  1. CREATE TABLE click_logs (
  2. id int(11) auto_increment,
  3. url varchar(250),
  4. title varchar(250),
  5. click_date datetime,
  6. PRIMARY KEY (id)
  7. ) TYPE=MyISAM

Analysing The Logs

I haven't had time to create a pretty interface to view the logs. That will follow soon. You can see some minimal statistics based on this click tracking mechanism on my about page and, if you choose to implement this system on your site, you can easily view overall link popularity with the following SQL command:

  1. select url, title, count(url) as quantity from click_logs group by url order by quantity desc

Conclusion

This solution seems to work quite well but it was put together quickly so I'm sure that over time it will need some improvements and there may be extra sanity checks I need to add in. If you spot anything glaring, post a comment. I don't have to worry about creating or inserting redirect URLs and the search engines should be happy. There is however one minor problem with this approach - clicks will not be recorded for visitors with JavaScript disabled in their browser or those using browsers so old that they don't support the DOM methods used. All links will still, however be available to them - we won't be locking anyone out of the content. Given that these visitors probably represent a tiny proportion of the overall visitors to my site and given that I'm more interested in the overall trends than exact click figures I'm more than happy with this compromise.

Comments

  • You sir are a genious! Thank you for sharing this.

    An interested reader - 22nd June 2006 #

Help make this post better

Notes: Standard BBCode for links, bold, italic and code are supported. rel="nofollow" is added to all links. Your email address will never be displayed on the site.

Back to index