Profile pic of Tommy KuTommy Ku's Blog

Reading and thinking

Website analytics for lazy people

Posted on  by Tommy Ku

This post is more than 2 years old, it may contain outdated information

Imagine shouting into the void where there’s absolutely no echo. This is what it’s like writing this blog after I have removed Google Analytics. I got organic traffic from time to time back when Google Analytics was enabled, and now I have zero idea.

Pretty sure I am not going back to over-tracking my visitors—but I do want to have an idea at least view counts to my site. Knowing th view count motivates me to continue writing things that someone might find useful.

Being lazy and prefer doing things as simply as possible, I know that most of the web traffic analytics services out there won’t fit. I want something I can drop in, and get out of at any time.

Building a program to automate and perform a computationally expensive task is one thing that all software engineers are more than prepared for. But doing things the layman way and achieve virtually the same result in lower cost is much much better.

Solution: + tracking pixel link click dashboard link click dashboard tracking a link to a…pixel.png?

The solution I opted for is easy to set up (took me 10 minutes to get first tracking in) without any configuration. I first created a transparent, 1x1 pixel PNG file. Then, I created a link to the pixel.png’s supposed URL.

Then, I inserted the link as an <img> to my homepage’s index.html.

<!-- Tracking pixel -->
<img src=""
     style="width: 0px; height: 0px; margin: 0; padding: 0; visibility: hidden;" />

If you have used before, you’d have noticed that the URL translation from URL to the original URL happens transparently to the user. This is done my a HTTP 301 Moved Permanently redirection returned by, which most browser would automatically follow to the redirected URL.

Therefore, from the users perspective loading this 1x1 pixel, 564 bytes, invisible image won’t make any difference in terms of experience and load speed. To the browser, it’s equally transparent because it’s a HTTP 301 redirection. Ad blockers usually don’t block frequently used link shortener such as (my uBlock Origin didn’t block it), so I am more or less sure I am not missing any visitor counts.

The benefit I get from this extra tracking pixel is that every time the link is hit, would increase its counter and I am able to see the visitor counts to these pages from One caveat to this approach is that I am not able to distinguish repeating visitors, which is fine by me.

When the browser is making a request to the URL, it includes a header entry referrer: , which means for the same site you can reuse the same URL across pages. On the dashboard you are able to see the breakdown of requests by referrer page. Edit: You cannot. Only the website’s domain, not full page URL, is included in referrer field (2020-12-30) doesn’t forget to sneak in a cookie, but it can be blocked if user disables third-party cookie.

Cookie from getting blocked, don’t

If you want strict segregation between tracking URLs, you can create one per page, and link to the same image file. However would give you the same URL if you’re linking to the same URL, so you need to add an extra query parameter (?now) to make them look different (bit still resolve to the same image file). => => please don’t block me even though I misused you.


Just to sweeten it a bit for the users to swallow accept this visitor counting approach, I have added an event listener to the tracking pixel <img> tag which changes from a 🙈 (see no evil monkey) to 👀 (eyes) emoji after the tracking pixel has finished loading.

Eyes emoji after tracking pixel is loaded
“I see you” (on

Clicking on the icon leads users to this article. Visitors will then realize that their visit is being counted.

  a#tracking-status {
    display: block;
    width: 0;
    line-height: 0;
    margin: 0 auto;
    padding: 0;
    text-decoration: none;

  a#tracking-status.unloaded::before {
    content: "\1F648";

  a#tracking-status.loaded::before {
    content: "\1F440";
<!-- Tracking pixel -->
<a href="" id="tracking-status" class="unloaded" title="Tracking Indicator"></a>
<img src=""
     style="width: 0px; height: 0px; margin: 0; padding: 0; visibility: hidden;"
     onload="javascript: document.querySelector('#tracking-status').classList.replace('unloaded', 'loaded')" />

Why not self-host/use other analytics services

The market is saturated with web analytics services, most of them have free tier, many available for self-hosting. I could have used any of them instead of going through this approach.

Aside from ordinary web analytics solutions, I could have also analyzed the web server’s access.log for page view counts.

The reason I didn’t take the access.log analysis approach is because the site is hosted on GitHub Pages. Despite the middle layer Cloudflare provides analytics service, it comes with a cost. Visit count needs to happen on client side somehow.

As for self-hosted analytics service, I simply don’t want to pay/setup a service on cloud simply for analytics which I need to maintain over the years. At such a small scale I like to do things the layman way.

Lastly, the reason I am not using other hosted analytics service is because this approach is so simple I can easily swap out to something else later if I want to.

Bonus: reactions

Loading an image means adding a count to the tracking. If image loading can be controlled by JavaScript, users can selectively load images to record their reactions to the page, such as leaving “Like” on the page.

You could also look at...

This post first appeared on . Permalink:

About the author

Profile pic of Tommy Ku

Tommy Ku, a Hong Kong-based Software Engineer experienced developing PHP and Java-based web solutions and passionate in Web technology.

Also a hobbyist digital and film photographer.