0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Next.js (App Router) でOGP画像を自動生成して詰まった話

Last updated at Posted at 2025-12-27

はじめに

Next.jsで作成した自分のポートフォリオサイトにOGP画像を設定した際、「画像が表示されない」「フォントの太さが効かない」といった問題にかなりハマりました。

この記事では、Next.js(App Router)でOGP画像を自動生成する方法と、
実際に詰まったポイント・注意点をまとめます。
今回作成したOGP画像は↓の感じです。

※ 本記事は Next.js 13以降の App Router 前提です(Pages Router では使えません)。

お品書き

  • OGP・OGP画像とは
  • Next.jsでOGP画像を生成する
  • OGP画像の確認方法
  • OGP画像を反映させる(metadataBaseの設定)
  • まとめ

OGP・OGP画像とは

OGPとは Open Graph Protocol の略で、
Slack / LINE / X(旧Twitter)/ Facebook などのSNSで
Webページを共有した際に表示される情報を制御する仕組みです。

具体的には、URLを共有したときに表示される

  • サイトタイトル
  • 説明文
  • サムネイル画像(OGP画像)

などを設定できます。

例えば、SlackでQiitaの記事URLを送信すると、以下のようなプレビューが表示されます。

SlackでのOGP表示例

OGPを適切に設定すると、
URL単体よりも情報量が増え、SNS上でのクリック率向上が期待できます。
(直接的なSEO効果は限定的ですが、SNS流入の増加による間接的な効果は見込めます)

OGPはHTMLのheadタグの中にog:~~のmetaタグを追加することで設定することができます。

詳しい話はSmartHRさんがDesign Systemの紹介で記述していたので確認してみてください。

Next.jsでOGP画像を生成する

OGP画像は通常、ページごとに画像を作成して設定する必要があります。
しかし、ページが増えるたびに画像を用意するのは正直かなり面倒です。

そこでNext.js(App Router)では、
OGP画像を動的に生成する仕組みが公式で提供されています。

今回はその仕組みを使って、
ポートフォリオサイトのOGP画像を自動生成しました。

今回作成したOGP画像生成のファイルは以下です。

next/og を利用した画像生成

Next.jsでは next/og モジュールの
ImageResponse コンストラクタを使ってOGP画像を生成できます。

公式ドキュメント

この仕組みを使うと、

  • JSX + CSS で画像を作成できる
  • 動的ルーティング(Dynamic Route)にも対応できる

というメリットがあります。

※runtimeにedgeを利用しているため一部使用できないNode.jsAPIがあります。

ファイル名と配置ルール(重要)

OGP画像を自動生成するためには、ファイル名に厳密なルールがあります。

  • ファイル名:opengraph-image.(js | ts | tsx)
  • 配置場所:対象ページのディレクトリ配下

例:app/about/opengraph-image.tsx
opengraph-image.tsx の例

import { ImageResponse } from 'next/og'
import { readFile } from 'node:fs/promises'
import { join } from 'node:path'
export const alt = 'About Acme'
export const size = {
  width: 1200,
  height: 630,
}
export const contentType = 'image/png'
export default async function Image() {
  const interSemiBold = await readFile(
    join(process.cwd(), 'assets/Inter-SemiBold.ttf')
  )
  return new ImageResponse(
    (
      <div
        style={{
          fontSize: 128,
          background: 'white',
          width: '100%',
          height: '100%',
          display: 'flex',
          alignItems: 'center',
          justifyContent: 'center',
        }}
      >
        About Acme
      </div>
    ),
    {
      ...size,
      fonts: [
        {
          name: 'Inter',
          data: interSemiBold,
          style: 'normal',
          weight: 400,
        },
      ],
    }
  )
}

注意点:フォントと font-weight が効かない問題

next/og は内部的に @vercel/og(Satori)を使用しています。
そのため、デフォルトフォントでは font-weight が効きません。
太字を使いたい場合は、
フォントファイルを明示的に読み込む必要があります。

関連Issue
https://github.com/vercel/next.js/issues/50127

動的ルートの場合

