SEO config — metadata, JSON-LD, canonical

This tutorial shows how to add SEO-friendly metadata to your Next.js App Router layout: title template, description, OpenGraph, Twitter cards, canonical URL, robots, icons, manifest, and JSON-LD structured data for better search and social previews.

Why metadata and JSON-LD matter for SEO

Search engines and social platforms use your page title, description, and images to display results and link previews. A canonical URL avoids duplicate-content issues. JSON-LD (e.g. WebSite, SearchAction) helps search engines understand your site and can enable rich results.

1. Viewport and metadataBase

In src/app/layout.tsx, export viewport for theme color and scaling, and set metadataBase so all relative URLs in metadata (e.g. images) resolve correctly:

const siteUrl = process.env.NEXT_PUBLIC_SITE_URL || "https://ck444.game";

export const viewport: Viewport = {
  themeColor: "#05070b",
  width: "device-width",
  initialScale: 1,
  maximumScale: 5,
};

export const metadata: Metadata = {
  metadataBase: new URL(siteUrl),
  title: { default: "Your Title", template: "%s | CK444 Game" },
  description: "Your description.",
  // ...
};

2. Title, description, and canonical

Use title.template so child pages get a consistent suffix. Set alternates.canonical to your site URL (or per-page in child layouts/pages).

3. OpenGraph and Twitter cards

Define openGraph and twitter with type: "website", url, title, description, siteName, and images (e.g. /og.png 1200×630). Twitter card can be summary_large_image.

4. Robots and icons

Set robots to index: true, follow: true and optionally googleBot with max-image-preview, max-snippet, max-video-preview. Add icons for favicon and Apple touch icon.

5. JSON-LD WebSite schema

Add a component that renders a <script type="application/ld+json"> with WebSite and optional SearchAction so search engines know your site URL and search capability:

const data = {
  "@context": "https://schema.org",
  "@type": "WebSite",
  name: "CK444 Game",
  url: siteUrl,
  potentialAction: {
    "@type": "SearchAction",
    target: `${siteUrl}/?q={search_term_string}`,
    "query-input": "required name=search_term_string",
  },
};
// Render: <script type="application/ld+json">{JSON.stringify(data)}</script>

Next steps

After layout metadata, add dark mobile-first CSS and robots and sitemap. Back to all tutorials.