Track outbound clicks with Google Analytics and jQuery

Update: Make sure you check out the new _trackEvent method of the Google Analytics pageTracker method. If your analytics account offers event tracking, this is the right way to do it if you don't want your events to count as pageviews. I've written a new post about tracking outbound clicks using the new method. -- Sometimes, you may want to know what outbound links a user is clicking on -- say, if you're linking to an affiliate's site and want to be able to count the clicks you're sending. Google Analytics offers this bit of code to accomplish this:

and says:
Google Analytics provides an easy way to track clicks on links that lead away from your site. Because these links do not lead to a page on your site containing the UTM JavaScript, you will need to tag the link itself. This piece of JavaScript assigns a pageview to any click on a link - the pageview is attributed to the filename you specify.
Two problems here: one, it's Javascript in an onclick tag, which is ugly and bad; two, you've got to add that to every link you want to track. No fun. Progressive enhancement says you should use Javascript to add behaviors that will only work with Javascript. I wanted to add this tracking ability to my blog, to see which outbound links people were clicking on. jQuery to the rescue:
$('a').each(function() {
  var $a = $(this);
  var href = $a.attr('href');

  // see if the link is external
  if ( (href.match(/^http/)) && (! href.match(document.domain)) ) {

    // if so, add the GA tracking code
    $a.click(function() { 
      pageTracker._trackPageview('/outgoing/' + href);
    });
  }

});
In my case, I wanted to track the post title (if there was one), in addition to the outgoing link's href. So:
$('a').each(function() {
  var $a = $(this);
  var href = $a.attr('href');

  if ( (href.match(/^http/)) && (! href.match(document.domain)) ) {
    $a.click(function() { 
      // get the post title if there is one 
      // and add it to the string for tracking
      var postTitle = $a.parents('div.post').find('h2:first');
      href = href.replace('http://',''); // cleanup for nice GA reports
      href = (postTitle.length > 0) ? postTitle.text() + '/' + href : href;

      pageTracker._trackPageview('/outgoing/' + href);
    });
  }

});
You can use the same method to unobtrusively add tracking code to file downloads:
var fileTypes = ['doc','xls','pdf','mp3'];

$('a').each(function() {
  var $a = $(this);
  var href = $a.attr('href');
  var hrefArray = href.split('.');
  var extension = hrefArray[href.length - 1];

  if ($.inArray(extension,fileTypes) != -1) {
    $a.click(function() { 
      // get the post title if there is one 
      // and add it to the string for tracking
      pageTracker._trackPageview('/documents/' + href);
    });
  }

});
See Google's help page for more information. Note that this example assumes you're using the new tracking code; you'll have to adjust accordingly if you're using the old tracking code. If you're using the new tracking code, it will look like this:
var pageTracker = _gat._getTracker("UA-XXXXXX-X");
pageTracker._initData();
pageTracker._trackPageview();

Loading mentions Retweet

Filed under  //  analytics   google analytics   howto   jquery   progressive enhancement   seo  

Anchor-based URL navigation, Take 2

Update: I encourage everyone who arrives at this post to check out Ben Alman's jQuery BBQ plugin -- it provides a ton of functionality above and beyond what this plugin offers, is much more robust, and is built to take advantage of the latest version of jQuery. While you're welcome to use the plugin on this page, it is no longer supported. I noticed I was getting a lot of visits via Google for my post on anchor-based URL navigation with jQuery, so I decided to write a plugin that would accomplish the same thing.

Call this function on an element that contains "panels" which, in turn, contain anchors. The container element should contain ONLY related panels, as this plugin will show only one first-child element of the container at once. This plugin will look at the current URL and see whether it contains an anchor. For example:
http://www.mysite.com/index.html#panel1
If it finds an anchor, it will look for the panel that contains the associated anchor tag; it will show this panel using the function defined by the showFn option, and it will hide the panel's siblings using the function defined by the hideFn option. If the nav option is set, it will use the nav option setting as a selector to locate the page's navigation. It will look for a link with an href matching the anchor; if it finds a matching link, it will run the function defined by the currentNavFn option on the link element (useful for setting the current nav item). If the nav option is set, it will also set up onclick functions on each of the links in the nav that refer to anchors on the page; the onclick function will use the show and hide options to show and hide the associated panels.

