Statac

Publish

Webmentions

A webmention is another site telling yours that it linked to one of your pages, as a reply, a like, a repost, a bookmark or a plain mention.

Turn them on

In statac.yaml:

url: https://example.org/
webmentions: true

Webmentions are off without this line, and need url. A relay, webmention.io, receives them for your site and keeps them: sign in there with your site’s address. Statac fetches them from it with the token it gives you.

The token

STATAC_WEBMENTION_TOKEN=your-token statac refresh

The token reads your mentions. It is yours, not the site’s, so it never goes in statac.yaml or any file you commit. statac refresh and statac serve read it from STATAC_WEBMENTION_TOKEN, or else from the one line of .statac/token.

The .gitignore that statac new writes keeps .statac/ out of the site’s history. Deleting .statac/ deletes the token too.

`.statac/token` wasn't used: it holds more than one line.
Webmentions weren't asked for: no token is in `STATAC_WEBMENTION_TOKEN` or `.statac/token`.

A token file that is empty, holds more than one line or is a link is left unused. Without a token, refresh fetches the stills alone.

Statac never shows the token or writes it anywhere, and statac build and statac check never need it. If a token has ever been committed, ask webmention.io for a new one.

Tell other sites where to send them

In the template that writes your pages’ <head>:

<head>
  <title>{{ headline(page) }}</title>
  {{ webmention() }}
</head>

webmention() writes the line that tells another site where to send a mention of the page: <link rel="webmention" href="https://webmention.io/example.org/webmention">, with your site’s host. A preview built with --url still names the site’s own host.

What refresh keeps

Fetched `fetched/faces/0123456789abcdef.jpg`.
Fetched `fetched/mentions/2028899.yaml`.
Webmention `2028900` not kept: `https://example.com/post-1/` isn't on this site.
Fetched 1 webmention and 1 face. 1 not kept.

statac refresh asks the relay for every mention since the last one it kept, and keeps each as a file of its own in fetched/mentions/. Serve does the same as it starts.

In fetched/mentions/2028899.yaml:

kind: "replied"
author: "A"
author_url: "https://a.example/"
face: "0123456789abcdef.jpg"
url: "https://a.example/post-1/"
target: "https://example.org/post-1/"
published: "2026-09-03"
fetched: "2026-10-06"
words: "Words."
Field What it holds
kind replied, liked, reposted, bookmarked or mentioned.
author, author_url Who sent it, and their own page.
face Their picture, in fetched/faces/.
url The page that sent it.
target The page of yours it is of.
published, fetched The day the mention was published, and the day Statac fetched it.
words Its text alone, never its HTML, cut to 2,000 characters.

Everything in a webmention was written by someone else, so Statac keeps its words as plain text, and an address only where it starts http:// or https://.

A mention of an address that isn’t on your site isn’t kept. Kept or not, each has its line in fetched/record, so it is never asked for again.

Faces

The sender’s picture is fetched once, made again from its pixels at 96 pixels wide with nothing else of the file kept, and kept in fetched/faces/.

A page shows a face only as the copies Statac makes of it, so your readers’ browsers never ask another site for it.

How old they are

Fetched: 87 stills, the oldest 6 days ago; 12 webmentions, the newest today.

statac build says how long ago the newest webmention was fetched, after the stills: see how old is it?

Show them on a page

In a post’s front matter:

mentions: true

In a new site, this shows the post’s webmentions after the post, with snippets/mentions.html: see the starter. On its notes and photographs, mentions: true only writes the line saying where to send them.

mentions: true gives page.mentions, which a layout reads. Write it on one page, or hand it down. Statac ships no layout for webmentions. In one of yours, such as templates/page.html after {{ page.content }}:

