Next.jsでCore Web Vitalsを測定する:RUMセットアップガイド
Next.jsにおけるCore Web VitalsのためのReal User Monitoring (RUM)の設定 (App RouterおよびPages Router)

Next.jsでCore Web Vitalsを測定する
Next.jsはReactの上に構築されたJavaScriptフレームワークであり、超高速で非常に使いやすいWebサイトを構築することを可能にします。確かに、Next.jsは非常に高速であり、その速度を維持するための多くの機能が組み込まれています。少なくとも、理論上はそうです。しかし時間が経つにつれて、Webサイトが成長し、より多くの機能が追加され、場合によってはすべてのベストプラクティスが守られていないとき、Next.jsのページはどんどん遅くなっていきます。おそらくそれが、あなたがこのページを訪れた理由でしょう :-)
最終レビュー: 2026年3月、Arjen Karelによる
遅いページを測定して防ぐには、Core Web Vitalsを測定し、指標がしきい値を下回ったときに対策を講じることが重要です。3つのCore Web Vitalsは、読み込みに関するLargest Contentful Paint (LCP)(しきい値: 2.5秒)、インタラクティブ性に関するInteraction to Next Paint (INP)(しきい値: 200ミリ秒)、および視覚的安定性に関するCumulative Layout Shift (CLS)(しきい値: 0.1)です。2025年のWeb Almanacによると、モバイルのオリジンのうち3つすべてに合格しているのはわずか48%です。特にNext.jsのサイトの場合、2023年のAstroフレームワークレポートでは、Next.jsのオリジンの約25%しか合格していないことがわかりました。Next.js 14および15におけるServer ComponentsとApp Routerはこれを改善しましたが、自身の現在地を知る唯一の方法は、独自のフィールドデータを測定することです。
Lighthouseのことは忘れましょう(ある意味で)
LighthouseはCore Web Vitalsのテストツールです。私が仕事をするほぼすべてのクライアントは、ある時点でLighthouseのスコアについて話し始め、それがSearch Consoleのスコアとどう一致しないのかを尋ねてきます。私が最初に伝えるのは、これです。「Lighthouseのことは忘れてください」。説明しましょう。

