This blog's comments are powered by Webmentions
Webmentions are a cool, standards-compliant mechanism to let your corner of the Web interact with other sites. What better way to add a comments system to my new Eleventy-powered blog?
At its core, Webmentions are just a means for one site to notify another that it's been mentioned. That said, webmentions aren't the most intuitive concept to grasp, and implementing them requires additional consideration.
Collecting mentions
Webmentions are sent via simple HTTP message with a source
and target
parameter. These are discovered based on a <link>
tag on your page. You can host this endpoint yourself, but I'm using the excellent Webmention.io to capture all webmentions for my domain:
<link rel="webmention" webc:keep href="https://webmention.io/steele.blue/webmention" />
Webmention.io provides an API that returns all the mentions for a page (or domain). I hit this at build-time, and create a new Eleventy collection with all the entries:
const url = `https://webmention.io/api/mentions.jf2?token=${apiKey}&per-page=1000`;
export default async () => {
const data = await EleventyFetch(url, { duration: '1d', type: 'json' });
const grouped = groupBy(data.children, 'wm-target');
const baseData = {};
for (const key of Object.keys(grouped)) {
baseData[content(key)] = grouped[key];
}
return baseData;
};
Displaying Webmentions
On each page, I include a Liquid component that finds any Webmentions for the URL, and renders each category (likes/reposts/comments):
This felt like the perfect place for a WebC-based component, but I ran into issues as I needed to pass in complex data as props, which isn't supported. Luckily WebC lets you mix in other templating languages, again showcasing its flexibility and pragmatism.
Since this only gets generated at build-time, it doesn't capture new mentions until I rebuild the site, which is fine for me. If you want more dynamism; you could setup a cron job to rebuild their site daily to pull in new mentions.
Webmention.io also supports outgoing webhooks, so you could directly trigger a rebuild when a new mention comes in.
And some people just pull in webmentions by fetching them client-side, and rendering interactions via JavaScript. Seia looks like a pretty straightforward Web Component providing drop-in support with Webmention.io.
Bridging from the Fediverse
Surprisingly, not 100% of online communication occurs via sites sending webmentions to each other. We'd also like to capture comments occurring on Mastodon (or other channels), even if they don't natively support webmentions. In IndieWeb parlance, this is known as a backfeed.
I'm using Ryan Barrett's Bridgy service for this. You can authorize Bridgy to poll your Mastodon account (or social networks) to discover likes/reposts/replies to your toots, and send them back to your site as Webmentions.
In addition, the Bridgy Cinematic Universe supports a number of other features, including posting to Mastodon when you publish new blog entries. And Bridgy Fed lets you create Mastodon/Bluesky/Indieweb accounts from any other permutation; a great way to implement POSSE.
Sending Outgoing Webmentions
As I'm writing posts, I want to send Webmentions to other sites which I reference. This requires a different set of tools, but again the Indieweb has provided a solid foundation to build atop.
I'm using Remy Sharp's webmention
CLI tool, which parses my existing Atom feed, finds all links which support mentions, and delivers a webmention to each.
As noted in his introductory post:
The ability to send Webmentions needs to be a part of an automated workflow - the same way as posting a new WordPress blog post automatically sent pingbacks.
I use a GitHub Action to trigger this, via a single line addition to my existing build:
- run: npx webmention _site/atom.xml --limit 1 --send
You can create a more robust interactivity by enhancing your page's markup with microformats, enabling comments and more.
TMTOWTDI
One exciting facet to integrating Webmentions into your workflow is that there's no one best way to do it. You can use existing tools and services to collect and deliver mentions, or customize them to your own liking.
This does make for a more complicated, "choose your own adventure" aspect to the process, but I find this to be a feature, not a bug. Mixing prebuilt tools with my own code has given me a better understanding of what works well and what I could improve on in the future. I can optimize for certain aspects (like zero-runtime JavaScript) when they tradeoff with others (real-time updates), while using the same protocol as someone who would make a different choice.
I found these sites valuable:
- Keith Grant's Adding webmentions to a static site
- Bob Monsour's Adding webmentions to my site
- Robb Knight's Adding Webmentions to your Site
- Paul Kinlan's Using Web Mentions in a static site
- Max Böck's Using Webmentions in Eleventy
- Sia Karamalegos An In-Depth Tutorial of Webmentions + Eleventy
Send me a Mention
So how do you actually comment on this post? You've got a few options:
Reply to me on the Fediverse, and your post will show up here.
Or even better, write a blog post of your own and send me an outgoing webmention. Websites: the cool and underground social network that you shouldn't sleep on in 2025.
- This blog's comments are powered by Webmentions - 2025
- From Gatsby to Eleventy - 2024
- Mutation Testing with StrykerJS - 2024
- My favorite water bottles - 2024
- Web Push is almost usable with iOS 17 - 2023
- I wired up my bike's GPS to order me pizza during a gravel race 🍕 - 2023
- Running a Playwright script on AWS Lambda - 2023
- Overly Complicate Starting Your Vehicle, Using Home Assistant, an ESP8266, and a Spare Car Fob - 2023
- Generating Custom OpenGraph Cards with Gatsby and the 11ty Screenshot Service - 2023
- Keeping your Fediverse followers when moving Owncast servers - 2023
- Running Owncast with Hardware Acceleration on a Raspberry Pi 4 - 2023
- Vite is Neat - 2023
- Serverless Bike Tracking with a SPOT Tracker, AWS Location + Friends - 2022
- Advent of Code as Soulcraft - 2021
- Gravel Worlds - Long Voyage - 2021
- Making a Raspberry Pi Photo Booth with Pibooth, NeoPixels, and Giant Buttons - 2021
- 3 Things I Learned Trying out the JavaScript Temporal API - 2021
- Green Screen Zwifting with retroreflective fabric - 2021
- Getting the PPPoE Credentials from your C4000XG without calling CenturyLink - 2020
- Setting up a Livestream with Owncast - 2020
- Indieweb Livestreaming your Wedding with Owncast - 2020
- Maybe mashups in 2020 are just Jamstack sites - 2020
- Secret Strava - 2020
- <bt-device> and Renderless Web Components - 2020
- Building Fast, Tiny GitHub Actions with Go and Docker - 2019
- Why I Built Blumhouse to Purge My Twitter History - 2019
- Toolchainless - 2019
- Web Components Aren't Weird Anymore - 2018
- JavaScript Gardening with the Particle Photon - 2018
- The Neverending Side Project - 2018
- Light Up Your Bike with Web Bluetooth and StencilJS - 2017
- Every Java Developer Should Learn TypeScript - 2017
- Web Bluetooth Is Your New Squeeze - 2017
- Building Custom Elements That Work With AngularJS 1.x and Angular - 2016
- How to Run a Board Game Library At Your Conference After-Party - 2016
- The Languages Which Almost Became CSS (Recap) - 2016
- Upgrading to Angular 2 using ngUpgrade - 2016
- Reacting to Heart Rate and Bike Sensors With RxJS - 2016
- Driving an LED Light Strip with Heart Rate and Bike Sensors - 2015
- Bringing ArnoldC to JavaScript - 2015
- Source Maps in 2015 - 2015
- We're hosting a JavaScript conference! - 2015
- Building a Handcrafted IR Blaster for Arduino-Powered Bike Lights - 2014
- Responsive Images using <picture> and srcset/sizes - 2014
- Responsive Web Design Workshop at Interface - 2014
- Hardware is the new Geocities - 2014
- Go(lang) for Broke - 2013
- Clickbait HTTP Status Codes - 2013
- A fresh coat of paint - 2013
- Exploring the Device APIs - 2013
- Diving into the Device API - 2013
- Unit Testing JavaScript when you're Afraid of JavaScript - 2013
- What Zelda Taught Me About Front End Engineering - 2012
- Unit Testing in JavaScript with Jasmine - 2012
- Town Tester - How well does your city unit test? - 2012
- Zen and the Art of TDD - 2012
- Lessons Learned from the first Hack Omaha - 2012
- I have a cameo in The Clean Coder - 2011
- Test-driven source code formatting - 2011
- Scramble Squares puzzle game solver - 2010
- Omaha Public Library card symbology - 2010
- Now this is a story all about how my bike got flipped, turned upside down - 2009
- The King of Kong - A Fistful of Inaccuracies - 2008
- Inelegant code affects your reputation - 2008
- Unintended consequences of the Internet - 2007
- Screen scraping Google Spreadsheets exported as HTML - 2007
- UI designs in Leopard that I really hope grow on me - 2007
- The Thatcher Illusion - 2007