Skip to content

RSS feeds

@scribe-atp/core exports generateFeed — a function that takes a fetched Site and returns a complete RSS 2.0 XML string. You wire it into your server-side route handler and return it as a response.

generateFeed needs a baseUrl (your site’s origin) and a feedUrl (the canonical URL of the feed itself):

import { fetchSite, generateFeed } from '@scribe-atp/core';
const site = await fetchSite('alice.bsky.social', 'alice-bsky-social');
const xml = generateFeed(site, {
baseUrl: 'https://alice.example.com',
feedUrl: 'https://alice.example.com/feed.xml',
});

generateFeed returns a string of RSS 2.0 XML ready to serve directly.

app/routes/feed.ts
import { fetchSite, generateFeed } from '@scribe-atp/core';
export async function loader({ request }: { request: Request }) {
const origin = new URL(request.url).origin;
const site = await fetchSite('alice.bsky.social', 'alice-bsky-social', request.signal);
const xml = generateFeed(site, {
baseUrl: origin,
feedUrl: `${origin}/feed.xml`,
});
return new Response(xml, {
headers: { 'Content-Type': 'application/rss+xml; charset=utf-8' },
});
}

generateFeed includes only published articles — articles in groups. Unpublished articles (site.ungroupedArticles) are excluded.

Each feed item contains:

  • <title> — from article.title
  • <description> — from article.synopsis (when set)
  • <link> — the canonical article URL, built from the site’s url and urlPrefix
  • <pubDate> — from article.createdAt
  • <guid> — the article’s AT URI (stable across URL changes)

Add a <link> tag in your HTML <head> so feed readers can discover the feed automatically:

<link
rel="alternate"
type="application/rss+xml"
title="My Blog"
href="/feed.xml"
/>