Lighthouseは、制御された条件下での非キャッシュの初回訪問時の「ラボデータ」を収集する非常に便利なツールです。残念ながら、収集されたデータが必ずしもフィールドデータを反映しているわけではありません。フィールドデータは、ユーザーがページを読み込むたびにブラウザによって収集されます。その後、そのデータはGoogleに送信され、実際のCore Web Vitalsスコアを決定するために使用されます。このプロセスは、Real User Monitoring (RUM)とも呼ばれます。
多くの開発者が見落としていることは次のとおりです。すなわち、INPはラボツールではまったく測定できないということです。LighthouseはWebサイトと対話しないため、インタラクションデータを持っていません。Total Blocking Time(TBT)をプロキシとして使用しますが、TBTとINPは同じものではありません。ラボツールでのCLSも、Lighthouseがページをスクロールしたりクリックしたりしないため、不自然に低いスコアを示します。実際のINPとCLSの数値を得る唯一の方法は、実際のユーザーから取得することです。
誤解しないでください。私はLighthouseが大好きです。これは見事なソフトウェアであり、おそらく実装すべき素晴らしい提案をくれます。私が言いたいのは、Next.jsサイトにおけるRUMの指標は、単なる初回の非キャッシュのビューだけで構成されているわけではないということです。そうではなく、Next.js WebサイトでのCore Web Vitalsはもっと複雑なのです。だからこそ、私がクライアントのために最初に実装することの1つが、リアルタイムのReal User Monitoringなのです。Googleのランキングの基準はLighthouseのスコアではなく、CrUXのフィールドデータです。
Next.jsでのCore Web Vitalsの測定 (App Router)
App Router(Next.js 13以降)を使用している場合、Core Web Vitalsを収集するための推奨される方法は、next/web-vitalsのuseReportWebVitalsフックです。このフックはNext.js自体に同梱されているため、追加でインストールするものはありません。
このフックは'use client'ディレクティブを必要とするため、小さなコンポーネントに分離するのがベストプラクティスです。これにより、クライアントの境界を狭く保ち、レイアウト全体をクライアントコンポーネントにしてしまうのを防ぎます。
// app/_components/web-vitals.js
'use client'
import { useReportWebVitals } from 'next/web-vitals'
export function WebVitals() {
useReportWebVitals((metric) => {
console.log(metric)
})
return null
}
次に、それをルートレイアウトでインポートします。
// app/layout.js
import { WebVitals } from './_components/web-vitals'
export default function Layout({ children }) {
return (
<html>
<body>
<WebVitals />
{children}
</body>
</html>
)
}
これで完了です。すべてのページの読み込みで、LCP、INP、CLS、FCP、およびTTFBがコンソールに報告されるようになります。もちろん、運用環境でコンソールにログを出力してもあまり意味がありません。ここからは、データをより有用な場所に送信する方法を説明しましょう。
カスタムエンドポイントにCore Web Vitalsを送信する
パフォーマンスデータを送信する最も信頼性の高い方法は、navigator.sendBeacon()です。これはまさにこの目的のために設計されています。すなわち、ナビゲーションをブロックすることなく、ユーザーがページから離れるときに小さなペイロードを送信します。
// app/_components/web-vitals.js
'use client'
import { useReportWebVitals } from 'next/web-vitals'
export function WebVitals() {
useReportWebVitals((metric) => {
const url = 'https://example.com/analytics'
const body = JSON.stringify(metric)
if (navigator.sendBeacon) {
navigator.sendBeacon(url, body)
} else {
fetch(url, { body: body, method: 'POST', keepalive: true })
}
})
return null
}
Google Analytics (GA4) にCore Web Vitalsを送信する
gtagスニペットを使用したGoogle Analytics 4を使用している場合は、Core Web Vitalsをカスタムイベントとして送信できます。
// app/_components/web-vitals.js
'use client'
import { useReportWebVitals } from 'next/web-vitals'
export function WebVitals() {
useReportWebVitals((metric) => {
window.gtag('event', metric.name, {
event_category: 'Web Vitals',
value: Math.round(metric.name === 'CLS' ? metric.value * 1000 : metric.value),
event_label: metric.id,
non_interaction: true,
})
})
return null
}
覚えておいてください。任意のRUMソースからCore Web Vitalsデータを読み取るときは、75パーセンタイルを使用する必要があります。これがGoogleの使用するしきい値です。平均値でも中央値でもありません。p75です。
トラフィックの多いサイトでのサンプリング
トラフィックの多いWebサイトでは、すべてのユーザーからデータを収集してもほとんど意味がありません。次のように、50%以下でサンプリングできます。
// app/_components/web-vitals.js
'use client'
import { useReportWebVitals } from 'next/web-vitals'
const inSample = Math.random() >= 0.5
export function WebVitals() {
useReportWebVitals((metric) => {
if (inSample) {
const body = JSON.stringify(metric)
navigator.sendBeacon('/analytics', body)
}
})
return null
}
Next.jsでのCore Web Vitalsの測定 (Pages Router)
まだPages Routerを使用している場合、Next.jsにはpages/_app.jsからエクスポートする組み込みのreportWebVitals関数が提供されています。これは古いアプローチですが、現在も機能します。
// pages/_app.js
export function reportWebVitals(metric) {
if (metric.label === 'web-vital') {
console.log(metric)
}
}
export default function App({ Component, pageProps }) {
return <Component {...pageProps} />
}
カスタムエンドポイントまたはGoogle Analyticsにデータを送信するための同じパターンがここにも適用されます。フックのコールバックの代わりに、reportWebVitals関数内にsendBeaconまたはgtagの呼び出しを配置するだけです。
注意すべき点の1つは、Pages RouterはNext.js-hydrationやNext.js-route-change-to-renderのようなNext.jsのカスタム指標もレポートすることです。これらは、ハイドレーションとクライアントサイドのナビゲーションにかかる時間を示します。App Routerバージョンでは、これらのカスタム指標はまだレポートされません。
サードパーティの監視ツール
Next.jsでCore Web Vitalsを収集するサードパーティツールはいくつかあります。Vercelには@vercel/speed-insightsがあり、Vercelにデプロイすれば設定なしですぐに機能します。簡単な概要を把握するには十分ですが、指標を細かいパーツに分解することはなく、ダッシュボードは基本的なものであり、Vercelエコシステムにロックインされることになります。
NewRelicとSentryはどちらもCore Web Vitalsを収集しますが、それらはパフォーマンスツールではありません。それらは、機能としてCore Web Vitalsを後付けしたエラートラッキングおよびAPMツールです。どちらも、初期のネットワークリソースとメインスレッドの時間を奪い合うスクリプトを注入します。私は、Sentryがモバイルで200ミリ秒のブロッキング時間を追加するのを見たことがあります。パフォーマンスの監視を助けるはずのツールとしては皮肉なことです。
私が使用し、推奨しているのはCoreDashです。これはCore Web Vitals専用に構築されています。すべての指標がサブパーツに分解されるため、どこに時間がかかっているかを正確に把握できます。ダッシュボードには、5つのメニューをクリックしなくても、傾向、リグレッション、ページレベルの内訳が表示されます。さらに、MCP統合により、フィールドデータをAIツールに接続し、平易な言葉でパフォーマンスに関する質問をすることができます。単に「モバイルでレイアウトシフトの原因となっているものは何か?」と尋ねるだけで、自分自身のデータから答えを得ることができます。
Next.jsでサードパーティスクリプトの問題を修正したり、レンダリングブロックとなるCSSを削除したりしたい場合、それらに関する専用のガイドも執筆しています。

