SEO for SaaS
Start
Guides

Other frameworks

SvelteKit, Nuxt, Remix, Express, Rails, Django: the same steps in any stack.

Every integration follows the same steps. The Next.js and Astro guides are complete, tested examples of them.

1. Fetch on the server

The content key is a secret: read the API from server or build code only, never from the browser. A site that renders only in the browser (a plain SPA) can't keep the key secret and shows search engines an empty page. Add server or build-time rendering first.

  • TypeScript or JavaScript: the TypeScript client is one file that needs only fetch, so it runs in SvelteKit load functions, Nuxt server routes, Remix loaders, Express, Hono, Bun, Deno, and Cloudflare Workers.

  • Any other language: two plain HTTP calls, shown in cURL and Python on List articles and Get an article.

2. Render the blocks

  • React available (Remix, React Router, Gatsby, or an island in any framework): use the React components unchanged.

  • Otherwise: write one small component per block type from the block reference. Render rich text as text runs, never as raw HTML (v-html, {@html}, set:html and raw stay off article content), keep each link's rel, and render nothing for a type you don't know. Keep the sfs-* class names, and article.css styles your markup with no changes.

3. Head tags

From article.seo: <title> from metaTitle, the meta description, a canonical link from canonicalPath resolved against your origin, Open Graph from openGraph, and jsonLd in one <script type="application/ld+json"> with < escaped as \u003c. Serve article URLs without a trailing slash, as canonicalPath has none. Details: SEO metadata.

4. Sitemap

Read the sitemap endpoint and write its entries into your sitemap as they are: url is the canonical URL and lastModified moves only when a reader would see a change. Never stamp articles with the build date; Google stops trusting a lastmod that moves on its own.

5. Refresh on publish

  • Server-rendered with a cache: mount a webhook endpoint that verifies the signature and purges your cache. The webhook handler is a fetch-style function for TypeScript runtimes; Python and cURL are on the same page.

  • Static site: point the webhook at your host's deploy hook. See Static sites.

  • No cache: nothing to do. Every request reads the current article.

Check

Build or run the site against the example article, which needs no key and has one of every block type: every block renders, the head tags are there once each, and an unsigned POST to your webhook endpoint returns 401.