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でOGP画像が表示されない原因とその対応策

Last updated at Posted at 2025-04-05

概要

Next.jsで構築したWebサイトにおいて、OGP画像がSNSで正しく表示されない問題が発生しました。
調査の結果、SSR(サーバーサイドレンダリング)時にクライアントオブジェクトである document を参照していたことが原因であると判明しました。

本記事ではその原因と対応策をまとめます。

問題の発生状況

  • Next.jsで構築したサイトをFacebookやX(旧Twitter)でシェア
  • OGP画像が表示されない
  • meta タグは正しく出力されている
  • OGP画像URLにも直接アクセス可能

調査の流れ

  1. metaタグの確認
    以下のように正しく記述されていたため、タグのミスではないと判断。

    <meta property="og:image" content="https://example.com/ogp.jpg" />
    <meta property="og:title" content="サイトタイトル" />
    
  2. Facebook Sharing Debuggerで確認
    Facebook Sharing Debugger にてURLを入力したところ、
    500 Internal Server Error が返されていました。

  3. Cloud Runのログ確認
    GCP(Google Cloud Run)のログを確認しましたが、payloadNotSet と表示されており、スタックトレースなどの詳細情報は取得できませんでした。

  4. 関連情報の調査
    以下の記事を発見し、類似の問題であると推測しました。
    https://blog.toru-takagi.dev/article/44/

原因

サーバーサイドレンダリング中に document.cookie を参照していたことが原因でした。
以下のようなコードが存在しており、これがSSR中にも実行されてしまい、
ReferenceError: document is not defined により500エラーが発生していました。

const hasCookie = document.cookie.includes('animationPlayed=true')

このコードは "use client" を記述しているファイル内で使用されていたため、
サーバーでは実行されないと思い込んでいました

しかし、Next.jsにおけるクライアントコンポーネントであっても、SSR時には関数本体が一度だけ評価されるため、
document などのクライアント専用オブジェクトを直接参照するとクラッシュします。

対応方法

クライアント側でのみ document を参照するよう、useEffect 内に処理を移動することで対応しました。

修正前(NG)

const hasCookie = document.cookie.includes('animationPlayed=true')

修正後(OK)

const [hasCookie, setHasCookie] = useState(false)

useEffect(() => {
  setHasCookie(document.cookie.includes('animationPlayed=true'))
}, [])

useEffect はクライアント側でのみ実行されるため、SSR中に document を参照することがなくなり、500エラーも解消されました。

なぜ「use client」だけでは不十分なのか

"use client" を付けたコンポーネントはクライアントコンポーネントとして扱われますが、
Reactが最初にHTMLを生成するためにコンポーネント関数本体を一度実行するという挙動は変わりません。

そのため、以下のような処理はSSR中にも評価されるため、注意が必要です。

// SSR中にも実行される(NG)
const width = window.innerWidth
const cookie = document.cookie

このような処理は、必ず useEffect または typeof window !== 'undefined' 等でガードする必要があります。

OGPとSSRの関係について補足

OGPは、ページのHTMLに含まれる <meta> タグの情報をもとにSNS側で展開されます。
FacebookなどのクローラーはJavaScriptを実行せず、SSRによって返されたHTMLのみを解析します。

つまり、SSR中にクラッシュしてHTMLが正しく返されない場合、OGP情報も取得できず、画像やタイトルが一切表示されないという結果になります。

まとめ

  • OGP画像が表示されない場合は、Facebook Debuggerなどでステータスコード(500など)を確認する
  • "use client" を記述していても、関数本体の評価はSSR中に一度だけ実行される点に注意
  • document, window, navigator, localStorage などのクライアント専用オブジェクトは、useEffect 内でのみ使用する

最後に

通常のブラウザの開発者ツールでは特に問題ないように見えるので解決に時間がかかりました
同様の現象に悩まれている方の参考になれば幸いです。

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?