App Router Metadata
The nextjs-seo-manager/metadata module provides helpers for integrating SEO Manager with the Next.js App Router metadata system. It uses React cache() so that generateMetadata and your page component share a single API call per request.
If you are using the Pages Router, see SEOHelper instead.
Exports
| Export | Type | Description |
|---|---|---|
createPageSEO | function | Factory that creates cached SEO helpers for a page |
AppSEOHelper | component | Client component for ld+json and analytics pings |
buildMetadataFromSEO | function | Maps SEO data to a Next.js Metadata object (advanced) |
mapFetchSEOToMetadata | function | Normalizes raw fetchSEO data with defaults (advanced) |
Quick Start
// app/dinner/page.tsx
import SEOInit from "nextjs-seo-manager/init";
import { createPageSEO, AppSEOHelper } from "nextjs-seo-manager/metadata";
SEOInit({
projectId: process.env.SEO_MANAGER_PROJECT_ID,
secretKey: process.env.SEO_MANAGER_SECRET_KEY,
projectKey: process.env.NEXT_PUBLIC_SEO_MANAGER_PROJECT_KEY,
});
const DEFAULTS = {
title: "Dinner Menu",
description: "Browse our dinner menu",
};
const pageSEO = createPageSEO("/dinner", DEFAULTS);
export const generateMetadata = pageSEO.generateMetadata;
export default async function DinnerPage() {
const seo = await pageSEO.getSEOData();
return (
<>
<AppSEOHelper data={seo} />
<h1>Dinner Menu</h1>
{/* your page content */}
</>
);
}
createPageSEO
| Property | Type | Required | Description |
|---|---|---|---|
| path | string | Yes | The page path to fetch SEO data for. Must begin with '/'. |
| defaults | SEODefaults | No | Default SEO values used as fallbacks when the dashboard has no data. |
| options | object | No | Additional metadata options. Shape: { metadataOptions: SEOMetadataOptions, meta: { request: object } } |
createPageSEO(path, defaults?, options?) returns an object with two methods:
generateMetadata()— an async function that returns a Next.jsMetadataobject. Export it directly asgenerateMetadatafrom your page file. It populatestitle,description,keywords,openGraph,twitter,alternates.canonical, androbots.getSEOData()— an async function that returns the full SEO data (including_pingconfig for analytics). Pass the result toAppSEOHelper.
Both methods use the same cached fetch, so the API is only called once per request even though both are invoked.
SEODefaults
| Property | Type | Description |
|---|---|---|
| title | string | Default page title used when no title is set in the dashboard. |
| description | string | Default page description used when no description is set in the dashboard. |
| keywords | string | Default keywords string. |
| image | string | Default Open Graph image URL. |
| canonical | string | Default canonical URL. |
| path | string | Default page path. Used to construct the canonical URL if not explicitly set. |
Fallback values used when the dashboard has no data for a field. For example, if no title is set for a page in the dashboard, defaults.title is used instead.
SEOMetadataOptions
| Property | Type | Description |
|---|---|---|
| structuredData | object | Custom JSON-LD structured data to include in the metadata. Overrides any structured data from the dashboard. |
| robotsOverride | object | Override the robots index/follow settings. Shape: { index: boolean, follow: boolean } |
AppSEOHelper
| Property | Type | Required | Description |
|---|---|---|---|
| data | object | Yes | The SEO data object returned by createPageSEO().getSEOData(). Contains page data, global settings, and analytics ping configuration. |
A client component ("use client") that renders what generateMetadata cannot:
- ld+json structured data —
<script type="application/ld+json">tags for the page'sldJsonandeventsdata. - Analytics ping — fires a request to the SEO Manager API on each navigation to track page views.
AppSEOHelper does not render meta tags — those are handled by generateMetadata.
buildMetadataFromSEO (Advanced)
For cases where you need more control over the metadata object, you can use buildMetadataFromSEO directly:
import { fetchSEO } from "nextjs-seo-manager";
import { buildMetadataFromSEO } from "nextjs-seo-manager/metadata";
export async function generateMetadata() {
const seoData = await fetchSEO("/custom-page");
return buildMetadataFromSEO(seoData, {
title: "Fallback Title",
description: "Fallback description",
}, {
robotsOverride: { index: true, follow: true },
});
}
The returned metadata includes: title, description, keywords, openGraph (title, description, images, type, locale), twitter (card, title, description, images), alternates.canonical, and robots.
Full Example with Layout
// app/layout.tsx
import SEOInit from "nextjs-seo-manager/init";
SEOInit({
projectId: process.env.SEO_MANAGER_PROJECT_ID,
secretKey: process.env.SEO_MANAGER_SECRET_KEY,
projectKey: process.env.NEXT_PUBLIC_SEO_MANAGER_PROJECT_KEY,
});
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>{children}</body>
</html>
);
}
// app/about/page.tsx
import { createPageSEO, AppSEOHelper } from "nextjs-seo-manager/metadata";
const pageSEO = createPageSEO("/about", {
title: "About Us",
description: "Learn about our company",
canonical: "https://example.com/about",
});
export const generateMetadata = pageSEO.generateMetadata;
export default async function AboutPage() {
const seo = await pageSEO.getSEOData();
return (
<>
<AppSEOHelper data={seo} />
<h1>About Us</h1>
<p>Welcome to our company.</p>
</>
);
}
For App Router robots.txt and sitemaps, see Robots.txt and Sitemaps.