Skip to main content
The cover image for "Writing statistics for your Eleventy (11ty) blog"

Writing statistics for your Eleventy (11ty) blog

Sidebar

One of the reasons why I [switched to Eleventy](/2023/10/27/switched-to-eleventy/) was to make it easier to do custom stuff, like creating a [writing statistics page](https://blog.rubenwardy.com/stats/) for my needs. This blog post is to share how I created that page and how you can create one for your blog.

One of the reasons why I switched to Eleventy was to make it easier to do custom stuff, like creating a writing statistics page for my needs. This blog post is to share how I created that page and how you can create one for your blog.

The problem #

My old blog was written in Jekyll. The stats page was incredibly complicated with a lot of template logic. There was also a mess of Python scripts to generate data.

Because of this, one of my fundamental design decisions was to do as much as possible in JavaScript. The data generated by this JavaScript code should match how it is used on the page. The liquid template should just render the data into HTML.

{
	"spotlight": [
		{
			"title": "Total words written",
			"icon": "pen",
			"value": 46891
		},
		{
			"title": "Total posts",
			"icon": "newspaper",
			"value": 78
		},
		{
			"title": "Total likes received",
			"icon": "heart",
			"value": 322,
			"hint": " Experimental, currently only counts Mastodon likes"
		}
	],
	"by_year": {
		"2023": {
			"total": 14,
			"wc_total": 15455,
			"wc_avg": 1104
		},
		"2024": {
			"total": 5,
			"wc_total": 3940,
			"wc_avg": 788
		},
		"2025": {
			"total": 8,
			"wc_total": 5021,
			"wc_avg": 628
		}
	}
}

How it works #

Register the stats plugin #

const pluginStats = require("./plugins/stats.js");

module.exports = function(eleventyConfig) {
    eleventyConfig.addPlugin(pluginStats);
}

Stats.js #

To make it as flexible as possible, we use a filter to pass in the posts to generate data for.

function buildStats(collection) {
	return {};
}

/**
 * @param {UserConfig} eleventyConfig
 * @returns {void}
 */
export default function (eleventyConfig) {
	eleventyConfig.addFilter("stats", buildStats);
}

This buildStats is the meat of the stats page. You can use my wordcount plugin to generate word counts for each post and then aggregate these word points by year, tag, or get a total. For my implementation, see https://gitlab.com/rubenwardy/eleventy-stats-example.

HTML #

The HTML page can pass in the post collection to get statistics:

{% assign stats = collections.post | stats %}

<section id="by-year">
	<h2>By year</h2>
	<div class="row row-wrap gap-4">
		<div class="col-md">
			<h3 class="mt-0 mb-3">Number of posts</h3>
			{% include "bar_chart.html" data: stats.by_year, value_key: "total" %}
		</div>
		<div class="col-md">
			<h3 class="mt-0 mb-3">Total words</h3>
			{% include "bar_chart.html" data: stats.by_year, value_key: "wc_total" %}
		</div>
		<div class="col-md">
			<h3 class="mt-0 mb-3">Average post word count</h3>
			{% include "bar_chart.html" data: stats.by_year, value_key: "wc_avg" %}
		</div>
	</div>
</section>

Conclusion #

Hopefully, this was useful as an example on how to get started with creating a writing stats page for your blog. The power of Eleventy is how easy it is to create custom logic and behaviour for your websites, so you should definitely modify this for your needs.

Again, a full working example is available at https://gitlab.com/rubenwardy/eleventy-stats-example.

rubenwardy's profile picture, the letter R

Andrew Ward

Hi, I'm Andrew Ward. I'm a software developer, an open source maintainer, and a graduate from the University of Bristol. I’m a core developer for Luanti, an open source voxel game engine.

Comments

Leave comment

Shown publicly next to your comment. Leave blank to show as "Anonymous".
Optional, to notify you if rubenwardy replies. Not shown publicly.
Max 1800 characters. You may use plain text, HTML, or Markdown.