Home avatar for ahmad.build About Notes Tags
← →

Setting up webmention with Cloudflare and AstroJS

This is part of effort to own my content. Rather than posting the content elsewhere, post it on my platform instead (this blog).

Basic Idea

  1. get our data from webmentions.io, and store within src/content/webmentions folder,
  2. create new Astro collection called webmentions,
  3. consume the data - get the collection from step 2 and call wherever,
  4. push to GitHub,
  5. link Cloudflare with GitHub

1. Get data from webmentions.io

I’m using script from Jan Monschke with a bit of modification. This script will be executed by GitHub action and auto commit to specified folder (in this case, src/content/webmentions folder).

import * as https from "https";
import * as fs from "fs";
import { getSlugFromPathName, getFileName } from "@/utils/common.js";

const { WEBMENTIONS_IO_TOKEN } = process.env;
const { HOSTNAME } = "ahmad.build";

async function fetchMentions() {
  const url = `https://webmention.io/api/mentions.jf2?domain=${HOSTNAME}&token=${WEBMENTIONS_IO_TOKEN}&per-page=999`;

  return new Promise((resolve, reject) => {
    // create Promise here
  }).then((response) => {
    return response.children;
  });
}

fetchMentions().then((webmentions) => {
  console.log(`Fetched ${webmentions.length} webmentions`);
  webmentions.forEach((webmention) => {
    // check if mention exist on disk. If exist, fetch new and overwrite. Else, create new mention.
    // write the mention to disk
  });
});

WEBMENTIONS_IO_TOKEN value need to be set on GitHub environment.

2. Create new Astro collection

To create new collection, we need to edit src/content/config.ts. Remember, Astro allow user to have multiple collections, e.g. notes, webmentions, activity etc. Case below, I’m creating new collection called webmentions.

const webmentionsSchema = z.object({
  url: z.string(),
  published: z.coerce.date(),
  "wm-property": z.string(),
  "wm-received": z.coerce.date(),
  content: z
    .object({
      text: z.string().optional(),
      html: z.string().optional(),
    })
    .optional(),
  author: z.object({
    type: z.string(),
    name: z.string(),
    photo: z.string(),
    url: z.string(),
  }),
});

const webmentions = defineCollection({
  type: "data",
  schema: z.array(webmentionsSchema),
});

3. Consume the webmention data

Now that the collection is ready, we can customize it to our liking. In my case, I’m getting like and reply. For that, create 2 component : WebmentionList.astro and WebmentionLike.astro

WebmentionList.astro

---

const { wm } = Astro.props;

let likeCount: any = [];
wm.map((wm: any) => {
	if (wm["wm-property"] === "like-of") {
		likeCount.push(wm);
	}
});

const hasLike = wm.some(function (wm: any) {
	return wm["wm-property"] === "like-of";
});
---
{
	wm.length > 0 && (
		<div class="webmentions">
			<div class="wm-header">
				<h3 id="webmentions">Webmentions</h3>

				{hasLike && (
					<div class="wm-like">
						<ul>
							{wm.map(
								(wm: any) =>
									wm["wm-property"] == "like-of" && <WebmentionLike {wm} />
							)}
						</ul>
						<WebmentionLikeCount {wm} />
					</div>
				)}
			</div>

			<ul class="wm-list">
				{wm.map((wm: any) => (
					<WebmentionCard {wm} />
				))}
			</ul>
		</div>
	)
}

WebmentionLike.astro

---
const { wm } = Astro.props;
const { photo, name, url } = wm.author;
---

{
	(
		<li>
			<a href={url}>
				<img class="avatar" width="32" height="32" src={photo} title={name} />
			</a>
		</li>
	)
}

4. Push to GitHub

Second last step is to push the code to GitHub. Don’t forget to set WEBMENTIONS_IO_TOKEN on GitHub environment.

5. Linked Cloudflare with GitHub

Last step is to create new site on Cloudflare and link the site with GitHub repository on previous step.

Credit

  1. https://sebastiandedeyne.com/adding-webmentions-to-my-blog/
  2. https://janmonschke.com/adding-webmentions-to-your-static-blog/
Posted Tue, 08 Aug 2023 edited Fri, 24 Nov 2023
webmention / astro / cloudflare / github / POSSE / snippet /
webmention / , astro / , cloudflare / , github / , POSSE / , snippet /
2 Likes
Webmention
Ahmad AlbakriSun, 01 Oct 2023

reply for the test

Ahmad AlbakriSun, 01 Oct 2023

replied!