動的ルートの場合もやることは変わらないですが、例えば記事ごとに表示させるテキストを変更することもできます。

openGraph-image.tsxファイル内でidを元にして外部からの情報をfetchして反映します。以下が記述例です。

import { ImageResponse } from 'next/og'
import { getCaptionForImage, getOGImages } from '@/app/utils/images'
 
export async function generateImageMetadata({
  params,
}: {
  params: { id: string }
}) {
  const images = await getOGImages(params.id)
 
  return images.map((image, idx) => ({
    id: idx,
    size: { width: 1200, height: 600 },
    alt: image.text,
    contentType: 'image/png',
  }))
}
 
export default async function Image({
  params,
  id,
}: {
  params: Promise<{ id: string }>
  id: Promise<number>
}) {
  const productId = (await params).id
  const imageId = await id
  const text = await getCaptionForImage(productId, imageId)
 
  return new ImageResponse(
    (
      <div
        style={
          {
            // ...
          }
        }
      >
        {text}
      </div>
    )
  )
}

OGP画像の確認方法

/opengraph-imageに直接アクセスする

ローカルサーバーを立ち上げてhttp:localhost:3000/.../opengraph-imageにアクセスすると生成されたOGP画像を直接確認することができます。

Chrome拡張機能を使った確認

以下のChrome拡張を使うと、localhostのページを一時的に外部公開することができます。

公開されたURLをOGP確認サイトに入力してチェックします。

OGP確認サイト例

メリット

  • 複数パターンのOGP表示タイプを確認できる

デメリット

  • 一時URLのため有効期限が短い(15分でリンクが切れる)

【個人的再推し】Vercel OG Image Playground

JSXを貼り付けるだけで、OGP画像の生成結果を確認することができます。
スクリーンショット 2025-12-27 22.30.47.png

メリット

  • 5種類ぐらいOGP画像のテンプレートが用意されている
  • サイト内のエディタでコードを編集したらすぐに画像が再生成されるので試行錯誤しやすい

デメリット

  • 外部フォントの読み込みをした上での画像生成はできない(と思われる)

OGP画像を反映させる(metadataBaseの設定)

opengraph-imageファイルを作成しただけではSNS上で正しくOGP画像を表示できない場合があります。この問題を解決するためにNext.js側でmetadataBaseを設定する必要があります。

metadataの設定はlayout.tsx,page.tsxで行います。

import type { Metadata } from 'next'

export const metadata: Metadata = {
  title: "mimimimimimi's portfolio",
  description: 'mimimimimimi is created',
  metadataBase: new URL('https://bike-bun-bun.com'),
  openGraph: {
    url: 'https://bike-bun-bun.com',
  },
  twitter: {
    card: 'summary_large_image',
    title: 'title',
  },
}

metadataBaseを設定しておくとopenGraph.urlを省略してもNext.jsがmetadataBaseのURLを自動的に見てくれるようになります。これでSlackやXなどにURLを貼った時にOGP画像が正しく表示されるようになります。

twitterはtwitterでOGPを表示する時の設定するオプションで、cardとはOGPの情報を表示する形式を指定するプロパティです。他にもtwitterはサイト作成者のTwitterIdやユーザーネームなどの設定を行うことができます。
詳しくは以下のドキュメントを読んでみてください。

OGP画像のURLがlocalhostを指してしまう問題

自分はmetadataの設定を一切していない状態でOGP画像の作成を行いましたが、localhostを指す問題が発生しました。確認手順を以下に記しておきます。

  1. デプロイ先のサイトを開く
  2. 開発者モード(検証)タブを開く
  3. headタグのmetaタグを確認する
  4. メタタグの<meta property="og:image" content="...">を確認する

contentには画像のURLが入るのですが、ここにlocalhost:3000/.../opengraph-imageみたいな記述があったらOGP画像をうまく表示できていない状態です。
749fc7ab-9f33-4798-a92b-486ee86c005c.png

まとめ

Next.jsのnext/ogはめちゃ便利だけど詰まりやすいポイントが各所にあるので注意しましょう。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?