# Other frameworks

Every integration follows the same steps. The [Next.js](/docs/guides/nextjs) and [Astro](/docs/guides/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](/docs/api/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](/docs/api/list) and [Get an article](/docs/api/get).

## 2. Render the blocks

- **React available** (Remix, React Router, Gatsby, or an island in any framework): use the [React components](/docs/components) unchanged.
- **Otherwise**: write one small component per block type from the [block reference](/docs/api/blocks). 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](https://seoforsaas.dev/r/files/components/seoforsaas/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](/docs/api/seo).

## 4. Sitemap

Read [the sitemap endpoint](/docs/api/sitemap) 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](/docs/api/webhooks) 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](/docs/guides/static-sites).
- **No cache**: nothing to do. Every request reads the current article.

## Check

Build or run the site against the [example article](/docs/api/example), 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`.
