Track outbound links and file downloads automatically in Google Analytics

Just to let you know that I have finally gotten round to updating the original combined tracking script hack I had for urchin.js to the new ga.js. Essentially the combined tracking script is a modification of the GATC so that it automatically tracks:

  • outbound links – Automatically
  • file downloads – Automatically
  • mailto links – Automatically

Therefore, instead of having to manually modify such links by adding an onClick event handler to your ‘a’ tags, this script will do it all for you.

April 2011 – New async hack launched
This hack has been completely revise for the latest GA async code. Further info >>

 

Why is this necessary?

Outbound links (links to other websites from yours), file downloads (e.g. PDFs, exe, xls etc.) and mailto links (links to an email address) can be important indicators as to whether your site is engaging with visitors. If so, you will certainly want to track these and potentially define them as goals in your Google Analytics reports.

Normally you do this by creating a virtual pageview. However if you have hundreds/thousands of these, or even just a few dozen that constantly change, manually tagging them is an administrative nightmare.

This script uses the properties of the browser (Document Object Model, or DOM for short), to capture links that are non-standard pageviews and automatically create the event handler for you.

The result is that your outbound links, file downloads and mailto links are tracked for you and are always up to date. The default virtual locations for these in your Google Analytics reports are: /ext/, /downloads/, and /mailto/ respectively, though of course you can change these as you wish. Typically you will wish to view these in your Content > Top Content report as shown below:

IMPORTANT: The position of this code within your page is important. This must placed after your call to the GATC. Add addLinkerEvents() in an onLoad event handler and host the JavaScript in a separate file. As an example I show this below, assuming the javascript is hosted in a file called trackExternal.js, as follows:

[js]

…your remaining web page content…

[/js]

A note on performance: Each time your page loads, this script will go through all links referenced on the page to see if it is for a download. Clearly the more links on your page, the harder the script must work. As long as the number of links on each page number in the hundreds and not thousands, performance should not be a problem. Also, pages with a large number of links, it is possible that visitors will click on a download link before the script has modified it. The result is that click through will not be tracked by Google Analytics.

Related posts:

Are you using this or creating your own hacks for Google Analytics? Please post your comments and share your thoughts here.

Looking for a keynote speaker, or wish to hire Brian…?

If you are an organisation wishing to hire me and my team, please view the Contact page. I am based in Sweden and advise organisations in Europe as well as North America.

You May Also Like…

