Popular Posts

I’ve gone back and forth about whether adding analytics to my blog for a while now. Recently I added a privacy focused analytics solution with Umamai that allowed me to add a new feature to my site.

Personally, I think website analytics have gotten a bad rap. At their core, analytics are a way to get feedback on the performance and reach of our sites. We spend a lot of time building these sites and their content, it’s only natural that we’d want to know if anyone else is interacting with them.

If I was going to add analytics, they need to satisfy a few requirements:

  • Respect my reader’s privacy
  • Free of cookie banner requirements
  • Open-source and maintainable
  • API to access the data
  • Easy to setup

Fortunately, Umamai meets all of these needs quite nicely.

Setup

Setup with Umamai is pretty easy. There is a self-hosted open source solution or a reasonably priced cloud solution. Since this is only a hobby project, the free tier of cloud hosting worked for me.

Once our account is setup, we get access the the dashboard. Setting up a website will give us access to a website ID that we’ll need for adding website tracking. Drop the little script into your <head> and we’ll soon be seeing metrics in our website dashboard.

<script
  defer
  src="https://cloud.umami.is/script.js"
  data-website-id="xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
></script>

Page Stats

Now that we have the metrics in place, it would be nice to have a way to download the website metrics for use with our site. Fortunately, Umamai has an API that allows us to do just that.

I use a Makefile locally to handle various project related tasks but the same strategy could be applied with other methods.

# Get the timestamp for now in milliseconds
endAt = $(shell echo $$(( $(shell date +%s) * 1000 )))

# Get the timestamp for 30 days ago in milliseconds
startAt = $(shell echo $$(( $(endAt) - 2592000000 )))

.PHONY: stats
stats:
	curl -H "Accept: application/json" -H "x-umami-api-key: ${UMAMI_API_KEY}" \
		"https://api.umami.is/v1/websites/${UMAMI_WEBSITE_ID}/metrics?startAt=$(startAt)&endAt=$(endAt)&type=url" \
		> assets/data/stats.json

With this added to a local Makefile I can simply type make stats and it will drop my stats for the last 30 days right into my site’s data folder.

[
  { "x": "/blog/great-sanddunes/", "y": 75 },
  { "x": "/blog/unplugged/", "y": 66 },
  { "x": "/", "y": 23 },
  { "x": "/blog/", "y": 3 },
  { "x": "/blog/indieweb/", "y": 1 },
  { "x": "/subscribe/", "y": 1 }
]

Now that the page metrics are in place, we can use them to generate a list of popular posts for people to read. I use Hugo for my site so here is an example of mapping the metrics to the blog pages and displaying the top 3 most popular links.

{{- $data := dict }}
{{- $path := "data/stats.json" }}
{{- with resources.Get $path }}
  {{- with . | transform.Unmarshal }}
    {{- $data = . }}
  {{- end }}
{{- else }}
  {{- errorf "Unable to get page stats resource %q" $path }}
{{- end -}}


<h2>Popular Posts</h2>
<ul>
  {{- range $index, $entry := $data }}
    {{- if le $index 3 }}
      {{- $matches := strings.FindRE `\/blog\/.+\/` $entry.x }}
      {{- if gt (len $matches) 0 }}
        {{- with site.GetPage $entry.x }}
          <li><a href="{{ .Permalink }}">{{ .Title }}</a></li>
        {{- end }}
      {{- end }}
    {{- end }}
  {{- end }}
</ul>

Now we can include this partial anywhere we want to get a list of popular posts for my site. You can see it in action at the bottom of this post.

Updating the List

My blog is a static site, so the popular post list will only update when I update my site. If I posted more regularly, I could probably rely on updating the metrics on every build. Since I tend to post infrequently, I’ll probably look into setting up a job to perform a site build once a day to keep things fresh.

Disclaimer

I work for Wizards of the Coast. The views expressed here are my own and do not reflect those of my employer.