Comments via Mastodon
I’m trying out a simple way to collect comments on a static blog via Mastodon and moderate them in Org-mode, with this post as a test case. The idea is simple: To open this page for comments, I publish a Mastodon toot that serves as an endpoint, collect the replies to that toot, moderate them, and post them here. Here I’ve experimented with implementing a solution in Elisp, so I can do all of that from within Emacs. If you’re on the Fediverse, you can reply to this toot from the link in the comment section below, and if you make your replies public, they will be automatically fetched and queued for moderation. Moderated posts will be published here, and you should receive a DM about it.
I’d like any comment solution to allow me to moderate comments in Org-mode. I’d also like to integrate my site more with the Fediverse (without actually implementing ActivityPub protocol for a static site!). If this works out, I might try the Indieweb approach with webmentions. And of course I could put up a standard comment form in PHP, and probably will, eventually. But I’d like to try out what can be done within the constraints of a static site first.
There is a package by Michael Herstine (aka sp1ff), indie-org, that adds Indieweb support to Org publishing, including POSSE to Mastodon and Twitter via brid.gy, and sending and receiving webmentions via webmention.io. I haven’t started using it, but the webmentions bit in particular looks really neat. Sp1ff has very instructive documentation, a showcase site, and a talk at EmacsConf 2022.
I’m looking forward to hearing what you think, both about the technical aspects (detailed below) and the human ones.
Human aspects: potentials and pitfalls
Some people will feel I’m wrong to copy Mastodon replies on my private blog. I think it’s fine to do so as long as I only collect “public” replies to toots that clearly notify readers how those replies will be used. I’m not sure if I could make it stick for legal purposes that this consitutes an implicit license to reproduce their content, though.
Then there’s keeping track of changes. One of the great things about Mastodon is the edit button. People may edit their toots after I’ve posted a copy in the comment section. Is it enough to provide a link back to their source comment? Or do I need to stay on top of how old comments are changing? Should I take care to delete them if the author deletes them on Mastodon? And if accepting comments from multiple methods, what if someone edits their toot after someone else has replied to it via a different method?
If I get around to merging comments from different sources, it means a discussion might happen across Mastodon, other people’s WordPress blogs, a comment form, etc. Then people might end up talking past each other, and I’m not sure how to avoid that without blitzing them with cross-notifications.
As for the risk of being overwhelmed by moderation demands, I’ll mitigate it by by not opening comments on everything, and by closing comments early and often.
By the way, though I’ve tried to implement a classical comment section here, it doesn’t have to be that way. With the freedom of moderating in Org-mode, I could use this setup for many purposes. For example, I could keep a record of feedback on a post, but hide the comments, just map over them to generate a thank-you list.
Technical aspects: the solution so far
My inspiration was Carl Schwan’s post about Adding comments to your static blog with Mastodon, which provided an implementation on top of Hugo. It sounded so seductively simple to get replies to a toot via a request to the Mastodon API:
GET https://{{instance}}/api/v1/statuses/{{id}}/context
This will work for up to max 60 public comments max 20 levels deep, the limit for anonymous requests. Beyond that I have to use a token, but for my needs, 60 comments will probably be plenty.
The devil is in the details: keeping track of endpoints and new and
old comments, saving state, facilitating moderation, and mitigating
security risks. Crucially, I already keep track of published pages,
some metadata, and a tag index in various variables that are updated
and saved to file every time a file is published. I just need to add
bits of metadata here (such as the timestamp of the latest comment),
as well as in Org entry properties under the Comments headline
(:ENDPOINT_TOOT:
id) and the individual comment entries (:CREATED:
and :MODIFIED:
timestamps, :PERMALINK:
, :CUSTOM_ID:
, and if it’s
a reply to another comment, :REPLY_TO:
). I use mastodon.el to
automatically notify commenters by DM from my Mastodon account when
their comments are published.
I fetch new comments by making a Mastodon API request with Emacs
request
to parse the JSON response and set up a callback that makes
the comments available for moderation by inserting them as level-2
Org-mode entries directly in the comment section of the relevant .org
source page. Since Org text can contain executable code that runs on
export, this entails a risk of malicious input, but a filter for
suspect patterns and the COMMENT
keyword on unmoderated entries
(which prevents export that might trigger execution) should help.
In short, with helper functions, the process is:
- Publish a new blog post with
org-publish
. - Toot an announcement and comment endpoint for the blog post. A
helper function
cmw-announce-toot
puts together a draft automatically in mastodon-toot-mode for me to review and send manually. I manually copy the link of the published toot. - Open the blog post for comments with the helper function
cmw-open-for-comments
. Paste the endpoint link from the last step at the prompt. - Fetch new/modified comments with
cmw-fetch-toot-comments
. - Moderate the comments manually and approve them with
C-c ;
(org-toggle-comment
). - Republish the pages that have new or modified comments, automatically updating metadata and notifying the commenters.
- Repeat steps 4–6 as long as I want to keep the comment section open.
OPEN Comments
From Fedi/Mastodon: comment via this toot.
TIP: You can use some Org-mode formatting in your comment. (Passing through HTML may mess up some of it.) Bare URLs automatically become links. MathJax should work.
/italics/
*bold*
http://gnu.org
[[http://gnu.org/][GNU]]
\pi r^2
H_{2}O
\( \pi r^2 \)
Bálint Magyar [2025-02-10 Mon 21:19]
Testing testing, is this thing on?
Via Mastodon – original post
Third spruce tree on the left [2025-02-10 Mon 21:19]
@noctuaminervae
So this collects responses via AP and tacks them onto the bottom of that static page?
neat.
Via Mastodon – original post
anders [2025-02-10 Mon 21:22]
test let me know the results.
Via Mastodon – original post
Owlet of Minerva [2025-02-10 Mon 21:29]
Reply to: Third spruce tree on the left [2025-02-10 Mon 21:19]
Yep. And when I reply to you, there should be a backlink to your reply!
Via Mastodon – original post
mrg [2025-02-10 Mon 22:00]
Oooh, nice, this looks right up my alley! Hope it works!
Via Mastodon – original post
Juan Escamilla Mólgora :gauss: [2025-02-10 Mon 22:18]
Hello World! -
probando probando
Via Mastodon – original post
Owlet of Minerva [2025-02-10 Mon 22:24]
Reply to: Juan Escamilla Mólgora :gauss: [2025-02-10 Mon 22:18]
Thanks, that shows something I need to watch out for. The entry properties (metadata) ended up getting attached to your sub-heading, which broke the setup. Easy enough to fix manually, but either I’ll have to ban headlines, or I’ll have to handle them in a smarter way.
Via Mastodon – original post
Giovanni - ZL2GX [2025-02-10 Mon 22:22]
Interesting idea - blending both orgmode markup/scripting and fediverse. It seems to be working so far. It’ll be interesting to see how you find the moderation side …
Via Mastodon – original post
Owlet of Minerva [2025-02-10 Mon 22:33]
Reply to: Giovanni - ZL2GX [2025-02-10 Mon 22:22]
@gmoretti Having fun so far!
(But scratching my head over why both your reply and a previous reply of mine Owlet of Minerva [2025-02-10 Mon 22:24] were both flagged “suspect” by my filter executables. Maybe a bad regex.) (Edit: Yes, an unescaped ’+’ sign.)
Via Mastodon – original post
Juan Escamilla Mólgora :gauss: [2025-02-11 Tue 00:51]
Reply to: Owlet of Minerva [2025-02-10 Mon 22:24]
Ups! Glad to be of help 😅Great project!
Via Mastodon – original post
slackline :emacs: :orgmode [2025-02-10 Mon 23:53]
This sounds intriguing. I’ll keep an eye on your blog and see how the experiment pans out.
Thanks for sharing. 👍
Via Mastodon – original post
Owlet of Minerva [2025-02-11 Tue 11:11]
Testing replacement of “entities” like ’&’. [Edit: Modifying and trying again.]
Via Mastodon – original post
mihec [2025-02-11 Tue 20:27]
greetings and congratulations from Emacs collective Ljubljana :)
Via Mastodon – original post
Gismoe [2025-02-11 Tue 20:30]
Hi emacs!
Via Mastodon – original post
Randy Ridenour [2025-02-11 Tue 21:32]
This is brilliant! I need to do this on my blog.
Via Mastodon – original post
Owlet of Minerva [2025-02-12 Wed 00:05]
Reply to: Randy Ridenour [2025-02-11 Tue 21:32]
Thanks!
A few bugs crept in this afternoon, so you did not receive the DM receipt you should have got. Meanwhile a lot of other people got multiple ones (sorry, folks!). But up until that point, it worked quite nicely …
Via Mastodon – original post
Owlet of Minerva [2025-02-12 Wed 09:38]
Testing again.
EDIT: Okay, DM notifications seem to be working again.
Again, apologies to everyone who received 2–3 repeat DMs. The code should robust enough now that it will not happen again, at least not to these replies.
Via Mastodon – original post
Len :tootsie: 🍉 [2025-02-12 Wed 10:10]
looks great!
Via Mastodon – original post
Mark T. Tomczak [2025-02-18 Tue 02:54]
Excellent! I wish you all the best with this. I did something similar with Hugo (hm… I thought I documented that but I can’t find the link!), but I didn’t think about moderation.
Via Mastodon – original post
Owlet of Minerva [2025-02-18 Tue 10:56]
Reply to: Mark T. Tomczak [2025-02-18 Tue 02:54]
Well, the sane way of doing this, I suspect, is just using javascript to pull the comments in the visitor’s browser where they’d appear immediately. No delays in moderation, no org-publish step, pretty much no security worries. But I’d like to curate a record of comments, and I’d like to keep my pages reasonably troll-free.
Via Mastodon – original post
Bruno Girin [2025-02-18 Tue 12:06]
Testing is important! This is a test reply to a post from @noctuaminervae to see if it all works.
Via Mastodon – original post
Karl T. [2025-02-18 Tue 21:37]
This is a toot! And a comment! But is it a tooting comment or a commenting toot?
Existential questions, to be sure.
Via Mastodon – original post
Owlet of Minerva [2025-02-18 Tue 22:53]
Reply to: Karl T. [2025-02-18 Tue 21:37]
Maybe it’s a commoot. Then again, I just looked that up, and people seem to be using that word to sell ads on trucks, for some reason I feel I ought to understand, but don’t. https://commoot.com/
Or a tooment. Very few people named Tooment out there, it seems, so it should be up for grabs. Sounds a bit like torment, though. Or tomb. But it rhymes nicely with “Hoom, Ent!”
Via Mastodon – original post
Owlet of Minerva [2025-02-19 Wed 09:38]
testing again
Via Mastodon – original post
Gismoe [2025-02-19 Wed 09:46]
Reply to: Owlet of Minerva [2025-02-19 Wed 09:38]
good morning :)
Via Mastodon – original post
Michael [2025-02-23 Sun 22:38]
Very cool.
Via Mastodon – original post
Owlet of Minerva [2025-02-24 Mon 08:39]
Reply to: Michael [2025-02-23 Sun 22:38]
Ooh, thanks! 🤩 Slowly gearing up to adapting your amazing indie-org package, but I wanted to learn from making this first.
Via Mastodon – original post
Michael [2025-02-27 Thu 23:01]
Reply to: Owlet of Minerva [2025-02-24 Mon 08:39]
Wow, that’d be great! I dunno… between indieweb & activitypub, it’s getting harder & harder to stick with a static site. Currently resisting the temptation to write my own blogging engine.
Via Mastodon – original post
Arne Babenhauserheide [2025-07-20 Sun 02:00]
@noctuaminervae Found your post via the emacs orgmode mailing list – pretty neat solution!
After losing one dynamic page and having to give up comments on two more (too much moderation effort), I no longer want online-editable pages, and this could give me a way to integrate feedback without the drawbacks.
Thank you for sharing!
To make it clear that the answers go to your page, you could show the original toot in an iframe that only starts after clicking: https://www.draketo.de/software/privacy-embed
Via Mastodon – original post