Next.jsにFirebaseアナリティクス(Google Analytics)を追加するには、 クライアントサイドでFirebase Analyticsを初期化し、必要に応じてイベント計測を行うようにします
measurementId を含む構成情報を取得します。npm install firebase
.env.local`
NEXT_PUBLIC_FIREBASE_API_KEY=xxx
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=xxx
NEXT_PUBLIC_FIREBASE_PROJECT_ID=xxx
NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET=xxx
NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=xxx
NEXT_PUBLIC_FIREBASE_APP_ID=xxx
NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID=xxx
src/common/firebase/firebaseConfig.ts
import type { Analytics } from "firebase/analytics";
import { getAnalytics, isSupported } from "firebase/analytics";
import type { FirebaseApp } from "firebase/app";
import { getApps, initializeApp } from "firebase/app";
const firebaseConfig = {
apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY,
authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,
projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET,
messagingSenderId: process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID,
appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID,
measurementId: process.env.NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID,
};
// Firebase アプリの初期化(既に初期化されている場合は既存のものを使用)
export const app: FirebaseApp =
getApps().length === 0 ? initializeApp(firebaseConfig) : getApps()[0];
// Analytics シングルトンインスタンス
let analyticsInstance: Analytics | null = null;
let analyticsInitialized = false;
// Analytics の初期化(内部的に1度だけ実行)
const initializeAnalytics = async (): Promise<void> => {
if (analyticsInitialized) return;
if (typeof window !== "undefined" && (await isSupported())) {
analyticsInstance = getAnalytics(app);
analyticsInitialized = true;
} else {
analyticsInitialized = true; // 失敗しても再試行しない
}
};
// Analytics インスタンスを取得(常に同じインスタンスを返す)
export const getFirebaseAnalytics = (): Analytics | null => {
return analyticsInstance;
};
// アプリ起動時に自動初期化
if (typeof window !== "undefined") {
initializeAnalytics();
}
AnalyticsProvider.tsx
"use client";
import { logEvent } from "firebase/analytics";
import { usePathname } from "next/navigation";
import { type ReactNode, useEffect } from "react";
import { getFirebaseAnalytics } from "@/common/firebase/firebaseConfig";
type AnalyticsProviderProps = {
children: ReactNode;
};
export const AnalyticsProvider = ({ children }: AnalyticsProviderProps) => {
const pathname = usePathname();
// pathname変更時にpage_viewイベントを送信
useEffect(() => {
const analytics = getFirebaseAnalytics();
if (analytics) {
logEvent(analytics, "page_view", {
page_path: pathname,
});
}
}, [pathname]);
return <>{children}</>;
};
src/app/providers.tsx
"use client";
import type { FC, ReactNode } from "react";
import { AnalyticsProvider } from "@/common/firebase/AnalyticsProvider";
type Props = {
children: ReactNode;
};
export const Providers: FC<Props> = ({ children }) => {
return (
<AnalyticsProvider>
{children}
</AnalyticsProvider>
);
};
呼び出し方
src/app/layout.tsx で以下のようにして呼び出します。
<Providers>{children}</Providers>
これだけでページ遷移時に自動的にGoogleアナリティクスに送信されます。
# イベントの送信方法
useLogEvent.ts
"use client";
import { logEvent as firebaseLogEvent } from "firebase/analytics";
import { getFirebaseAnalytics } from "@/common/firebase/firebaseConfig";
export const useLogEvent = () => {
const logEvent = (
eventName: string,
eventParams?: Record<string, string | number | boolean>,
) => {
const analytics = getFirebaseAnalytics();
if (analytics) {
firebaseLogEvent(analytics, eventName, eventParams);
}
};
return { logEvent };
};
const { logEvent } = useLogEvent();
// バリデーションエラー時の処理
logEvent("任意のイベント名", {
// 任意のオブジェクト
});
Google Analyticsの公式イベントについて、カテゴリ別に説明します。
補足: これらの公式イベントを使用することで、Google Analyticsでの標準レポートが自動的に機能し、他のアプリとの比較も可能になります。
https://chromewebstore.google.com/detail/google-analytics-debugger/jnkmfdileelhofjcijamephohjechhna
Google Analytics 4(GA4)の管理画面にログインします。
左下の「管理」をクリックします。
「プロパティ」列から「データの表示」を探し、「DebugView」を選択します。
DebugViewの画面が起動し、左側に過去30分のイベントタイムライン、右側に各イベントの詳細情報が見られます。
https://dev.classmethod.jp/articles/classmethod-study-meeting-osaka-react-core-web-vital/
https://nextjs.org/learn/seo/web-performance
Next.jsのuseReportWebVitalsフックで取得できる指標は以下の通りです。
| 指標名 | 正式名称 | 説明 | 測定内容 | |
|---|---|---|---|---|
| LCP | Largest Contentful Paint | 最大のコンテンツ要素が描画されるまでの時間 | メインコンテンツの読み込み速度 | |
| INP | Interaction to Next Paint | 操作から次の描画までの時間 | 全体的なインタラクティブ性 | 2 |
| CLS | Cumulative Layout Shift | ページの視覚的安定性 | レイアウトのずれの累積値 | |
| FID | First Input Delay | ユーザーの最初の操作に対する応答時間 | インタラクティブ性(非推奨、INPに置き換え) | |
| TTFB | Time to First Byte | サーバーからの最初のバイト受信までの時間 | ネットワークリクエストの応答速度 | |
| FCP | First Contentful Paint | 最初のコンテンツが画面に描画されるまでの時間 | ページの初期レンダリング速度 |