thesabunSat, 01 Jul 2023
Trying out this guide to sending webmentions
pasarlokenSat, 21 Oct 2023

@ahmadalbakri reply from fediverse

pasarlokenSat, 21 Oct 2023

@ahmadalbakri im a banana

Lloyd AtkinsonSun, 06 Oct 2024

This is a list of everything I read while researching and implementing Webmentions in no particular order:

  • IndieWebify.Me - a guide to getting you on the IndieWeb
  • Using the Webmention.io API : Random Geekery
  • An In-Depth Tutorial of Webmentions + Eleventy
  • Adding webmentions to your static blog | Jan Monschke
  • Using Webmentions in Eleventy | Max Böck
  • Adding Webmentions to Your Site • Robb Knight
  • Setting up webmention with Cloudflare and AstroJS - ahmad.build
  • Integrating Webmentions with Next.JS • Deloughry.co.uk
  • Getting Started With Webmention and NextJS

Further reading

  • Displaying Webmentions on My Site | James’ Coffee Blog (there’s lots of other webmention posts here too)
  • Adding reply context to my social pages | James’ Coffee Blog
  • The fediverse and the indieweb
  • IndieWeb - A Primer | Not Someobody Else’s Problem - Mine. IndieWeb - A Primer | Not Someobody Else’s Problem - Mine.
  • Let’s talk about making IndieWeb weirder and easier
  • Wars of Conflicting Webs
  • You’re not wrong. The problem is the ActivityPub spec by itself doesn’t give you enough to implement a working system, and Mastodon filled in the rest with decisions they made on their own. So what actually exists is mostly a Mastodon-specific protocol built on the ActivityPub framework.

External services I’m using

  • Bridgy - Most sites do not send webmentions, so Bridgy fills this gap by automatically scanning various social sites and then sending a webmention to your site.
  • Webmention.io - My site is a static site, and I don’t want to host or implement a Webmention receiver myself. This external service is the webmention receiver. I can include some HTML that tells Bridgy to call that.

Displaying WebMentions

There’s a lot of ways the various types of webmentions can be displayed visually. However, there are specific semantic patterns via microformat classes that should be used. Many sites seem to skip this unfortunately. The indieweb wiki fortunately gives several examples where this is doing correctly.

  • comments - IndieWeb
  • likes - IndieWeb
  • reposts - IndieWeb

The general format for all of these are as follows. Notice usage of h-entry, p-author, h-cite, u-comment, etc.

<div class="h-entry">    <h1 class="p-name">The Main Entry</h1>    <p class="p-author h-card">John Smith</p>    <p class="e-content">A few insights I've had:</p>    <h2>Comments</h2>    <div class="u-comment h-cite">        <a class="u-author h-card" href="http://jane.example.com/">            Jane Bloggs        </a>        <p class="p-content p-name">Ha ha ha great article John.</p>        <a class="u-url" href="http://jane.example.com/c12">            <time class="dt-published">2015-07-12 HH:MM</time>        </a>    </div>    <div class="u-comment h-cite">        <a class="u-author h-card" href="http://kim.example.net">            Kim Codes        </a>        <p class="p-content p-name">What were the insights?</p>        <a class="u-url" href="http://kim.example.net/k23">            <time class="dt-published">2015-07-12 HH:MM</time>        </a>    </div></div>

Another example, this time of likes:

<li class="p-like h-cite">    <a href="https://instagram.com/p/4CPkIKDckd/#liked-by-341817" class="u-url">        <span class="p-author h-card">            <img                class="u-photo"                src="https://pkcdn.xyz/igcdn-photos-b-a.akamaihd.net/ae05b7dcc1946a0f6c26ff1d293e41122f532dff7d778152b30a4229ac1db68d.jpeg"                data-src="https://pkcdn.xyz/igcdn-photos-b-a.akamaihd.net/ae05b7dcc1946a0f6c26ff1d293e41122f532dff7d778152b30a4229ac1db68d.jpeg"                height="36"`            />        </span>    </a>    <a style="display:none;" class="p-name u-url" href="http://instagram.com/strangeways">        Ankur    </a></li>

Debugging and other stuff

  • Webmentions are Great (Mostly) - As webmentions and the various implementations and tools being somewhat open ended and not consistent, some badly formatted webmentions can be sent (in this case from a poorly written Wordpress plugin, surprise…). Need to ensure this sort of sanity checking is applied; “empty” replies with an emoji should be handled.

The webmentions for this note look like this. Here is an early experiment with fetching and displaying webmentions in Astro:

avatar for ahmad.build © ahmad.build 2025 RSS Contact GitHub Mastodon