21 Mar

tracking external links with AJAX

There was a bit of chat on the #linux chatroom about how Donncha’s linktracker used a method which could be misread as an attempt to spam google.

So, we had a bit of a brainstorm, and Stewie suggested that I try using XMLHTTPRequest to track the link before it is followed.

…which I did.

On the example page, I have three links – two external, and one internal. I guessed that it’s silly to record internal links, when your web logs already do that, so I deliberately told the script to ignore internal links.

The script automatically searches the document for links, and attaches an ‘onclick’ event which calls the link tracker before the link is followed.

Donncha says he’ll be using it in his WPMU WordPress enhancement. I’ll be writing it into a plugin probably tonight, if someone else doesn’t do it first 🙂

update 2005-09-23: noticed this fantastic example of how to avoid all the AJAX malarkey to do this trick. I’m surprised I didn’t think of it myself! I’m blinded by science, I suppose – applying new tricks to everything, when a simple gimmick will do the trick even better. Well done, Martin!

15 thoughts on “tracking external links with AJAX

  1. Pingback: Holy Shmoly! :: Tracking external links with AJAX

  2. Oh man, this is so awesome. Track link hits without screwing with the src attribute? W00t!

    I was going to make a download counter plugin that uses mod_rewrite to change src=xyz.zip to counter.php?download=xyz.zip which then updates something in the db and then returns a .zip to the browser, but this seems way more elegant. I expect your plugin to do what I wanted to 🙂 Eagerly awaited.

  3. That is one sexy script job! Just last weekend, as I was working on a new click-counting plugin (see my sidebar for a demo), I tried combining the functions of a go.php into the plugin’s php to simplify installation and updates. It works quite well but in the html it generates, all of the hrefs include the ugly url with php?argument. I haven’t dropped in the JS to fix the status bar and the save-as filename and now I think I might not bother. Your solution is much prettier on the client side and if I couple that with the unified plugin.php/go.php I’ll have the best of both worlds.


  4. Great code, just one question… onclick doesn’t seem to work when opening new windows (or new tabs in Mozilla/Firefox). Any ideas?

  5. Regarding Google spamming: my redirect script works fine for IE and Firefox with these headers:
    header('Status: 303 See Other');
    header("Location: $url");

    The 303 would (I hope) not affect Google’s perception of page ownership.

  6. I’m wondering how hard it is to tie this js to a particular entry id. I’ve mocked up a hit counter pretty much like go.php- but the ‘hits’ are tied to entry id rather than http://whatever.com. I’m using it with a ‘link’ page that’s open to communal links- so the same link could be submitted by different members. I like to be able to track click-thrus according to the id rather than the uri. So when I pass the variable it looks like ?url=http://whatever.com&id=xxx.

    Any way to add a second variable a la: var url=’go.php?’+b.href+c.title; or something?

    (Yes, I’ve bookmarked your weblog!)

  7. Rob, you could add a new attribute to each anchor tag like this:
    and then set up your var url with some kind of delimiter:
    var url='go.php?'+b.href+'uniquedelimiter'+b.linkid;
    Then update the code in go.php to split the query string at the delimiter and update the database with the resulting data.

  8. Pingback: Skeltoac » Blog Archive » Count My Clicks

  9. Pingback: klog » Blog Archive » External link tracker plugin

  10. Thanks for the kind words 🙂 I have that ‘blinded by science’ effect often enough myself. That’s why it’s always the first thing I check: can it be done simpler?

  11. Pingback: Suttree » Elixir for Immortal Baboon

  12. I noticed that you fire off to the click counter synchronously (ie. using false on the async argument in the call to XmlHttpRequest.open). Did you choose to do this synchronously for a reason?

  13. Mark, I think the reason I chose a synchronous call was that, as this was the final act of a closing page, I wanted to make sure the call was actually made, instead of being nullified as the rest of the page was removed. Call it a “race condition”. I’m not even certain that it matters, but I just wanted to be sure.

  14. I am trying to use this link tracker for my weblogic portal application to track external links. It is really an awesome code to track the external links. I have one yet problem to solve. I need to identify on which portlet this external link was clicked. I tried inspecting the DOM object to retrieve the portlet name but not successful so far. Any ideas to solve this?

  15. Surekha, I’m not familiar with weblogic. Is the portlet identifiable from the URL? ie, if it’s http://blah.blah/testme then is “testme” the name of the portlet? If not, then I think you’d need to find some way of injecting the name into the document (maybe in the Head section as a Meta tag) and that’s beyond the scope of this small script.

Comments are closed.

%d bloggers like this: