I follow what's published on FiveThirtyEight via their RSS feed. On average, I probably click through to one article a week. A week or two ago, I clicked through to a FiveThirtyEight story and the browser tab where it was loading became unresponsive. My reaction was "somehow they managed to get around Ghostery and do some advertising/tracking shenanigans to freeze my browser, oh well", and I closed the tab. The tab hung around for a minute but then went away. I figured it was an isolated incident.
Fast-forward to this morning. I saw a story I was interested in reading in my feed reader so I clicked the link. New tab opens, and is immediately unusable. I can't scroll, I can't open dev tools, I can't close the tab. This time I was a bit more motivated to figure out what was going on.
Once I got the rogue tab closed, I whitelisted FiveThirtyEight. Then the page loaded and operated as expected. But by this point, I couldn't care less about the actual content—I wanted to know why the page froze when running an ad blocker.
If you've run an ad blocker for any amount of time, you have seen weird, half-rendered pages while cruising around the web. Occasionally sites will only render their content after some combination of advertising and tracking scripts have loaded. Others will show you a pop-up if they detect a blocker and ask to be whitelisted. Sometimes I whitelist, sometimes I give up and forget about whatever previously grabbed my attention.
This FiveThirtyEight experience was different. Missing content and broken pages, I understand that. A locked up browser tab from a reputable site I frequent is something different. I really wanted to figure out what was happening.
Ghostery was clearly the culprit, but why? I've been using it for a couple years now, and can't recall having a problem like this in the past.
I started re-blocking each tracker identified by Ghostery. I'd block one, reload. If the page worked, I went to the next one. None of the trackers from the big, recognizable companies (Google, Facebook, Adobe) were causing the problem. I could block those and the page still worked.
I narrowed down the problem to the advertising tracker called "NetRatings SiteCensus". I'd never heard of it, but apparently it's something from Nielsen (of TV ratings fame, I think).
Visiting the page in question with dev tools gave me a little more info:
Over 2300 requests, running one request per millisecond based on the timestamp in the URL query string. That's enough to freeze any browser tab. The full URL to the script in question is:
https://cdn-gl.imrworldwide.com/novms/js/2/ggcmb510.js?_=timestamp. That script wasn't necessarily problematic, but rather all the requests to get it.
Looking at the "Initiator" for all these requests, I headed over to
Now I was getting somewhere:
espn.track.initNielsen was trying to load the script in question, then executing a function to call
espn.track.nielsen. Who was calling
nielsen, of course. The infinite loop was taking shape.
What about the next level up the stack? Who starts this
After diligently dissecting 8k lines of code... just kidding, I ⌘ + f-ed around until I figured out that
espn.track.nielsen is first called by another function called
init defined inside of another function called
espn.track.trackPage. That one,
trackPage, is called by another function called
loadOmniture that's defined in a
<script> tag in the page's HTML just inside the closing body tag. Whew.
Here's a recap starting with page load, rather than working backward from the two functions that endlessly call each other:
- Page loads
<script>tags in the page are executed
espn.track.trackPagepassing an object with a property called
enableNielsenthat is truthy
trackPagedefines a local function called
initand runs it
espn.track.nielsenwhen the aforementioned
enableNielsenproperty is true-ish
- our new friend
nielsenchecks if a global variable named
- when there's no variable named
initNielsentries to insert the Nielsen NetRatings SiteCensus script and runs
Ghostery blocks that script, so we get an endless loop where each loop iteration makes a request.
Why doesn't this happen without an ad blocker? That is because the Nielsen script in question,
https://cdn-gl.imrworldwide.com/novms/js/2/ggcmb510 defines a global named
NOLCMB when it loads, thereby avoiding the infinite loop caused by
initNielsen (steps 7 and 8 above).
NOLCMB global acts as a flag as to whether or not the Nielsen tracker is loaded. The code naively assumes that when the tracker isn't loaded, it can load it. And so it tries over and over.
In summary: request blocked? Do it again! Again! And again. Yep, again. Repeat thousands of times. browser tab dies
This is the one of the few experiences I've had where running an ad-blocker made a page less usable. And since I'd like to avoid that, I've left my whitelisting of FiveThirtyEight in place.