I actually can't recall anymore, what got me started with this whole IndieWeb thing. According to my browser history, I visited IndieWeb.org on June 15, 2022, so around a month ago. I read up on Miriam Suzanne's hugely popular post Am I on the IndieWeb Yet? and searched Google for "hugo indieweb" in the hopes there was some kind of recipe to get me started on my static page (I'm a developer and after all *let's say it all together* developers are lazy).

There wasn't THE ONE answer I was hoping for, but instead lot's and lot's of blog posts by people describing their way of getting into the IndieWeb. I was overwhelmed and intrigued at the same time, so I let it rest for a couple of days - four, to be exact. The afternoon of June 20, 2022, I went deep, even deeper than Jamiroquai, into the rabbit hole that is The IndieWeb. Let's retrace my steps through said browser history and commits.

What's IndieWeb?

The IndieWeb is a people-focused alternative to the 'corporate web'. - IndieWeb.org

That's what it says on the cover. It's about owning your content, sharing your thoughts and ideas in one place and then syndicating it to other (social) platforms. What if Twitter, for example, will be bought by a stupidly rich philanthropist who decides to shut it down? Where will all your tweets go?

In my opinion, your Twitter or your Facebook profile should not be your digital identity, owned by a tech company. You should be the sole owner of the content you share online. And that's what IndieWeb encourages people to do.

How does it work?

Alright, from here on, I'll be outlining which steps I took, to make my website ready for the IndieWeb.

I already owned a domain and space to host a site, so that's a given, though I wasn't aware of it being an actual requirement to "become a citizen of the IndieWeb". I first stumbled upon Amit Gawande's post IndieWebify Your Hugo Website, because this site is also generated using Hugo. I actually wrote the theme myself, so making changes to it's markup wouldn't be a problem.

1. Set up Web Sign In

In order to authenticate yourself as the owner of your website using your domain, you will need to set up means to sign in via IndieAuth. That means you use your domain to verify yourself as the owner of your other social profiles.

Just add a rel=me microformat to all your links leading to your profiles on other platforms. That's actually the first thing I changed and made a commit for.

Hint: All code excerpts are reduced to a minimal working example.

<div>
{{ range .Site.Menus.social }}
<a rel="me" href="{{ .URL }}" title="{{ .Name }}"> {{ .Name }} </a>
{{ end }}
</div>

Next, I added an authorization endpoint to validate my identity. There are different services, but IndieAuth.com seems to be the go to solution.

{{ with .Site.Params.indieweb }} <link rel="authorization_endpoint" href="{{
.authorizationEndpoint | default "https://indieauth.com/auth" }}" /> <link
rel="token_endpoint" href="{{ .tokenEndpoint | default
"https://tokens.indieauth.com/token" }}" /> {{ end }}

I also read about it on Ana Ulin's post Using Your Site As Your Login. I went back to her posts about IndieWeb a couple of times during my journey.

2. Add author markup

Next step was to actually provide some basic information about myself, on my website. Sure, I already had an About page, but that's not machine readable. The h-card microformat provides properties that can be parsed. Here's the commit.

<div class="h-card">
<p>
<a class="u-url" href="{{ .Site.BaseURL }}">{{ .Site.Title }}</a>
{{ with .Site.Params.Hcard.Avatar }}
<img class="u-photo" alt="" src="{{ . | absURL }}" />
{{ end }}
<span class="p-name" rel="me"> {{ .Site.Params.Hcard.FullName }} </span>
</p>
{{ with .Site.Params.Hcard.Biography }}
<p>
<span class="p-note">{{ . | markdownify }}</span>
</p>
{{ end }}
</div>

Again, this is a minimal example. There are many more properties that can be added. This is where I found IndieWebify.me, a nice guide to check whether your site is ready for the IndieWeb.

Valid `h-card` entry parsed by IndieWebify.me

Valid h-card entry parsed by IndieWebify.me

3. Add content markup

If you want to publish content on the IndieWeb, it has to be machine readable as well. I added more markup, this time to my post templates. That's the h-entry microformat. IndieWebify.me was a huge helper for this step. A couple of commits and iterations later, my content was recognized correctly.

In this example, I add the following h-entry properties:

  • p-name - the post's title
  • e-content - the post's content
  • p-author - who wrote the post
  • dt-published - when the post was published
  • u-url - the permalink to the post
  • p-category - categories or tags for the post
{{ define "main" }}
<article class="h-entry">
<h1 class="p-name">{{ .Title }}</h1>
<p class="e-content">{{ .Content }}</p>
<div>
<span>Posted By:</span>
<a rel="author" class="p-author h-card" href="{{ "about" | relURL }}">
{{ .Params.author }}
</a>
</div>
<div class="pb-2">
<span>Posted:</span>
<time class="dt-published" datetime="{{ .PublishDate.Format "January 2, 2006" }}">
<a class="u-url" href="{{ .Permalink }}">{{ $publishDate }}</a>
</time>
</div>
<div class="pb-2">
<span>Categories:</span>
{{ range $idx, $category := . }}
{{- if ne $idx 0 }}{{ end }}
<a class="p-category" href="{{ "categories/" | relURL }}{{ $category | urlize }}">
{{ $category }}
</a>
{{- end }}
</div>
</article>
{{ end }}

