me
https://shub.club
    loading
00:00:00
*

My website's stats only gets updated when I make a new blog post

I think I have a kinda overkill analytics stack for my website.

I host an Umami Analytics instance on Vercel (0$/m), and host the data on a database on a vps that I spend 15$/mo on (I use it for other things too, dw).

I say it's overkill because realistically, I just want a view counter, I don't really need anything else, knowing what country my readers come from, cool but not changing my life. The bare view metric is all I need to know to see what people find the most interest on my website. I could swap to something simpler, but my system works, and it's free (for now), so why not.

All this data though brings me an idea - let's show my website visitors the viewcounts for pages on this site.

Since I'm storing all this analytics data in a DB anyway, might as well do something with it. I already feel embarrassed paying 15$ a month to have data on a VPS, so I don't want to spend even more, so we have to make sure I don't add any new services to this feature.

Then it came to me - it's not super critical that you see live viewcounts, so why not inject those views in our build system that I get for free, with my free static site hosting from DigitalOcean. (I'm not sponsored by anyone, I swear)

The code part...

Since I already use 11ty as my build system, this is pretty easy, I can just hook my DB url and then calculate views on the build step:

import  pg from 'pg';

async function getViewCounts() {
  const query = `SELECT count(url_path), url_path FROM website_event WHERE event_type = 1 GROUP BY url_path;`

  const client = new pg.Client({
    connectionString: process.env.POSTGRES_URL,
    ssl: {
      rejectUnauthorized: true
    }
  });

  await client.connect();

  const response = await client.query(query);
  await client.end();

  let totalViews = 0;

  const counts = {};
  response.rows.forEach(row => {
    const out = parseInt(row.count, 10);
    counts[row.url_path] = out;
    totalViews += out;
  });

  counts['total'] = totalViews;

  return counts;
}

Then I just set it as some global data in my 11ty config:

const lastUpdatedAt = new Date().toISOString();

eleventyConfig.addGlobalData('viewCounts', await getViewCounts());

Then I render it to you:

<div @raw="JSON.parse(viewCounts).total"></div>

As you can see on the homepage, and in the page header (as of Oct 2025), we got views!!!

Conclusion

I think as devs we think always about making data as realtime as possible, but sometimes it's interesting to think of not doing that to save on other constraints, like making things free!

The viewcount system seems to be working, and I think the only big downside is that viewcounts only update when I make more blog posts, which maybe is a good thing :)