Mastodon Reactions on Bearblog
Last updated: 7 months, 1 week ago. Modified the snippet.
Recently, I transferred my blog to Bearblog. Which was shortly after I experimented with Webmentions for the first time on my previous website. It was a pain to set it up…
I came across some talk about privacy issues on Mastodon related to some bridge, which kind of relates to Webmentions too. Without going into the specifics about Webmentions and recent privacy debates on the Fediverse, I recommend reading the article “Webmentions Redux” by Robb Knight.
After some reading and understanding on privacy concerns, I've come to agree with the points raised.
Have I mentioned that Bearblog doesn't support Webmentions? The HTML markup lacks the necessary attributes (microformats 2) for it.
I liked Robb Knight's implementation, so I aimed for something similar on my Bearblog while prioritizing people's privacy online.
Here's what I've done to implement Mastodon reactions on my Bearblog.
- Support Bearblog and get a subscription, this will support the platform and unlock additional features which are required for the Mastodon reactions to work.
- Add the required JavaScript in the Footer directives, within
<script></script>
tags. - Modify
mastodonInstanceUrl
andmastodonUsername
to your specific Mastodon instance and username. The script will check whether the page is of apost
type. If it is, it will retrieve the numeric value from thebody
HTML class attribute, which will represent the Mastodon post ID. Once all conditions are met, it will fetch the results from the Mastodon API and output them as an HTML code snippet within the post, before thetags
paragraph.
// Mastodon Reacts: Privacy friendly
const mastodonInstanceUrl = "https://mastodon.social";
const mastodonUsername = "yeechie";
const processMastodonReacts = async (statusId, bodyElement, tagsElement) => {
try {
const response = await fetch(`${mastodonInstanceUrl}/api/v1/statuses/${statusId}`, {
headers: { "Content-Type": "application/json" },
});
if (!response.ok) throw new Error(`Failed to fetch Mastodon status: ${response.statusText}`);
const { favourites_count = 0, reblogs_count = 0, replies_count = 0 } = await response.json();
const html = `
<div class="mastodon-reacts">
<span class="mastodon-postlink">
🗨️ <a href="${mastodonInstanceUrl}/@${mastodonUsername}/${statusId}" target="_blank">Reply on Mastodon</a>
</span>
<dl class="mastodon-status">
<dt class="likes">❤️ Likes: </dt><dd>${favourites_count}</dd>
<dt class="boosts"> 🔄 Reposts: </dt><dd>${reblogs_count}</dd>
<dt class="replies"> 💬 Replies: </dt><dd>${replies_count}</dd>
</dl>
</div>`;
const sanitizedHtml = DOMPurify.sanitize(html);
tagsElement.insertAdjacentHTML("beforebegin", sanitizedHtml);
} catch (error) {
console.error("Error fetching Mastodon status:", error.message);
}
};
document.addEventListener("DOMContentLoaded", () => {
const body = document.querySelector("body.post");
if (!body) return;
const statusIdMatch = body.className.match(/\d+/);
if (!statusIdMatch) return;
const mastodonStatusId = statusIdMatch[0];
const tagsElement = document.querySelector("p.tags");
const script = document.createElement("script");
script.src = "https://cdn.jsdelivr.net/npm/dompurify/dist/purify.min.js";
script.defer = true;
script.onload = () => processMastodonReacts(mastodonStatusId, body, tagsElement);
document.head.appendChild(script);
});
- Add
class_name:
to the post attributes, followed by the Mastodon post ID. I chose this method becausecustom_meta_tag:
doesn't function on posts; it only works on the homepage. - Style the output however you want with custom CSS.
That's it!
Pastebin
Take a look at my pastebin.yeechie.one For the up-to-date code that I use.