Recipes

Layout + Page Merge (Next.js)

// app/layout.tsx
import { seoLayout } from "@better-seo/next"
export const metadata = seoLayout({ title: "Site" })

// app/about/page.tsx
import { seoPage } from "@better-seo/next"
export const metadata = seoPage({ title: "About" })
// Final title: uses titleTemplate from config

Route Rules

seo({
  rules: [
    { match: "/blog/*", schema: [article({ ... })] },
    { match: "/app/*", meta: { robots: "noindex,nofollow" } },
    { match: "/docs/**", openGraph: { type: "article" } },
  ],
})

generateMetadata + Async Data

import { prepareNextSeo } from "@better-seo/next"
import { article } from "@better-seo/core"

export async function generateMetadata({ params }) {
  const post = await fetchPost(params.slug)
  return prepareNextSeo({
    title: post.title,
    description: post.excerpt,
    canonical: `/blog/${post.slug}`,
    openGraph: { images: [{ url: post.ogImage }] },
    schema: [article({
      headline: post.title,
      datePublished: post.date,
      url: `${site}/blog/${post.slug}`,
    })],
  }, { baseUrl: site })
}

OG Image Generation

npm install @better-seo/assets
import { generateOG } from "@better-seo/assets"
import { writeFile } from "node:fs/promises"

const png = await generateOG({
  title: "Hello World",
  siteName: "My Site",
  theme: "dark",
})
await writeFile("./public/og.png", png)

CLI: npx @better-seo/cli og "Hello World" -o ./public/og.png --site-name "Brand"

Icons + Manifest

npx @better-seo/cli icons --input ./logo.png --out ./public

Generates: favicon.ico (16/32), PNG set (16–512), apple-touch-icon, maskable icon, optional manifest.json.

MDX Frontmatter → SEO

import { fromMdx } from "@better-seo/compiler"
import { readFileSync } from "node:fs"
import { createSEO } from "@better-seo/core"

const partial = fromMdx(readFileSync("post.mdx", "utf8"))
const seo = createSEO(partial, { baseUrl: site, defaultTitle: "Blog" })

CLI: npx @better-seo/cli content from-mdx --input ./post.mdx --out ./seo-input.json

React SPA (Vite)

import { BetterSEOHelmet, SEOProvider } from "@better-seo/react"
import { createSEO, webPage } from "@better-seo/core"

// App root
<SEOProvider config={seoConfig}>
  <App />
</SEOProvider>

// Page
const seo = createSEO({ title: "Dashboard", schema: [webPage({ name: "Dashboard" })] }, config)
<BetterSEOHelmet seo={seo} />

Robots + Sitemap (Next.js)

// app/robots.ts
import { renderRobotsTxt } from "@better-seo/crawl"
export default function robots() {
  return renderRobotsTxt({ sitemap: [`${process.env.SITE_URL}/sitemap.xml`] })
}

// app/sitemap.ts
import { renderSitemapXml } from "@better-seo/crawl"
export default async function sitemap() {
  const urls = await getRoutes() // from your route manifest
  return renderSitemapXml(urls.map(loc => ({ loc })))
}

Next