Getting Started
Install react-ssr-seo and add production-ready SEO to your app in minutes.
1Installation
Install the package using your preferred package manager:
npm install react-ssr-seo
yarn add react-ssr-seo
pnpm add react-ssr-seo
Peer dependency: React >= 18.0.0 is required. The package has zero other dependencies.
2Create a Site Config
Define shared SEO defaults for your entire site. This config will be merged with page-specific overrides.
import { createSEOConfig } from "react-ssr-seo";
// Shared base config — reused across all pages
export const siteConfig = createSEOConfig({
titleTemplate: "%s | My Site",
description: "Default site description for SEO.",
openGraph: {
siteName: "My Site",
type: "website",
locale: "en_US",
},
twitter: {
card: "summary_large_image",
site: "@mysite",
},
});
export const SITE_URL = "https://mysite.com";titleTemplate uses %s as a placeholder. When a page sets title: "About", it renders as About | My Site.
3Build Your First SEO Page
Use mergeSEOConfig to combine your base config with page-specific values, then render with the <SEOHead> component.
import {
mergeSEOConfig,
buildCanonicalUrl,
SEOHead,
} from "react-ssr-seo";
import { siteConfig, SITE_URL } from "../config/seo";
export function AboutPage() {
const seo = mergeSEOConfig(siteConfig, {
title: "About Us",
description: "Learn about our mission and team.",
canonical: buildCanonicalUrl(SITE_URL, "/about"),
openGraph: {
title: "About Us — My Site",
description: "Learn about our mission and team.",
url: buildCanonicalUrl(SITE_URL, "/about"),
},
});
return (
<html>
<head>
<SEOHead {...seo} />
</head>
<body>
<h1>About Us</h1>
<p>Our story...</p>
</body>
</html>
);
}This generates the following HTML tags:
<title>About Us | My Site</title> <meta name="description" content="Learn about our mission and team." /> <link rel="canonical" href="https://mysite.com/about" /> <meta property="og:title" content="About Us — My Site" /> <meta property="og:description" content="Learn about our mission and team." /> <meta property="og:url" content="https://mysite.com/about" /> <meta property="og:site_name" content="My Site" /> <meta property="og:type" content="website" /> <meta property="og:locale" content="en_US" /> <meta name="twitter:card" content="summary_large_image" /> <meta name="twitter:site" content="@mysite" />
4Add JSON-LD Structured Data
Use the built-in schema generators to add structured data for rich search results.
import {
createArticleSchema,
createBreadcrumbSchema,
JsonLd,
} from "react-ssr-seo";
// In your component:
const articleSchema = createArticleSchema({
headline: "My Blog Post",
url: "https://mysite.com/blog/my-post",
datePublished: "2025-06-15",
dateModified: "2025-07-01",
author: [{ name: "Jane Doe", url: "https://mysite.com/authors/jane" }],
publisher: { name: "My Site", logo: "https://mysite.com/logo.png" },
images: ["https://mysite.com/images/post.jpg"],
});
const breadcrumb = createBreadcrumbSchema([
{ name: "Home", url: "https://mysite.com" },
{ name: "Blog", url: "https://mysite.com/blog" },
{ name: "My Blog Post", url: "https://mysite.com/blog/my-post" },
]);
// In JSX:
<head>
<SEOHead {...seo} />
<JsonLd data={articleSchema} />
<JsonLd data={breadcrumb} />
</head>5Framework Integration
Next.js (App Router)
Use the builder functions with generateMetadata and render JSON-LD directly in your page component.
import {
mergeSEOConfig,
buildCanonicalUrl,
buildTitle,
buildOpenGraph,
createArticleSchema,
safeJsonLdSerialize,
} from "react-ssr-seo";
import { siteConfig, SITE_URL } from "@/config/seo";
import type { Metadata } from "next";
export async function generateMetadata({ params }): Promise<Metadata> {
const post = await getPost(params.slug);
const seo = mergeSEOConfig(siteConfig, {
title: post.title,
description: post.excerpt,
canonical: buildCanonicalUrl(SITE_URL, `/blog/${post.slug}`),
});
return {
title: buildTitle(seo.title!, seo.titleTemplate),
description: seo.description,
alternates: { canonical: seo.canonical },
openGraph: {
title: post.title,
description: post.excerpt,
url: seo.canonical,
images: [{ url: post.image }],
},
};
}
export default async function BlogPage({ params }) {
const post = await getPost(params.slug);
const schema = createArticleSchema({
headline: post.title,
url: buildCanonicalUrl(SITE_URL, `/blog/${post.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>
);
}React Router 7 SSR
Use the <SEOHead> component in your Document (root layout).
import { SEOHead, JsonLd, mergeSEOConfig } from "react-ssr-seo";
import { siteConfig } from "./config/seo";
export default function Root() {
const seo = mergeSEOConfig(siteConfig, {
title: "Home",
canonical: "https://mysite.com",
});
return (
<html lang="en">
<head>
<meta charSet="utf-8" />
<meta name="viewport"
content="width=device-width, initial-scale=1" />
<SEOHead {...seo} />
</head>
<body>
{/* Your app content */}
</body>
</html>
);
}Express / Generic SSR
Use renderToString with the SEOHead component for any Express-based SSR setup.
import express from "express";
import { renderToString } from "react-dom/server";
import { SEOHead, mergeSEOConfig } from "react-ssr-seo";
import { siteConfig } from "./config/seo";
const app = express();
app.get("/", (req, res) => {
const seo = mergeSEOConfig(siteConfig, {
title: "Home",
});
const html = renderToString(
<html>
<head>
<SEOHead {...seo} />
</head>
<body>
<h1>Welcome</h1>
</body>
</html>
);
res.send(`<!DOCTYPE html>${html}`);
});
app.listen(3000);6Explore More
This very page has SEO tags! Right-click and select "View Page Source" to see the title template, description, canonical URL, Open Graph, and Twitter Card meta tags generated by react-ssr-seo.