← Back to Blog | adding comments on my blog with bluesky

| Talor Anderson

This blog now has commenting powered by bluesky!

I like bluesky a lot as an app. I think their decentralized model is cool: I have the handle @talor.computer not because I happened to get that username on their site first but because I own the domain name https://talor.computer.

All data on the site is freely accessible and easy to retrieve by simple APIs. Very different than X/Twitter's extremely locked down, expensive-to-the-point-of-not-existing API.

Because you can look up the data for any post, including replies, Bluesky ends up being a great way to build a comments feature into your site, where replies under a certain bluesky post show up as comments under your blog!

Here's the tutorial I followed, modified slightly to fit my own blog, for how to set this up.

In my blog post editor, I added a helper that lets me paste a link to a bluesky post, and then it transforms it automatically into a did and cid pair (identifiers needed to look up the post from the API).

export interface BlueskyPostInfo {
  did: string;
  cid: string;
}

export function parseBlueskyUrl(
  url: string
): { handle: string; cid: string } | null {
  try {
    const urlObj = new URL(url);

    // Match pattern: https://bsky.app/profile/{handle}/post/{cid}
    const match = urlObj.pathname.match(
      /^\/profile\/([^\/]+)\/post\/([^\/]+)$/
    );

    if (!match) {
      return null;
    }

    const [, handle, cid] = match;
    return { handle, cid };
  } catch {
    return null;
  }
}

export async function resolveBlueskyHandle(
  handle: string
): Promise<string | null> {
  try {
    const response = await fetch(
      `https://public.api.bsky.app/xrpc/com.atproto.identity.resolveHandle?handle=${encodeURIComponent(handle)}`
    );

    if (!response.ok) {
      return null;
    }

    const data = await response.json();
    return data.did;
  } catch {
    return null;
  }
}

export async function convertBlueskyUrl(
  url: string
): Promise<BlueskyPostInfo | null> {
  const parsed = parseBlueskyUrl(url);
  if (!parsed) {
    return null;
  }

  const did = await resolveBlueskyHandle(parsed.handle);
  if (!did) {
    return null;
  }

  return {
    did,
    cid: parsed.cid,
  };
}

Hopefully this will get me some traction on my posts over there: I've been growing a decent following on X/Twitter, but don't see much engagement on bluesky yet.

Leave a comment if you see this!

Leave a comment on Bluesky

Comments

Loading comments...