記事

動的にOGPを生成する方法

satori

#tech

簡単に自分が理解したフローを描いておく
APIRouteでOGPを生成する関数を作る

  • そこに引数には、タイトルなどを流すようにする

metaタグのcontentにurlを書き込む

  • dev環境と本番環境でURLを動的に変わるようにしておいたら開発が楽になる

@vercel/ogを使う時は、vercel以外にdeployする時は動かないかもなので、そのときはsatoriを使う方がいいかもしれない

デザインはここで確認するのが良さそう

毎回deployしたり、ngrokでURLを発行して確認してると日が暮れる

https://rakko.tools/tools/9/

  • SNSなど共有したときにどんなふうに見えるのかを調整するツール

queryでtitleを渡そうとしたらハマった

import { ImageResponse } from "@vercel/og";
import { NextApiRequest, NextApiResponse } from "next";

export const config = {
  runtime: "edge",
};

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  console.log(req.query);
  const title = req.query.title as string;
  if (!title) {
    res.status(400).json({ error: 'Title is required' });
    return;
  }
  // const title = req.query.title as string;
  // console.log(title);
  return new ImageResponse(
    (
      <div
        style={{
          fontSize: 40,
          color: "black",
          background: "white",
          width: "100%",
          height: "100%",
          padding: "50px 200px",
          textAlign: "center",
          justifyContent: "center",
          alignItems: "center",
          display: "flex",
          flexDirection: "column",
          position: "relative",
        }}
      >
        {/* {title} */}
        'test'
        <div
          style={{
            position: "absolute",
            bottom: 10,
            right: 10,
            display: "flex",
            alignItems: "center",
          }}
        >
          <img
            src="https://kinjo.me/profile.jpg"
            alt="アイコン"
            style={{
              width: 30, // アイコンの幅
              height: 30, // アイコンの高さ
              marginRight: 5,
              borderRadius: "50%", // 画像を円形にする
            }}
          />
          <span style={{ fontSize: 16 }}>kinjo shotaro</span>
        </div>
      </div>
    ),
    {
      width: 1200,
      height: 630,
    }
  );
}
export default function BlogId({ blog }: { blog: BlogPost }) {
  const toc = renderToc(blog.body);
  const isDevImageUrl = process.env.NODE_ENV === "development" ? "http://localhost:3000" : "https://kinjo.me";
  return (
    <>
      <SeoHead
        title="Blog"
        titleTemplate={blog.title}
        description={blog.description}
        imgUrl={`${isDevImageUrl}/api/ogp?title=${encodeURIComponent(blog.title)}`}
      />

これはダメらしい??

    • わかった
    • ファイル名が、ogp.tsxにしてたのをog.tsxにしたらいけた

ファイル名が決まっているらしい

クエリには空欄でも行ける

  • api/og?title=kinjo shotaro
  • ブラウザはエンコードしてくれるからな気がする

© 2026 Shotaro Kinjo