Jesse Wunderlich

USMC Sgt (ret) · UAS operator · serial builder · dad · lake country, MN
NO COOKIES NO TRACKERS NO ADS

A visitor counter that doesn't track you

· 2 min read · by Jesse Wunderlich

Look in the sidebar and you’ll see a little odometer. I wanted one because I miss the web where a hit counter was just a fun thing on the bottom of a page. I did not want to bring along the tracking that came with the modern version of it. So I built my own, and here is exactly what it does.

What you see

The counter is an SVG image. When your browser loads the page, it asks my server for /api/counter, and the server draws the digits and sends back a picture. There is no script on the page for it. That is why the site can keep a strict content security policy and ship no client JavaScript for this.

What it stores

The count lives in Upstash Redis. The main thing stored is one integer: the total.

That alone would count every reload, so I wanted something closer to unique visitors per day. When a request comes in, the server takes your IP address and your browser’s user-agent string and runs them through an HMAC (a keyed hash). The key is a secret that changes every day. It is derived from the Redis token plus the current UTC date, so yesterday’s hashes can’t be matched against today’s.

That hash becomes a short-lived key in Redis, set only if it doesn’t already exist, and set to expire after 24 hours. If the key was new, the counter goes up by one. If it already existed, you were already counted today, and the number stays put.

Your raw IP address is never written to Redis and never logged by the counter code. The only thing that exists is the hash, and it disappears on its own after a day.

The small rules

  • It only answers GET and HEAD requests. Anything else gets a 405.
  • Requests that look like bots, crawlers, link previewers, and monitoring tools can read the number but don’t add to it.
  • If Redis is unreachable, the page doesn’t break. The odometer shows a row of dashes.
  • The response isn’t cached, so the number is current.

Why bother

Mostly because I can, and because I think it’s a good trade. I get the fun of a counter. You get a page that doesn’t set cookies, doesn’t load third-party trackers, and doesn’t build a profile of you. The whole thing is one small file, and this post describes everything it does.

It isn’t perfect. A hash of an IP and a user-agent is a rough stand-in for “a person.” Two people on the same network with the same browser will look like one visitor, and one person on a phone and a laptop will count twice. I’m fine with that. It’s a counter, not an audit.

If you want the plain-English version of everything this site collects, it’s on the privacy page. If you want to see how the rest of it is put together, check the colophon.

permalink