{% set mentions = page.webmentions %}
{% if page.mentions and (mentions.said or mentions.faces) %}
<section class="mentions">
  {% for mention in mentions.faces %}
  <a href="{{ mention.url }}" rel="nofollow ugc">{% if mention.face %}<img src="{{ mention.face.src }}" width="{{ mention.face.width }}" height="{{ mention.face.height }}" alt="">{% endif %}{% if mention.author %}{{ mention.author }}{% endif %} {{ mention.kind }}</a>
  {% endfor %}
  {% for mention in mentions.said %}
  <article>
    <p><a href="{{ mention.url }}" rel="nofollow ugc">{% if mention.author %}{{ mention.author }}{% endif %} {{ mention.kind }}</a></p>
    {% if mention.words %}<p>{{ mention.words }}</p>{% endif %}
  </article>
  {% endfor %}
</section>
{% endif %}

page.webmentions gives the page’s mentions, oldest first: said, the replies, mentions and bookmarks, and faces, the likes and reposts. What a mention gives lists the fields.

Each link carries rel="nofollow ugc": it leads to a page someone else chose.

Warning:

Print a mention’s words as they are, as above. Never hand them to markdown or safe: both put any HTML in them into your page as HTML, and the words are someone else’s.

A mention belongs to the page published at its address, or to the page whose redirect_from holds that address.

Microformats

The starter’s snippets/mentions.html marks each mention up as microformats:

Class On
h-cite Each mention.
u-url The link to the page that sent it.
p-author h-card Who sent it, with u-photo on their face and p-name on their name.
dt-published Its day, in a <time>.
p-content Its words.
u-in-reply-to, u-like-of, u-repost-of, u-bookmark-of The page a reply, a like, a repost or a bookmark answers, on a <data> element that shows nothing.

Sending webmentions

Statac never sends a webmention: when a post of yours links to another site, that site isn’t told. Send one yourself once the post is published.

Turn one away

statac refuse https://a.example/post-1/
Refused `https://a.example/post-1/`: 1 webmention removed.
Removed `fetched/mentions/2028899.yaml`.

statac refuse turns a mention away for good: it removes it now, and statac refresh never keeps it again.

Give it the address of the page that sent the mention, as the mention’s file gives it in url. The scheme, a leading www., the capitals of the host and a final slash make no difference.

Everything from one sender

statac refuse https://a.example/
Refused everything from `https://a.example/`: 3 webmentions removed.
Removed `fetched/mentions/2028899.yaml`.
Removed `fetched/mentions/2028900.yaml`.
Removed `fetched/mentions/2028907.yaml`.
Removed `fetched/faces/0123456789abcdef.jpg`.

Give the address of the sender’s site, or of a part of it. That takes every mention whose url or author_url is at the address or under it, and whatever comes later from there: https://a.example/a takes in https://a.example/a/post-1/ but not https://a.example/ab/.

An address is taken as one mention only where exactly one mention was sent from it and nothing else kept is under it.

Options

Option What it does
--site=<folder> The site’s folder, the same as naming it after the address: statac refuse https://a.example/ docs.
--today=<date> The day the refusal is recorded on, as 2026-10-04. Without it, today on this computer’s clock.

refuse reads only fetched/, so it works on a site with an error elsewhere.

Nothing refused: no webmention kept here is from `https://a.example/`.

What refuse changes

In fetched/refused:

statac refused 1
sender	https://a.example/	2026-10-06
mention	https://b.example/post-1/	2026-10-06

refuse lists the address in fetched/refused, removes each mention’s file and marks its line in fetched/record absent. It removes a face no mention left names.

Webmention `2028911` not kept: `https://a.example/` is refused.

From then on, statac refresh keeps nothing from a refused address, and says so.

Undo a refusal

Remove the address’s line from fetched/refused, and each refused mention’s absent line from fetched/record, then run statac refresh.

Note:

The relay sends only what is newer than the newest mention the record has a line for, so a mention comes back only where nothing newer has been kept since.

When something is wrong

Statac reports each problem itself, with what to do: Problems explained lists them. The one that isn’t a mistake:

Problem What happened What to do
mention-of-no-page A mention is of an address where nothing is published, mostly because a page moved. No page shows it. Add the old address to the page’s redirect_from, or delete the mention’s file.

Where next?

Something unclear or wrong? Open an issue on GitHub.