Valid `h-card` parsed by IndieWebify.me

Valid h-card parsed by IndieWebify.me

At this point, my content is correctly marked up to be consumed by the IndieWeb. This was all relatively easy. The next step was a little bit more challenging, because it meant working on the backend.

4. Add Webmentions

After I read Fundor 333's post How I implement Indieweb, Webmention and H Entry in My Blog I was wondering: What are Webmentions?

Webmentions are a W3C recommendation for conversations and interactions across websites. It's a simple way to notify an URL when it is mentioned i.e. by me or on my site. It is basically a way of interacting with other people's content from your website.

For example: I read a super interesting post on another blog and I want to reply to it, or show my appreciation by reacting to it. I can do that, by writing a post on my site, referencing that other post and add markup indicating this is a response or a like. I can then send a Webmention to that other blog, telling it I reacted to it from my website.

Sounds complicated? Well, it's just like Twitter, where you react to a tweet by commenting or liking it.

I found out there's an easy way to set up Webmentions: Webmention.io, written and maintained by Aaron Parecki. It's a service that handles Webmentions, simply by using Web Sign-In and adding some endpoints as links to your website.

This would work perfectly as kind of a plug-and-play solution for my theme for others to use. But I'm more the guy who likes to self-host stuff. The list of publisher services on indieweb.org has some alternatives for sending and receiving Webmentions. I settled with Go-Jamming by Wouter Groeneveld. It's a really well written replacement for Webmention.io. Also his post Host your own webmention receiver was most helpful.

After Go-Jamming was running on my server, I added the Webmention endpoints.

<link rel="webmention" href="https://jam.chringel.dev/webmention" />
<link rel="pingback" href="https://jam.chringel.dev/pingback" />

Now all that was missing was a way to display them. I read through several blog posts how to render Webmentions in a static site: Jessica Smith's post How I Integrated Webmentions Into My Hugo Static Site, Keith Grant's post Adding Webmention Support to a Static Site and of course Wouter Groeneveld's post that I already mentioned.

Two commits later I had markup for displaying responses (as in comments) and reactions (as in favorites, reposts...).

My current (semi-automatic) workflow for parsing Webmentions goes like this:

  1. (Watch the feed for incoming Webmentions at https://jam.chringel.dev/feed/)
  2. When my site is built with Github Actions, fire up a simple node.js script to fetch Webmentions as JSON from the API
  3. Hugo processes the JSON file while building my site

5. Syndication and Backfeed

One last peace to the puzzle were two terms I came across while reading all those posts that seemed to belong together: POSSE and backfeed.

The first means publishing your content on your own site first, and then post links on other (social) platforms (Publish on your Own Site, Syndicate Elsewhere), for example tweeting about your post with a link to your site.

The latter describes the process of pulling in interactions of your POSSE copies to the original post. So, if someone comments on a tweet with the link to your post, it actually gets reverse syndicated to your site as a Webmention.

Adding syndication markup is easy, it's just another microformat.

{{ with .Params.syndication }} {{ range $silo, $url := . }}
<a href="{{ $url }}" class="u-syndication" rel="syndication"
>
{{ title $silo }}</a
>

{{ end }} {{ end }}

And add the links where you syndicated your post in the front matter.

---
...
syndication:
mastodon: https://fosstodon.org/web/@chringel/...
twitter: https://twitter.com/DeEgge/status/...
...

---

To achieve backfeed, I use a service called brid.gy. Once you are authenticated "Bridgy polls your silo posts, discovers original post links, and sends comments to those links as webmentions" (How to use). It automatically scrapes your site and checks links in your tweets or toots if they have a Webmention endpoint to notify them, when they are mentioned. It works quite well for what I want to achieve, which is displaying reactions to my posts from other platforms on my website.

Next steps

What I'm currently missing is a way of having IndieWeb conversations (IndieWeb level 3, according to IndieWebify.me). For that, I would like to implement a content type notes, short posts as a way to react to other people's posts. There are also microformats for that: in-reply-to, u-like-of and u-repost-of.

Final thoughts

At this point, I'm a Level 2 IndieWeb citizen. I can use Web Sign-In with my site, I marked up content using microformats and I can send and receive Webmentions to and from other IndieWeb sites.

As I said before, there is no out-of-the-box solution for making your website ready for the IndieWeb. It involves a lot of customization, fiddling with services and setting up endpoints.

Also, I think my Webmention workflow is lacking. I need to implement a way to automatically rebuilt my site when new Webmentions are coming in.

Syndication is another troubling topic. The process is a bit convoluted, and I'm not sure I'm doing this right. You see, I have to first publish my post, let my site be built, then syndicate the link (tweet it on Twitter, toot it on Mastodon), then add those tweet- and toot-links to my post and republish my site. If there's a better way, I still haven't found it.

But in the end I'm quite happy with what I've accomplished. Ever since I started this journey IndieWeb-things kept popping in my head at the weirdest of times, and I'm content with the way things are right now. I resurfaced from the rabbit hole. Glad to be back!