Field note

The analytics that classified everything and sent nothing

A week of clean code, a dashboard of zeroes, and the two reasons an empty report is the most expensive thing on a screen.

By ·Published

The short answer

This site classified every click correctly and delivered none of them to Google Analytics. The tag loads late, and an event sent before the tag is configured is discarded without an error. A second bug hid a whole section from its own view counter. Both were invisible to the test suite, because both were true of the browser rather than of the code.

SHT-02Field note

01

A dashboard of zeroes is not a report

The site had traffic, the pricing page had readers, and the events panel in Google Analytics had nothing in it. That is the single most misleading screen in this trade, because an empty report and a broken pipe look exactly alike, and only one of them is news. The honest reading of a zero is that you have learned nothing yet.

02

The first fix was real, and changed nothing

The call looked wrong. It was rewritten to the shape the documentation uses, deployed, and checked again the next day. Still nothing. That is worth saying out loud, because a plausible fix that changes nothing is more dangerous than no fix: it closes the question. The only thing that reopened it was going back to the deployed page and watching what the browser actually sent, which was nothing at all.

03

What was actually wrong

The tag is loaded on idle so it never competes with the page for the first render. That is the right call for the reader and it moves the tag's arrival to a moment nobody controls. A click on a button near the top of a page can happen before that moment. An event sent then is not queued and not rejected: the function it is passed to does not exist yet, so the event is dropped in silence, and by the time the tag is configured the click is gone.

04

The queue

Now every event goes into a small array first. A tick checks whether the tag has arrived; when it has, the array is flushed in order and the queue goes back to being empty. It gives up after thirty seconds, because a reader who has blocked analytics is not a reader to keep waiting on, and a queue that never drains is a memory leak with a polite name. Fifteen lines, and the events arrived.

05

The second one was hiding in the same week

One event still never fired: the view counter on the pricing block. It used an intersection observer with a threshold, which sounds like a fraction of the screen and is a fraction of the observed element. The pricing block is taller than a phone screen, so the fraction it asked for could never be reached on the device most readers use. The block was always on screen and the observer was correct to say it had never crossed the line.

06

Why neither could fail a test

There was a test. It asserted that a click on a call to action produced an event with the right name and the right properties, and it passed, before and after, because the classification was never the broken part. A unit test of a function that sends can only tell you the function was called. It cannot tell you anything about the destination, which is the only part anyone cares about.

07

What the studio does with this now

Any change to measurement is checked at the destination, on the deployed page, with the network tab open, before it is called done. The same rule already applies to database work here: a migration is verified by asking the database what it has, not by reading the file that was supposed to change it. Measurement had been the exception, and it was the exception because a green dashboard and an empty one look identical from a terminal.

08

The part worth taking away

If a report you own has been quiet for a week, do not read the quiet as a result. Find out whether anything is arriving at all, and make the two cases print different sentences: nothing happened, and nothing arrived. Every system this studio builds has that distinction written into it somewhere, and it is written in because of weeks like this one.

SHT-04FAQ

Questions this post answers.

N01Why not just load the analytics tag first?
Because it costs the reader. The tag is not needed to read the page, and loading it early competes with the content for the first render on a phone. Deferring it is the right trade, and it puts the tag's arrival outside anyone's control, which is a thing the code that sends events has to account for rather than assume away.
N02How would I know this is happening on my own site?
Open your own site on a phone or in a narrow window, open the network tab, and click something you believe is tracked. If no request leaves for your analytics provider, the event does not exist, whatever your code says. This takes about a minute and is the only check that answers the question.
N03Does an empty analytics report mean nobody is converting?
It means you do not know. An empty report has two causes that look the same: nothing happened, or nothing arrived. Until you have ruled out the second, the first is a guess, and it is the guess that gets acted on because it is the one that sounds like data.