Options

  • showFn function to show the current panel
  • hideFn function to hide the current panel's siblings
  • nav selector for the page's navigation section
  • currentNavFn function to run on the link in the nav that is associated with the anchor
  • anchorClass class assigned to anchor tags; setting this will improve the speed on pages with lots of links
  • noAnchorFn function to run if the URL does not contain an anchor
Default option values:
var options = {
  showFn: function() { $(this).show(); },
  hideFn: function() { $(this).hide(); },
  nav: null,
  currentNavFn:
    function() {
      // this will add a class to the parent of the
      // link that matches the currently selected anchor
      $(this).parent().siblings().removeClass('anchor-nav-current');
      $(this).parent().addClass('anchor-nav-current');
    },
  anchorClass: null,
  noAnchorFn:
    function() {
      // this will show the first panel
      // if the URL doesn't contain an anchor
      $container.children().hide().eq(0).show();
    }
};

Loading mentions Retweet

Filed under  //  anchor   jquery   navigation   plugins   progressive enhancement  

Anchor-based URL navigation with jQuery

Update: I've since written a anchor-based URL navigation plugin that attempts to capture what's described below. -- I'm working on an application that has several panels of content, each accessed by clicking on a link in the page's main navigation. I wanted to give users the ability to get back to a panel after they'd left the application, without having to click on the panel in the navigation again, so I set it up so the URL would include an anchor link indicating the current panel (e.g. http://www.mysite.com/index.html#panel1). This had the added benefit of encouraging me to be a good front-end developer by following the principles of progressive enhancement -- before I set this up, a user without Javascript wouldn't get anywhere when they clicked on a link in the page's main navigation, and that's no good. Now, users without Javascript will be taken down the page to the panel they want, and users with Javascript will get the fancy Web 2.0 panels that show and hide and fade and stuff. Here's what I did:

  • Set up anchor tags at the top of each "panel" div, and give the anchor tags a class of anchor:
    ...
  • Put links to the anchors in the main navigation:
    1. Panel 1
    2. ...
  • Set up the onclick behavior for the main navigation items:
    var j = 1;
    $('ol#nav li').each(function() {
      $(this).click(function() {
        $('ol#nav li').removeClass('current');
        $(this).addClass('current');
        $('div.panel:visible').hide();
        $('#panel'+j).fadeIn(500);
      });
      j++;
    });
    
    // don't include return false! you want the URL 
    // to change to reflect which panel is showing --
    // the next step will make it so that all of the anchors
    // will be at the top of the page, so the fact that this
    // returns true won't cause the page to scroll to the anchor.
  • Move all the anchor tags to the top of the page so users with Javascript won't get bumped down the page when they click on a link:
    $('a.anchor').remove().prependTo('body');
    You might not want to include this step, or you might want to move the anchor tags elsewhere. This worked for me in this case, though.
  • When a user arrives on the page, look to see if they've requested a specific panel:
    var myFile = document.location.toString();
    if (myFile.match('#')) { // the URL contains an anchor
      // click the navigation item corresponding to the anchor
      var myAnchor = '#' + myFile.split('#')[1];
      $('ol#nav li a[href="' + myAnchor + '"]').parent().click();
    } else {
      // click the first navigation item
      $('ol#nav li:first').click();
    }
The end. Now users who arrive via a URL that includes an anchor tag will go to the proper panel, and everyone else will get the default behavior of going to the first panel.

Loading mentions Retweet

Filed under  //  front-end development   javascript   jquery   progressive enhancement