--- date: '2023-02-09' title: 'Adding client-side rendered webmentions to my blog' description: 'My blog is currently hosted on weblog.lol which allows for a simple and configurable weblog managed in git with posts formatted in markdown.' draft: false tags: ['webmentions', 'development', 'JavaScript', 'API'] --- My blog is currently hosted on weblog.lol which allows for a simple and configurable weblog managed in git with posts formatted in markdown. I wanted to add webmentions to my blog which, as of now, doesn't include a build step. To accomplish this, I've added an intermediary api endpoint to the same Next.js app that powers my [/now](https://coryd.dev/now) page. Robb has [a handy write-up on adding webmentions to your website](https://rknight.me/adding-webmentions-to-your-site/), which I followed — first adding the appropriate Mastodon link to my blog template, registering for webmentions.io and Bridgy, then adding the appropriate tags to my template document's `
` to record mentions. Next it was simply a question of rendering the output from the webmentions endpoint. My Next.js api looks like this: ```typescript export default async function handler(req: any, res: any) { const KEY_CORYD = process.env.API_KEY_WEBMENTIONS_CORYD_DEV const KEY_BLOG = process.env.API_KEY_WEBMENTIONS_BLOG_CORYD_DEV const DOMAIN = req.query.domain const TARGET = req.query.target const data = await fetch( `https://webmention.io/api/mentions.jf2?token=${DOMAIN === 'coryd.dev' ? KEY_CORYD : KEY_BLOG}${ TARGET ? `&target=${TARGET}` : '' }&per-page=1000` ).then((response) => response.json()) res.json(data) } ``` I have a pair of keys depending on the mentioned and provides domain, though this is only used on my blog at present. I also support passing through the `target` parameter but don't leverage it at the moment. This is called on the client side as follows: ```javascript document.addEventListener('DOMContentLoaded', (event) => { ;(function () { const formatDate = (date) => { var d = new Date(date), month = '' + (d.getMonth() + 1), day = '' + d.getDate(), year = d.getFullYear() if (month.length < 2) month = '0' + month if (day.length < 2) day = '0' + day return [month, day, year].join('-') } const webmentionsWrapper = document.getElementById('webmentions') const webmentionsLikesWrapper = document.getElementById('webmentions-likes-wrapper') const webmentionsBoostsWrapper = document.getElementById('webmentions-boosts-wrapper') const webmentionsCommentsWrapper = document.getElementById('webmentions-comments-wrapper') if (webmentionsWrapper && window) { try { fetch('https://utils.coryd.dev/api/webmentions?domain=blog.coryd.dev') .then((response) => response.json()) .then((data) => { const mentions = data.children if (mentions.length === 0 || window.location.pathname === '/') { webmentionsWrapper.remove() return } let likes = '' let boosts = '' let comments = '' mentions.map((mention) => { if ( mention['wm-property'] === 'like-of' && mention['wm-target'].includes(window.location.href) ) { likes += `