132 Comments

  1. Bill D.

    Hey Brian,

    After years with Indextools (now Yahoo) we made the jump to GA. Tons of good data but I am surprised there is no built-in download tracker. Our site has numerous PDF and ZIP files many of which are created dynamically via a database query selected by the user, making individual onClick events impossible. However, like Jan and Draschi above, as a recent adopter of GA, I am using the latest tracking code recommend by Google. Of all the code I’ve seen that attemps to address this issue, yours is the most practicle. My question is, if and when you update your code to work with the new GA tracking snippet, would it be possible to place your code near the bottom of the page without having to use the onLoad function, so it will run after the download links get generated? Refer to this page as an example:
    http://www.bwsc.org/REGULATIONS/standard_details/standard_details.asp

    Thanks

    Bill

    Reply
  2. Drachsi

    All I wanted to do was track pdf file views or downloads. Then I found this site and thought, great, even better. But I have the same problem as Jan above. Im using the new Google code.

    Any idea when a solutiuon might be available?

    Regards

    Drachsi

    Reply
  3. jan

    Brian, it doesn’t work with me. I am using the latest GA tracking code and whenever I placed the “” part the GA stopped working.

    The latest GA looks like this. Any idea how to make it work?

    var _gaq = _gaq || [];
    _gaq.push([‘_setAccount’, ‘UA-xxxxxxx-xx’]);
    _gaq.push([‘_trackPageview’]);

    (function() {
    var ga = document.createElement(‘script’); ga.type = ‘text/javascript’; ga.async = true;
    ga.src = (‘https:’ == document.location.protocol ? ‘https://ssl’ : ‘http://www’) + ‘.google-analytics.com/ga.js’;
    var s = document.getElementsByTagName(‘script’)[0]; s.parentNode.insertBefore(ga, s);
    })();

    Regards

    Jan

    Reply
    • Brian Clifton

      Jan: The code is not written for the async GATC (that has only been formally released in the past few weeks).

      Reply
  4. Brendan

    You might like to try the following – replace the final closing brace “}” with the following JavaScript:

    
        startFormsListener();
    }
    
    function startFormsListener(){
        if (window.addEventListener){
            window.addEventListener("load", attachFormSubmit, false);
        }
        else if (window.attachEvent){
            window.attachEvent("onload", attachFormSubmit);
        }
    }
    
    function attachFormSubmit(){
        var forms = document.getElementsByTagName('form');
        for (var x = 0, y = forms.length; x < y; x++){
            if (forms[x]){
                if (forms[x].addEventListener){
                    forms[x].addEventListener("submit", trackFormSubmit, false);
                }
                else if (forms[x].attachEvent){
                    forms[x].attachEvent("onsubmit", trackFormSubmit);
                }
            }
        }
    }
    
    function trackFormSubmit(attachFormSubmit){
        var elmnt = attachFormSubmit.srcElement;
        if (elmnt){
            pageTracker._trackPageview(document.location.pathname + document.location.search + "&SubmitFormAction=" + elmnt.action);
        }
        else{
            pageTracker._trackPageview(document.location.pathname + document.location.search + "&SubmitFormAction=" + this.action);
        }
    }
    
    Reply
  5. Hugh Gage

    Brian, this is ingenious but does it work with outbound (or any other links) that are contained in buttons? (similar to your “submit comment” button immediately below this box as I write)

    Reply
  6. Mark Larsen

    Thanks for the hack for automatic tracking of downloaded files in Google Analytics. I installed the hack in a separate trackExternal.js, per your recommendation. But how do I add a view for:
    /ext/, /downloads/, /mailto/
    in the Top Content report? Or will this simply show up tomorrow, after Google downloads my data? Thanks!

    Reply
    • Brian Clifton

      Mark: yes, its just a matter of waiting for the pageview reports to be populated with the new values i.e. 4 hours of so.

      Reply
  7. Chafik

    Hi, good job on this script which is very useful. But I have some troubles by using it. I have installed it on my page as you explain in this post but when I go to Content > Top Content page in GA, I only see visits to the page “/”.

    But I clicked on some links to test and the results don’t appear in Google Analytics… Did someone have the same problem ?

    I don’t see how can I solve this, I’ve installed the latest GATC and the latest script (Jan 15th 2009).

    Thanks a lot

    Reply
  8. dgilperez

    Regarding the direct downloads trick, great work Brian !!!
    I’m enjoying your book.

    Regards.

    Reply
  9. dgilperez

    Hi Brian !

    Thanks for your answer. I have to say I have very little control on the web page I want to track their links. It’s a completely static one and have limited control over the code. That means I cannot add much JS nor any dynamic language.

    If this can still be done, I’ll check your book out, although I’m quite in a hurry and worried about the time it’ll take to arrive at Spain.

    Regards !

    Reply
  10. dgilperez

    Hi !

    Many thanks for maintaining this useful script.

    I’m looking for a way to track external accesses to my PDF’s URLs, I mean when someone browses directly for the URL without loading any web page where the onClick event is located.

    Is it possible? Any hints?

    Many thanks !!!!!

    Reply
    • Brian Clifton

      dgilperez: The “hack” to do this is describe in Ch9 of the book – Tracking Links to Direct Downloads. It has been updated for the second edition, but essentially the method remains the same.

      Reply
  11. Rene Kreijveld

    Hi Brian,
    Thanks for a brilliant solution.
    I do have some problems however getting it to work.
    I have added the script on our site http://global.atradius.com/, right after the ga.js code.
    I also modyfied the body tag (added onLoad code), but I am unsure if this is necessary. No downloads are found in analytics.
    Did we do something wrong here?
    Thanks in advance,
    Rene

    Reply
    • Brian Clifton

      Rene: Make sure your GATC is for the latest ga.js and the script you are using is the latest from the site. In the post I describe the placement of the call to the /trackExternal.js file. This is critical.

      I do need to update this post to reflect ga.js (not the legacy urchin.js), but you should be able to figure this out…

      Reply
  12. john

    Actually, forget it. I was being dumb. Just dropped the alert into the function.

    Reply
  13. john

    Hey Brian,

    I’m moving from the urchin to ga version of tracking and am testing your script.

    Two comments/questions:
    1) Curious as to why this version doesn’t use setAttribute.

    2) The commented out alerts for testing will never see the splitResult variable since it’s local to the onClick function that’s being written for each link. Am I missing something?

    Reply
  14. Lauren

    I have this script on a page with a product review script, and the two are conflicted somehow.

    On this test page( http://www.avaline.com/ test-color-selector ), the “write your own review” link under the “Review” tab is supposed to expands= to show the review form, but upon hitting it a second time, it won’t run this part of the script which should make the form disappear again:
    else {
    document.getElementById( ‘review_form’ ).style.display = ‘none’;
    reviewsLink.innerHTML = ‘[+]Write your own review’;
    }

    The full if-statement is attached to the onClick event of the element with an id of “write_review,” and when I click, in the bottom of the FF browser I can see “Waiting for http://www.google-analytics.com” for a split second. When I remove the addLinkerEvents-ga.js script, the full if-statement works, and allows the review form to collapse and expand as it should.

    Any ideas as to what in particular is causing the conflict?

    Reply
  15. Jakub Uradnik

    Hello Brian,

    Many thanks for your reply and sorry for the long delay in responding. Holidays and all…

    I have double checked I’m using the latest addLinkerEvents-ga.js and I am afraid I am. For the site above I am still getting that site’s own pages reported as /ext/ ones. I can send you a screenshot of my GA Top content report, if you’d like to see it.

    Thanks
    J

    Reply
  16. BClifton

    Rick: The script should go after everything. Thanks for the feedback. Spread the word 🙂

    Reply
  17. Rick

    i guess it did strip that out – should the /trackExternal line go after EVERYTHING or after the first script and before
    try {

    Reply
  18. Rick

    Hello all – thanks to everyone for providing such a great community resource. I’m about to add this script for a site with the GATC in the header. When using the ga.js version of GATC should the script src=”/trackExternal.js” type=”text/JavaScript” go after everything, or in between the two scripts like below? (it the software takes out the code than I’m referring to placing it in between the initial call to GATC and script that contains my UA number).

    var gaJsHost = ((“https:” == document.location.protocol) ?

    “https://ssl.” : “http://www.”);
    document.write(unescape(“%3Cscript src='” + gaJsHost + “google-

    analytics.com/ga.js’ type=’text/javascript’%3E%3C/script%3E”));

    try {
    var pageTracker = _gat._getTracker(“UA-xxxxxxxxx”);
    pageTracker._trackPageview();
    } catch(err) {}

    Thanks in advance for any feedback!

    Reply
  19. Jakub

    Hello Christopher, Brian and all,

    I am having the same problem as Christopher above (posting no. 70). He was never replied to and I haven’t found an answer to our problem anywhere else, so I was wondering whether Brian or anyone else would know what the /ext/ reporting on internal page views is caused by. I tried changing the HTML on my pages around a few times (not the javascript) but no setup bore any fruit.

    Thanks
    J

    Reply
    • BClifton

      Jakub: Do you have the latest script? There was a bug I fixed a while ago which from memory sound similar to this. Ensure you get the latest file form the Hacks & Download section and subscribe to the script updates. Let me know if that solves the problem.

      Reply
  20. Admin

    Trying to implement the outbound tracking as follows:

    _uacct = “UA-xxxxxxx-x”;
    urchinTracker();

    (all this in the header)

    and

    But no errors on load – nor data tracked in GA

    J

    Reply
  21. Alex

    Hi Brian,

    thanks for your scripts and your book (I’m reading it right now).

    I’ve tried to implement the tracking srcipt for ga.js, and although I don’t get any script errors with firebug, I’m not getting any results in GA.

    It’s been implemented in one of our websites: http://www.unctad.info/en/Public-Symposium-Website/
    but I’m not 100% about the order of the ga-related scripts… Unless I have to wait a bit longer for the results to appear…

    what do you think?

    a

    Reply
  22. Jason Seddon

    Hi Brian

    My tracking code goes to multiple accounts so pageTracker has been changed to firstTracker, secondTracker etc.

    Will the script work if I change all the pageTracker references to secondTracker and just track downloads in one of the accounts, or will the script need modifying further than that?

    Cheers

    Reply
  23. Brendan Halloran

    Hi Brian,

    I have discovered that when you click on a “javascript:close();” button, the following shows up in the cookie string when you inspect it using HttpWatch “utmp=/outbound/undefined”.

    Any tips on how to get around this issue? For now, I have created a filter that discards all pageviews with the name “/outbound/undefined”, but it would be good to stop it at the source.

    Reply
  24. Brendan Halloran

    Hi Brian,

    What does “Only links written to the page (already in the DOM) will be tagged” mean? Can you give me an example?

    Thanks,

    Brendan.

    Reply
  25. Michael Mackay

    Hello,

    I’m trying to install this script on the website for the company I work for, but when I try to use the “addLinkerEvents()” command on the body OnLoad IE reports an error. (Object Expected) I’ve essentally copy/pasted your code(With the exception of the tracking code for GA). I’ve tried it in the header, and the footer, and I’m not very good with Javascript. Any help or suggestions would be appreciated. Thanks!

    Reply
  26. Brendan Halloran

    And yet more feedback from me Brian!

    I have discovered through testing that there is a way to ensure that the sub-domains of a website are not tracked as external links. You simply add “.” in front of the root domain – an example follows:
    var extTrack = [“.domain.com”];
    and this will recognise http://www.domain.com, sub.domain.com, etc as internal links.

    Brendan.

    Reply
  27. Brendan Halloran

    Hi Brian,

    Another question for you! Do you know if it’s possible to modify the script to allow the data to be sent back to multiple GA accounts/profiles?

    Brendan.

    Reply
  28. Antoine Préfontaine

    Hi again Brian!

    I’ve installed your script on my server and I noticed that I just could not see the Events Tracking Reports in Google Analytics. I soon realized that I just didn’t have access to this functionality within my GA account, simply because I didn’t have a Beta version for my own personal Web site.

    So here are some links that might be useful for others that happen to have the same problem that I had.

    First, if you want to benefit from the Event Tracking method, you need to fill that request form from Google (http://spreadsheets.google.com/viewform?key=p7DycufUwNgmtunKEtgNGBg&hl=en).

    Secondly, even though you don’t receive any news from Google, you don’t have to wait to see the Event Tracking reports. Here is an article from 3DIssue (http://www.3dissue.com/news/?tag=event-tracking) that shows you exactly what to do. You’ll see, it is pretty easy and very useful.

    Thanks for sharing this information with your audience.

    Best regards, Antoine Préfontaine 😉

    Reply
  29. Brendan Halloran

    Hi Brian,

    I have tested Stephane’s script and it does work well, as does yours. The best of both of your scripts would be a fantastic outcome – the ability to use pageviews or events, as well as be able to track clicks on mailto links in addition to outbound links and downloads.

    Regards,

    Brendan Halloran.

    Reply
    • Brian Clifton

      Brendan: Yes I am aware of Stephane’s script and I am sure it works well. I am also working on a switch method so you can choose which tracking method to use. Allow a month for this…

      Reply
  30. Brendan Halloran

    Hi Brian,

    I have an update on the Firefox issue as mentioned in my last post.

    Even though LiveHTTPheaders, HttpFox and HttpWatch all indicated that the data was not being fired off to GA when a downloadable document was clicked on in Firefox, I have been reassured that the script does work because data is now showing up in my GA reports.

    Brendan.

    Reply
  31. Brendan Halloran

    Hi Brian,

    I have successfully installed and tested this script and it is working well apart from one issue.

    The gif is not being fired off when downloads are clicked on when Firefox is being used.

    Do you have any suggestions?

    Regards,

    Brendan.

    Reply
  32. Christopher

    I’m testing out your script and love the idea. I’m interested in applying it to a very large site. But I noticed something odd on mine. All of my traffic since installing is showing as /ext/ links. Sorry I should say if some one clicks on a link to another page even that page is showing up in GA as /ext/www.domainname.ca/web/internalpage.html But this page internalpage.html isn’t external lol it’s just another page on my site. All links are are root relative links. /web/pagefile.html

    Any ideas what I might have done wrong? Thanks again ps I bought your book and really like it. I hope you put out something with Adwords and more SEM.

    Cheers,

    C

    Reply
  33. Brian Clifton

    John: Could be lots of reasons for differences (have a look at this post if you have not read already: http://www.advanced-web-metrics.com/accuracy-whitepaper). One thing I would try, is to move the GATC to the top of page i.e. in the <head> section. This ensures the tracking code is loaded before anyone can click away…

    Shirlz: Your understanding is correct. There is a reason for this – though I can’t remember exactly why. Let me think it through and get back to you.

    Update: OK, so the logic for having only extTrack[0] for file downloads is that these should only be hosted on your primary domain. It doesn’t make sense to host ‘your’ downloads on a third party site – they would then be an outbound link and picked up as such.

    Jeremy: Thanks for the feedback. Let me know if it solves your problem.

    Reply
  34. Jeremy Hutton

    Hey Brian – Thanks for the code! I’ve been slaving away trying to manually track pdfs for awhile now and this will save me tons of time. (Keeping my fingers crossed!)

    Reply
  35. shirlz

    Thanks for this Brian.

    I’m not sure if the tracking electronic downloads part of the combined script is entirely correct (or I may have misunderstood it). It splits on extTrack[0] always, but should it not loop through the array of extTrack and then split based on the match?

    Thanks!
    Shirley

    Reply
  36. John

    I’m using this to track clicks to vendors (external clicks to other domains) from a product site. I am seeing clicks in top content, but these clicks don’t match up with the traffic that the vendors are seeing from the page. One day I’ll have 3 clicks from vendors.html to a specific vendor, but said vendor will have 15-20 referrals from mysite.com/vendors.html – Anyone have any idea why this might be?

    Reply
  37. webdesign

    There are some script errors, but overall it’s awesome!!

    Reply
    • Brian Clifton

      Webdesign: Can you expand on what errors you are getting please

      Reply
  38. Dario

    Brian,
    Well, there are two onCLick events on the page: Google AdSense ads and print page option…do they count as “undefined” external URLs? Thanks

    Reply
  39. Dario

    Hello,
    I have implemented all the code and everything seems to be OK. But, there is one thing that I don’t understand -in TOP CONTENT report there is also mentioned this: “/ext/undefined” What does it mean and is there a way to solve this issue?
    Thanks in advance.

    Dario

    Reply
    • Brian Clifton

      Dario: Not sure – do you have other onClick event handlers already on the page?

      Reply
  40. Antoine Préfontaine

    Ok

    As I can see, the script that I just wrote just don’t show up… Anyway, the main idea is that I took your trackExternal.js and I saved it to a folder called GA-scripts on my server and then I’ve changed my GATC and the body tag in my pages. Is it fine to do it that way.

    Thanks again! Antoine 😉

    Reply
  41. Antoine Préfontaine

    Hi everyone!

    Hi Brian ! Thank you for your book. I’ve read it all and it is a great tool for me.

    I’m Antoine, a French Canadian guy, so I apologize for my bad English.

    I’ve tried to install the script to my Web site but I’m very not sure if I did the setup properly. (I know sweet nothing about JavaScript).

    Could you please tell me if I did the right thing?

    1) I’ve firstly created a new folder on my server called GA-scripts where I’ve copy and pasted the New Combined tracking script that I found at http://www.advanced-web-metrics.com/scripts/addLinkerEvents-ga.js. I’ve named that document trackExternal.js

    2) Since I am using WordPress, I’ve changed my GATC in the footer.php with the following :

    _uacct = “UA-*******-1”;
    urchinTracker();

    3) Finally, in the page.php, I’ve changed the tag by

    Can you please tell me if I did the right thing? If not, could you please provide me with more detailed information with the set up process.

    Thank you very much for your help.

    Best regards, Antoine 😉

    Reply
  42. John

    Does anyone have any idea why this wouldn’t work with ga.js on a Yahoo store?

    Reply
  43. June

    Thanks for that Brian. You wouldn’t believe what the problem was! I copied and pasted your code from this page into my code but my code editor didn’t like the style of double quote marks.

    After puzzling over what could be causing the Javascript error, I noticed the style of quote marks was different to those used elsewhere in the code. I fixed it up and the error disappeared… so I’ll have to wait another day or so to see if the clicks show up in analytics.

    Thanks again for your help.

    June

    Reply
  44. June

    Hi Brian,

    I’ve been trying to get this script working for the last week or two and after cleaning up a couple of silly errors on my part, I still can’t get it work. Could you take a look for me? I could add onClick to every link but I have hundreds of downloadable files on this site and I don’t think I can face doing that.

    Site is itute.com

    Thanks,
    June

    Reply
  45. Brian Clifton

    Steve: Yes, “var pageTracker” is the declaration of a variable in the GATC. So if you have: “var newTracker” you need to change all references to reflect this.

    Chandra: The way around this is to have all direct links to PDFs go to a landing page, first and then follow the click throughs. See Tracking Links to Direct Downloads in Chapter 9.

    Reply
  46. Chandra Pandey

    Hi Brian,

    First of all, thanks for all your good work on the scripts! This resource is extremely helpful.

    I have been trying to track downloads and had success with tracking files being downloads / viewed on my site.

    However, what I’m writing in about is slightly different.
    I have links from other sites (e.g. Wikipedia) which give users the option to download a .pdf on my site. They are mentioned on the Wikipedia site as url to ‘http://www.mysite.co.uk/xyz.pdf’

    This makes it possible for the user to directly view the page. This is further complicated because my site is database driven and all the files are present in the repository.

    Is there a way of tracking these Inbound downloads from my site?

    Thanks a ton!
    Chandra

    Reply
  47. Steve Bowsher

    Hi Brian,

    I’ve, unsuccessfully, been trying to implement this code onto our site. We have multiple profiles in our GA set-up, with a naming convention of firstTracker, secondTracker, etc and was wondering whether I will need to amend the 3 lines with ‘pageTracker’ mentioned to ‘firstTracker’ etc?

    Steve

    Reply
  48. Jason Hardgrave

    It is in the code in the body tag on line 57
    .

    Anyway, I know how much of a pain IE is, and we could all use a little more support and fixes from Microsoft rather than advertising, but is there a work around for this problem with IE? Unfortunately, IE is still the standard on most sites, and cutting out that part of our audience would make the tracking shaky at best.

    Again, an example of a coder coming up with something cool and IE breaking it by not following the rules 🙁

    Thanks again for your time and attention

    Reply

Submit a Comment

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Share This