bye bye webmentions...

Wouter Groeneveld 3 weeks ago
parent 97fb468078
commit 1009e6f756

@ -18,7 +18,6 @@ enableGitInfo = true
pagination = 30
description = "Freshly Baked Thoughts"
webmentionServer = ""
copyright = "&uarr;&nbsp;<a href='#header'>Top</a> <svg class='icon icon-small' width='16' height='16'><title>lightbulb icon</title><use xlink:href='#bulb'></use></svg> <a href='/'>Brain Baking</a> | <a href='/archives'>Archives</a> | <a href='/copyright-and-tracking-policy'>&copy; CC BY 4.0 License</a>."

@ -0,0 +1,69 @@
title: "Why I Retired My Webmention Server"
date: 2023-05-08T09:37:00+02:00
- webdesign
- webmentions
- indieweb
After two years of building and running my own fully featured Webmention server, I think it's time to shut it down. I've been thinking about doing so for a few months, and [Eli's comment]( has finally pushed me to take a closer look whether it's worth it or not:
> I think Im ready to wholly remove all indieweb functionality from my website. The only Webmentions I receive at this point are spam from a Russian poker website that likes to link to 1 random blogpost of mine that has nothing to do with gambling, or gaming.
Before I get to the _why_, I want to take a moment to congratulate the IndieWeb community on their efforts to bring back a personal World Wide Web, a place where people come first and own their domains, a place where things are happily shared instead of stolen stolen, a place where cool things inspire others to tinker. I've been a fan of the concept ever since I stumbled upon it, although the implementation of their ideas isn't always ideal (see [the IndieWeb mixed bag](/post/2021/03/the-indieweb-mixed-bag/)). My [own Webmention implementation](/post/2021/05/beyond-webmention-io/) is freely available and fully implements the protocol, verified by unit tests, so knock yourself out if you decide to ignore the premise of this post.
## Why Webmentions can be a drag
Maintaining _anything_ can be a drag, honestly. But let's focus on a generic self-hosted Webmention server instead.
### 1. Spam
As Eli mentioned, and quite self-explanatory. I spent days coding in guard clauses---see [fighting Webmention and Pingback spam](/post/2022/04/fighting-webmention-and-pingback-spam/)---but in the end, that doesn't fix the underlying issue: not everyone on the internetz behaves the way they should, and in the end, whether you like it or not, you're still either deleting spam in your inbox or spending time sifting through domain (dis)allow lists. It's a never-ending story. My disallow list was larger than my allow list. AI-generated Wordpress sites pop up everywhere, "mentioning" your stuff to get a piece of your clicks.
I'd rather spend my Sunday doing something else.
### 2. Maintenance
This includes database maintenance---compression, upgrades, yaddayadda---and server maintenance---`sudo systemctl restart gojamming` yaddayadda.
I'd rather spend my Sunday doing something else.
### 3. Very few mentions are worth mentioning
That's right; about `75%` of the mentions I do receive are completely useless "like" messages. Microformats supports multiple "types" of mentions, whether it's a comment on your article, an RSVP, or just a very social media-like "like" with an empty body. I had to write a few lines of code to filter out that stuff. If you don't believe me, visit a random Webmention-enabled site and scroll down to the "comments" until you see a lot of Twitter-infested avatars or hearts without any text.
### 4. Microformats is far from perfect
A Webmention parses HTML to scan for the author, aforementioned mention type, and contents. The problem is that some people send mentions as type "like" with an empty body, and some as type "mention" with body text "like". Then your parser fails to detect a `h-author` or someone placed one of those bogus classes on the wrong `<div/>`. Every little design mistake someone makes on their site results in a fucked up mention. You did take all those stupid cases into account while building your server, did you?
### 5. Most mentions come from Bridgy
[Bridgy]( is a free service that allows you to connect social media accounts to your Webmention server (probably using another hosted service, [](, meaning for instance tweets of people mentioning or replying to your link via Twitter suddenly appear as a mention on your site. Great stuff, right? Except those people have no idea their avatar and text is being yanked. I've questioned these practices before and it's clear that they're built without thinking too hard about privacy.
As a result, I had to anonymize everything coming from Bridgy myself. Yet another unnecessary `if {}` clause, yay. By the way, using a hosted Webmention server kind of defeats the purpose of the whole IndieWeb "own your data" mantra!
### 6. Very few mentions are received at all
In the past month, I think I received exactly two mentions: both originating from ``, my other blog. Me, myself, and I! I did/do receive the occasional mention, but I'm acquainted with most of these authors and we also exchange pleasantries using email, a protocol I deem much more appropriate for the occasional digital message or two.
I've been on the fence several times, and the `/notes` section was solely there to provide a mention starting point for other sites, but I'd rather just send out emails: contrary to the Webmentioned notes, they usually net interesting conversations.
### 7. My own server is far from perfect
When [I published a blogpost and then deleted it](/post/2023/01/i-published-a-blogpost-and-then-deleted-it/) in January, I accidentally triggered mentions to be resent for _every single post_ on Brain Baking due to how my server uses the RSS feed and timestamps to determine which article to process. Whoops. Even though that's fixed now, I'm sure the server is still a potential danger to both others (sorry about the spam!) and my own server (please don't hack me).
### 8. It complicates my website
As mentioned, before you can enable Webmentions, you need to be "[IndieWeb-complaint](" by sprinkling CSS pseudotags to label content and help Microformat parsers correctly identify your data. If your HTML structure isn't up to snuff it could require reshuffling things back and forth, as a `p-author` tag should be within a `h-entry`. After hours of cursing I just ended up pasting `h-entry` on the root `<html/>` element. For now, I'll leave the tags as is.
I eventually threw out [Gemini compatibility](/post/2021/04/using-hugo-to-launch-a-gemini-capsule/) precisely because of that: yet another thing that needlessly complicates matters.
I'd rather spend my Sunday doing something else. Wait, I already said that, didn't I? I'm at a point in life where I need to optimize my time spent with anything, and again, If I have to choose between spending time coding in yet another edge case or just writing and replying to a lovely email from a reader, I'd prefer the latter, even though I highly enjoyed building the Go server, and when things start itching again, I'll probably build another IndieWeb tool in the future. And no, that problem isn't fixed by outsourcing your mentions, it just triggers other more questionable problems.
If you'd like to comment and/or reach out, I'd be happy to receive, read, and respond to your email. The "reply by email" button is still there in the RSS feed. Cheers!
_(No mentions were sent during the publishing of this post)_

File diff suppressed because it is too large Load Diff

@ -1,13 +0,0 @@
const { readFileSync } = require('fs');
if(!process.env.WEBMENTION_TOKEN) {
throw "No webmention token set!"
const configToml = readFileSync(`${__dirname}/../config.toml`)
const endpoint = /webmentionServer = \"(.+)\"/.exec(configToml)[1]
module.exports = {
token: process.env.WEBMENTION_TOKEN

@ -1,12 +1,5 @@
const { webmention } = require('jam-my-stack');
const wmconfig = require('./_conf.js');
(async function() {
// 1. send webmentions
console.log("1. Sending webmentions...")
const since = await webmention.send("", wmconfig)
console.log(` -- done`)
console.log("-- all done!")
console.log("-- postdeploy: all done!")

@ -1,24 +1,24 @@
const { mastodon, goodreads, webmention, youtube } = require('jam-my-stack');
const { mastodon, webmention, youtube } = require('jam-my-stack');
const fsp = require('fs').promises;
const wmconfig = require('./_conf.js');
const rootdir = `${__dirname}/../`;
(async function() {
// 1. get webmentions
console.log("1. Fetching webmentions...")
// get webmentions (turned off, 08/05/2023)
console.log("-- Fetching webmentions...")
const mentions = await webmention.getWebmentions("", wmconfig)
const json = JSON.stringify(mentions, null, 4)
await fsp.writeFile(`${rootdir}/data/webmentions.json`, json, 'utf-8')
// 2. generate youtube thumbnails
console.log("2. Generating YouTube thumbnails...")
console.log("--> Generating YouTube thumbnails...")
await youtube.thumbify({
postDir: `${rootdir}/content/post`,
downloadDir: `${rootdir}/static/img/yt`,
overlayImg: `${rootdir}/play.png`
console.log("-- all done!")
console.log("-- precommit: all done!")

@ -27,7 +27,6 @@
<div class="belowsingle">
<div class="txtblock">
{{ partial "single-related" . }}
{{ partial "single-webmentions" . }}
{{ partial "single-comments" . }}

@ -51,7 +51,6 @@
<div class="belowsingle">
<div class="txtblock">
{{ partial "single-related" . }}
{{ partial "single-webmentions" . }}
{{ partial "single-comments" . }}

@ -8,8 +8,6 @@
<link rel="me" title="Mastodon" href="{{ .Site.Author.mastodonlink }}" />
<link rel="me" title="Github" href="{{ .Site.Author.githublink }}" />
<link rel="author" href="{{ $base }}humans.txt" type="text/plain" />
<link rel="webmention" href="{{ .Site.Params.webmentionServer }}/webmention" />
<link rel="pingback" href="{{ .Site.Params.webmentionServer }}/pingback" />
<!-- generate a thumbnail -->
{{- $logo := "img/bblogo.png" -}}
{{- $thumb := $logo | absURL -}}

@ -1,59 +0,0 @@
{{ $mentions := (where (where (where .Site.Data.webmentions "relativeTarget" "==" $.RelPermalink) "content" "!=" "") "type" "!=" "like") }}
{{ $wmServer := .Site.Params.webmentionServer }}
{{ if $mentions }}
<h3 class="page-header" id="mentions">
<a href="#mentions">
<svg class='icon icon-text' width='24' height='24'>
<use xlink:href='#discuss'></use>
Mentions and Replies
<div class="tootlist" style="margin-bottom: -3rem">
{{ $i := 0 }}
{{ $done := 0 }}
{{ range $mentions }}
{{ $i = add $i 1 }}
{{ if and (gt $i 5) (eq $done 0) }}
{{ $done = 1 }}
<a href="#morementions"><button>Show {{ add (sub (len $mentions) $i) 1 }} more...</button></a>
<div id="morementions">
{{ end }}
<article class="u-comment h-cite toot">
{{ $name := | safeHTML }}
<p class="p-content p-name">
{{ if .content }}
{{ .content | safeHTML }}
{{ else }}
{{ $name }} liked this post.
{{ end }}
<div class="meta">
<svg class='icon icon-small'>
<use xlink:href='#cal1'></use>
<time class="dt-published" datetime="{{ .published }}">
{{- $publishedAsDate := .published | time -}}
{{ partial "reldate" $publishedAsDate }}
<a rel="author" class="u-author h-card u-url permalink" href="{{ .source }}">
{{ $name }}
{{ end }}
{{ if gt $i 5 }}
<a href="#mentions"><button>Collapse mentions</button></a>
{{ end }}
{{ end }}