Copy-Paste Recipes
Ready-to-use code examples for common page types. Copy, paste, and customize for your project.
All recipes assume you have a shared config/seo.ts with siteConfig and SITE_URL, and a Document component. See Getting Started for setup.
1. Simple static page
Good for About, Contact, Terms, Privacy pages.
pages/AboutPage.tsxTSX
import { mergeSEOConfig, buildCanonicalUrl } from "react-ssr-seo-toolkit";
import { siteConfig, SITE_URL } from "../config/seo";
import { Document } from "../components/Document";
export function AboutPage() {
const seo = mergeSEOConfig(siteConfig, {
title: "About Us",
description: "Learn about our mission, team, and values.",
canonical: buildCanonicalUrl(SITE_URL, "/about"),
});
return (
<Document seo={seo}>
<h1>About Us</h1>
<p>Our story and mission...</p>
</Document>
);
}2. Blog article with structured data
pages/BlogPostPage.tsxTSX
import {
mergeSEOConfig,
buildCanonicalUrl,
createArticleSchema,
createBreadcrumbSchema,
} from "react-ssr-seo-toolkit";
import { siteConfig, SITE_URL } from "../config/seo";
import { Document } from "../components/Document";
export function BlogPostPage({ post }) {
const url = buildCanonicalUrl(SITE_URL, `/blog/${post.slug}`);
const seo = mergeSEOConfig(siteConfig, {
title: post.title,
description: post.excerpt,
canonical: url,
openGraph: {
title: post.title,
description: post.excerpt,
url,
type: "article",
images: [{ url: post.image, width: 1200, height: 630 }],
},
twitter: {
title: post.title,
description: post.excerpt,
image: post.image,
},
});
const schemas = [
createArticleSchema({
headline: post.title,
url,
datePublished: post.publishDate,
dateModified: post.updateDate,
author: post.authors,
publisher: { name: "My Blog", logo: `${SITE_URL}/logo.png` },
images: [post.image],
}),
createBreadcrumbSchema([
{ name: "Home", url: SITE_URL },
{ name: "Blog", url: buildCanonicalUrl(SITE_URL, "/blog") },
{ name: post.title, url },
]),
];
return (
<Document seo={seo} schemas={schemas}>
<article>
<h1>{post.title}</h1>
<p>By {post.authors.map(a => a.name).join(", ")}</p>
<div>{post.content}</div>
</article>
</Document>
);
}3. Product detail page
pages/ProductDetailPage.tsxTSX
import {
mergeSEOConfig,
buildCanonicalUrl,
createProductSchema,
createBreadcrumbSchema,
} from "react-ssr-seo-toolkit";
import { siteConfig, SITE_URL } from "../config/seo";
import { Document } from "../components/Document";
export function ProductDetailPage({ product }) {
const url = buildCanonicalUrl(SITE_URL, `/products/${product.slug}`);
const seo = mergeSEOConfig(siteConfig, {
title: product.name,
description: `$${product.price} — ${product.description}`,
canonical: url,
openGraph: {
title: product.name,
description: product.description,
url,
type: "product",
images: [{ url: product.image, width: 1200, height: 630 }],
},
});
const schemas = [
createProductSchema({
name: product.name,
url,
description: product.description,
images: [product.image],
price: product.price,
priceCurrency: product.currency,
sku: product.sku,
brand: product.brand,
availability: product.inStock
? "https://schema.org/InStock"
: "https://schema.org/OutOfStock",
ratingValue: product.rating,
reviewCount: product.reviewCount,
}),
createBreadcrumbSchema([
{ name: "Home", url: SITE_URL },
{ name: product.category.name, url: buildCanonicalUrl(SITE_URL, `/category/${product.category.slug}`) },
{ name: product.name, url },
]),
];
return (
<Document seo={seo} schemas={schemas}>
<h1>{product.name}</h1>
<p>${product.price}</p>
<p>{product.description}</p>
</Document>
);
}4. FAQ page with rich results
pages/FAQPage.tsxTSX
import {
mergeSEOConfig,
buildCanonicalUrl,
createFAQSchema,
} from "react-ssr-seo-toolkit";
import { siteConfig, SITE_URL } from "../config/seo";
import { Document } from "../components/Document";
const faqs = [
{ question: "What is your return policy?", answer: "30-day money-back guarantee." },
{ question: "How long is shipping?", answer: "5-7 business days standard." },
{ question: "Do you ship internationally?", answer: "Yes, to 50+ countries." },
];
export function FAQPage() {
const seo = mergeSEOConfig(siteConfig, {
title: "FAQ",
description: "Answers to frequently asked questions.",
canonical: buildCanonicalUrl(SITE_URL, "/faq"),
});
return (
<Document seo={seo} schemas={[createFAQSchema(faqs)]}>
<h1>FAQ</h1>
{faqs.map((faq, i) => (
<div key={i}>
<h3>{faq.question}</h3>
<p>{faq.answer}</p>
</div>
))}
</Document>
);
}5. Dynamic route with API data
server.tsx (Express route)TSX
app.get("/blog/:slug", async (req, res) => {
const post = await fetchPostBySlug(req.params.slug);
if (!post) {
res.status(404).send("Not found");
return;
}
const html = renderToString(<BlogPostPage post={post} />);
res.send(`<!DOCTYPE html>${html}`);
});6. Private / noindex page
pages/DashboardPage.tsxTSX
import {
mergeSEOConfig,
buildCanonicalUrl,
noIndex,
noIndexNoFollow,
} from "react-ssr-seo-toolkit";
import { siteConfig, SITE_URL } from "../config/seo";
import { Document } from "../components/Document";
export function DashboardPage() {
const seo = mergeSEOConfig(siteConfig, {
title: "Dashboard",
canonical: buildCanonicalUrl(SITE_URL, "/dashboard"),
// noindex but still follow links:
robots: noIndex(),
// noindex AND nofollow:
// robots: noIndexNoFollow(),
});
return (
<Document seo={seo}>
<h1>Dashboard</h1>
</Document>
);
}7. Multi-language page with hreflang
Hreflang exampleTSX
const seo = mergeSEOConfig(siteConfig, {
title: "Home",
canonical: SITE_URL,
alternates: [
{ hreflang: "en", href: SITE_URL },
{ hreflang: "es", href: `${SITE_URL}/es` },
{ hreflang: "fr", href: `${SITE_URL}/fr` },
{ hreflang: "de", href: `${SITE_URL}/de` },
{ hreflang: "x-default", href: SITE_URL },
],
});
// Renders <link rel="alternate" hreflang="..." href="..." /> for each8. Composing multiple schemas
Using composeSchemasTSX
import {
createOrganizationSchema,
createWebsiteSchema,
composeSchemas,
} from "react-ssr-seo-toolkit";
const org = createOrganizationSchema({ name: "My Co", url: "https://myco.com" });
const site = createWebsiteSchema({ name: "My Co", url: "https://myco.com" });
// Option 1: Separate schemas (multiple <script> tags)
<Document seo={seo} schemas={[org, site]}> ... </Document>
// Option 2: Composed @graph (single <script> tag)
const composed = composeSchemas(org, site);
<Document seo={seo} schemas={[composed]}> ... </Document>9. Custom meta and link tags
Custom tags exampleTSX
const seo = mergeSEOConfig(siteConfig, {
title: "My Page",
additionalMetaTags: [
{ name: "author", content: "Jane Doe" },
{ name: "theme-color", content: "#6d28d9" },
{ property: "fb:app_id", content: "123456789" },
],
additionalLinkTags: [
{ rel: "preconnect", href: "https://fonts.googleapis.com" },
{ rel: "icon", href: "/favicon-32.png", sizes: "32x32", type: "image/png" },
{ rel: "apple-touch-icon", href: "/apple-touch-icon.png" },
],
});10. Next.js App Router page
See the Next.js Guide for the full setup.
app/blog/[slug]/page.tsx (Next.js)TSX
import {
mergeSEOConfig, buildTitle, buildCanonicalUrl,
createArticleSchema, safeJsonLdSerialize,
} from "react-ssr-seo-toolkit";
import { siteConfig, SITE_URL } from "@/lib/seo";
import type { Metadata } from "next";
export async function generateMetadata({ params }): Promise<Metadata> {
const { slug } = await params;
const post = await getPost(slug);
const seo = mergeSEOConfig(siteConfig, {
title: post.title,
description: post.excerpt,
});
return {
title: buildTitle(seo.title!, seo.titleTemplate),
description: seo.description,
alternates: { canonical: buildCanonicalUrl(SITE_URL, `/blog/${slug}`) },
};
}
export default async function BlogPage({ params }) {
const { slug } = await params;
const post = await getPost(slug);
const schema = createArticleSchema({
headline: post.title,
url: buildCanonicalUrl(SITE_URL, `/blog/${slug}`),
datePublished: post.date,
author: [{ name: post.author }],
});
return (
<article>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: safeJsonLdSerialize(schema) }}
/>
<h1>{post.title}</h1>
<p>{post.content}</p>
</article>
);
}All functions used in these recipes are documented in the API Reference. See the Article Demo, Product Demo, and FAQ Demo for live working examples.