Archive for January 25th, 2009

Sooner or later you, dear NoScript user, may face this puzzle: you already allowed every single script source looking "legitimate" on a certain page, but the damn thing stubbornly refuses to work as it should. Then, in a moment of enlightenment, you dig inside your Untrusted menu, and there you find You put it there long ago because you don't like to be tracked, but now you cross your fingers and temporarily allow it... et voilà, the page starts behaving!

Now, you may ask why the hell a web site requires Google Analytics scripts to be enabled for providing its basic features, and you might be right: no reason for that. On the other hand, a growing number of web sites leverage Google Analytics for more than just tracking page views and navigation: they also try to collect finer grained usage data about some specific features of theirs. Therefore they call functions or reference objects from from their own "1st party" specific scripts, e.g. when you click a certain button: if is blocked by NoScript (or by AdBlock Plus, or by your hosts file, for the matter), the 1st party code referencing it will obviously fail and the button will stay dead. You can be hinted about Google Analytics being the culprit by opening Tools|Error Console and watching for errors like "urchinTracker is not defined" or "_gat is not defined”.

So far, all you could do about that was allowing But latest NoScript ( or above) implements a new feature, called Surrogate Scripts, which works around this problem out of the box and is customizable enough to cope with similar 3rd party script issues in the future. How does it work? Very simple: whenever an external script is blocked, NoScript checks if its URL matches a certain pattern, and if it does an alternate user-provided surrogate script gets executed instead, in the context of the loading page. There you can define surrogates for any required object or function.

There's no UI for this feature (yet?), but its intended audience is likely geeky enough not no need one.
You can specify as many URL/surrogate mappings as you want, by creating a couple of about:config preference entries under the noscript.surrogate root.
The built-in Google Analytics mapping can be regarded as a reference:

  • *
  • var _0=function(){};with(window)urchinTracker=_0,_gat={_getTracker:function(){return {__noSuchMethod__:_0}}}
    var _0=function(){};with(window)urchinTracker=_0,pageTracker={_setDomainName:_0,_trackPageview:_0,_initData:_0},_gat={_getTracker:function(){return window.pageTracker}}*

If you want to exempt some pages from this replacement (e.g. because they already provide a graceful fallback for missing external scripts), you can add an URL pattern to the preference, e.g. * * Script Surrogates can be disabled globally by setting noscript.surrogate.enabled to false.

Happy hacking :)


Jesse Andrew told me about some Google Analytics API not covered by the original surrogate, so rather than trying to find out every possible tracker method, present and future, I decided to catch them all by exploiting a nifty Mozilla JavaScript feature, i.e. __noSuchMethod__. Please get (latest development build) if you want to this more reliable approach right now.

Update 2

Since I've been asked by concerned non-geeks (especially those who can't read JavaScript code) what exactly the Google Analytics surrogate does, here's a plain English description: the Google Analytics surrogate script does NOTHING. It’s a dummy “catch all” replacement for the most common Google Analytics functions: it makes the calling pages happy, helping not to break sites, but doesn’t send nor receive anything to/from Google.

Update 3

NoScript now supports a second kind of script surrogates, called "Page-level surrogates": if the sources patterns start with the "@" character, the replacement scripts are executed before the matched page starts to be parsed and before any other script can run. This allows preemptive patching of the loading page, similarly to GreaseMonkey but in a more pervasive way, since GreaseMonkey's scripts can run only when the DOM is already parsed (i.e. after page scripts already run).

Bad Behavior has blocked 725 access attempts in the last 7 days.