1. ホーム
  2. Next.js

【Next.js】metadata でタイトル・説明文を設定する方法|SEO・OGP を解説

Share

ページのタイトルや説明文(<title><meta name="description">)は、検索結果の見え方や SNS でのシェア表示に大きく影響します。Next.js の App Router では、こうしたメタ情報を Metadata API で宣言的に設定できます。<head> を自分で書く必要はなく、ファイルから metadata をエクスポートするだけです。この記事では、静的な metadata の書き方、URL に応じて変える generateMetadata、共通設定の継承、OGP(SNS 用の画像・情報)の設定までを初心者向けに解説します。前提として App Router を使っていることとします。

metadata オブジェクトで基本情報を設定する

もっとも簡単なのは、layout.tsxpage.tsx から metadata という名前のオブジェクトをエクスポートする方法です。Next.js がこれを読み取り、自動で <head> 内に対応するタグを出力します。

app/about/page.tsx
import type { Metadata } from 'next';

// このページのメタ情報を宣言する
export const metadata: Metadata = {
  title: '運営者について',
  description: '当サイトの運営者と目的を紹介するページです。',
};

export default function AboutPage() {
  return <h1>運営者について</h1>;
}

これだけで、このページには <title>運営者について</title><meta name="description" content="..."> が出力されます。Metadata 型を付けておくと、指定できるプロパティを補完でき、書き間違いも防げます。値が固定のページは、この静的な metadata で十分です。

URL に応じてメタ情報を変える(generateMetadata)

ブログ記事のように、ページごとにタイトルが変わる場合は、固定の metadata では対応できません。そこで使うのが generateMetadata 関数です。動的ルーティングの params を受け取れるので、記事のデータをもとにタイトルや説明文を組み立てられます。

app/blog/[slug]/page.tsx
import type { Metadata } from 'next';

// params からデータを取り、メタ情報を動的に生成する
export async function generateMetadata({
  params,
}: {
  params: Promise<{ slug: string }>;
}): Promise<Metadata> {
  const { slug } = await params;
  const res = await fetch(`https://example.com/api/posts/${slug}`);
  const post = await res.json();

  return {
    title: post.title,
    description: post.summary,
  };
}

export default async function BlogPost({
  params,
}: {
  params: Promise<{ slug: string }>;
}) {
  const { slug } = await params;
  return <h1>記事: {slug}</h1>;
}

generateMetadataasync にできるので、記事データを取得してから titledescription を返せます。これで /blog/hello/blog/world で別々のタイトルが付き、検索結果にも記事ごとの正しいタイトルが表示されます。静的な metadatagenerateMetadata は同じファイルで併用できません。値が固定なら前者、URL によって変わるなら後者、と使い分けます。

共通設定とタイトルのテンプレート

メタ情報は、上位の layout.tsx で設定したものが下位のページに引き継がれます。サイト全体で共通の設定はルートの app/layout.tsx に置くとよいでしょう。特に便利なのが title.template で、各ページのタイトルに自動でサイト名を付け足せます。

app/layout.tsx
import type { Metadata } from 'next';

export const metadata: Metadata = {
  title: {
    default: 'My Blog',            // タイトル未指定のページで使われる
    template: '%s | My Blog',      // %s に各ページのタイトルが入る
  },
  description: 'Web 開発の学習ブログです。',
};

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="ja">
      <body>{children}</body>
    </html>
  );
}

template: '%s | My Blog' を設定しておくと、あるページで title: '運営者について' と書くだけで、実際のタイトルは 運営者について | My Blog になります。%s の部分に各ページのタイトルが差し込まれる仕組みです。トップページなど個別のタイトルを持たないページには default の値が使われます。サイト名を毎回手で付ける手間が省け、表記も統一できます。

OGP(SNS シェア用)の情報を設定する

SNS でリンクを共有したときに表示されるタイトル・説明・画像は、OGP(Open Graph Protocol)というメタ情報で決まります。Metadata API では openGraph プロパティで指定できます。

app/page.tsx
import type { Metadata } from 'next';

export const metadata: Metadata = {
  title: 'My Blog',
  description: 'Web 開発の学習ブログです。',
  openGraph: {
    title: 'My Blog',
    description: 'Web 開発の学習ブログです。',
    images: ['/ogp.png'], // SNS で表示される画像
    type: 'website',
  },
};

openGraph を設定すると、<meta property="og:title"> などのタグが自動で出力されます。images にサムネイル画像を指定しておくと、シェア時に画像付きのカードで表示され、クリック率の向上が期待できます。記事ごとに画像を変えたいときは、generateMetadata の中で openGraph.images を組み立てればOKです。

タイトルが反映されないと感じたとき

Metadata API でつまずきやすいのが、クライアントコンポーネントに metadata を書いてしまうケースです。metadatagenerateMetadata は、ファイル先頭に 'use client' が付いたコンポーネントでは機能しません。メタ情報の設定はサーバーコンポーネント('use client' の付いていないファイル)で行う必要があります。

もし対象のページがクライアントコンポーネントになっている場合は、メタ情報だけを親の layout.tsx(サーバーコンポーネント)に切り出すか、ページ本体をサーバーコンポーネントにして、インタラクティブな部分だけを子のクライアントコンポーネントに分ける構成にします。「メタ情報はサーバー側で設定する」と覚えておくと、この種のトラブルを避けられます。

まとめ

Next.js App Router の Metadata API を使うと、<head> を直接書かずにタイトルや説明文を設定できます。値が固定のページは metadata オブジェクトをエクスポートし、URL によって変わるページは generateMetadata 関数で params をもとに動的に生成します(両者は同一ファイルで併用不可)。ルートの layout.tsx に共通設定を置き、title.template%s | サイト名)を使えばサイト名を自動付与できます。SNS 向けには openGraph でタイトル・説明・画像を設定しましょう。なお metadata はサーバーコンポーネントでのみ有効なので、'use client' のファイルには書かない点に注意してください。まずは固定ページに metadata を1つ追加して、ブラウザのタブや検索結果での見え方を確認してみましょう。

参考ページ