The project is in a healthy, maintained state
jekyll-webmentions-static fetches Webmention.io mentions during Jekyll build and injects them as static data into site.data["webmentions"] keyed by post URL. No JavaScript, no runtime API calls — pure static HTML.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
 Dependencies

Runtime

>= 4.0
 Project Readme

jekyll-webmentions-static

Gem Version Tests

Fetch and render Webmention.io mentions as static HTML at Jekyll build time. No JavaScript, no runtime API calls — pure static output.


How it works

During jekyll build, the plugin:

  1. Fetches all webmentions for your domain from the Webmention.io API.
  2. Groups them by target URL and stores them in site.data["webmentions"].
  3. Injects matching mentions into each post's page.webmentions array.
  4. Caches the API response locally so repeated builds don't hammer the API.

Installation

Add to your site's Gemfile:

gem "jekyll-webmentions-static"

And to _config.yml:

plugins:
  - jekyll-webmentions-static

Then run:

bundle install

Configuration

Add to _config.yml:

webmentions:
  token: YOUR_TOKEN        # or use WEBMENTION_TOKEN env var (preferred for CI/CD)
  cache: true              # default: true — cache API responses locally
  cache_ttl: 3600          # default: 3600 — seconds before the cache is considered stale

Getting a token

  1. Go to webmention.io and sign in with your domain (using GitHub, email rel=me, or another IndieAuth provider).
  2. Once authenticated, your API token is shown in your settings.
  3. Add the token to your _config.yml or (strongly preferred) set it as an environment variable:
export WEBMENTION_TOKEN=your-token-here

The environment variable always takes precedence over the config file value. This keeps secrets out of version control.

Add the rel="webmention" link to your <head>

Webmention.io needs to know your site is using it. Add these two tags to your HTML <head>:

<link rel="webmention" href="https://webmention.io/yourdomain.com/webmention" />
<link rel="pingback" href="https://webmention.io/xmlrpc" />

Usage in templates

Option 1 — Liquid tag (built-in template)

Place {% webmentions %} anywhere in a post or page layout to render a minimal, accessible webmentions section:

{% webmentions %}

This renders likes, reposts, and bookmarks as counts, and replies as individual cards with author name, avatar, and content.

Option 2 — Manual template with page.webmentions

For full control over markup, iterate over page.webmentions directly:

{% if page.webmentions %}
  <section class="webmentions">
    {% assign likes   = page.webmentions | where: "type", "like-of" %}
    {% assign replies = page.webmentions | where: "type", "in-reply-to" %}

    {% if likes.size > 0 %}
      <p>{{ likes.size }} like{{ likes.size | plural: "", "s" }}</p>
    {% endif %}

    {% for mention in replies %}
      <article>
        <strong>{{ mention.author.name }}</strong>
        {% if mention.content.text %}
          <p>{{ mention.content.text }}</p>
        {% endif %}
        <a href="{{ mention.url }}">{{ mention.published | date: "%B %-d, %Y" }}</a>
      </article>
    {% endfor %}
  </section>
{% endif %}

Accessing all webmentions in any template

The full hash is available at site.data.webmentions:

{% assign mentions = site.data.webmentions[page.url | prepend: site.url] %}

Caching

The plugin writes fetched data to _webmentions_cache.json in your site source directory. Subsequent builds within the TTL window (default: 1 hour) read from this file instead of calling the API.

Add the cache file to your .gitignore:

_webmentions_cache.json

To force a fresh fetch, delete the cache file or set cache: false in your config.


GitHub Actions setup

Store your token as a repository secret named WEBMENTION_TOKEN, then expose it in your workflow:

- name: Build Jekyll site
  run: bundle exec jekyll build
  env:
    WEBMENTION_TOKEN: ${{ secrets.WEBMENTION_TOKEN }}

Because the cache file is in .gitignore, each CI build fetches fresh data. To cache across CI runs, add _webmentions_cache.json to your Actions cache key. Without CI caching you'll make one API call per build, which is fine for most sites.

Keeping mentions fresh with a scheduled rebuild

Webmentions only update when your site is rebuilt. If your site doesn't publish frequently, add a schedule trigger to your GitHub Pages workflow so mentions stay current automatically:

on:
  push:
    branches: [main]
  schedule:
    - cron: '0 */6 * * *'   # rebuild every 6 hours

Adjust the cron interval to taste — daily (0 0 * * *) is reasonable for most sites. Each scheduled run fetches any new mentions from Webmention.io and publishes the updated site.


Webmention types

type Meaning
like-of Someone liked your post
repost-of Someone reposted / boosted it
in-reply-to A reply with content
bookmark-of Someone bookmarked it
mention-of A generic link mention

Styling

The {% webmentions %} tag outputs unstyled semantic HTML. All elements use BEM class names:

/* Outer section */
.webmentions { }

/* Reaction count pills */
.webmentions__counts { }
.webmentions__likes { }
.webmentions__reposts { }
.webmentions__bookmarks { }

/* Replies section */
.webmentions__replies { }
.webmentions__replies-heading { }

/* Individual reply card */
.webmention__reply { }
.webmention__author { }
.webmention__avatar { }        /* circular avatar img */
.webmention__author-name { }   /* linked name */
.webmention__date { }
.webmention__content { }

The count pills include a title attribute (e.g. title="2 likes") for native browser tooltip text on hover.


Requirements

  • Ruby >= 2.7
  • Jekyll >= 4.0
  • No additional gems required — uses Ruby's built-in net/http

License

MIT © 2025 Jason Chance