Next.jsでGoogle Optimaizeの実装
Next.jsでGoogle Optimaizeを実装しようとするとgtag.jsを記述しないといけないのですが、公式で記載されているものをそのまま搭載してもPVを取ってくれなかったり、ちゃんとテスト出来ない状態になってしまうのでそれ用に記述を変えてあげないといけないとのことで、やっていきたいと思います。
今回はTypeScriptでの実装になります。
参考にさせていただいたサイト
- Next.jsでGoogle Analyticsを使えるようにする
- Next.jsプロジェクトにGoogle Analyticsを導入する
- 公式サンプル
- 公式サイトの環境変数のところ
- TypeScript でモジュール内でのみ参照可能なグローバル変数を宣言する
- SPA(Gatsby)を使い、Google OptimizeでA/Bテストをする方法
.envの作成
.envに記載した環境変数はprocess.env
でアクセス出来ますので.envにGAのIDを記載します。
NEXT_PUBLIC_GA_TRACKING_ID=<YOUR_GA_ID>
何回か公式サイトを読んで.envに何故書くのか?と思っているのですが(別に普通にexportで呼び出しても使えるのを確認しているので)
サイトアクセスしている間だけアクセスしたいのでグローバル変数として設定しているんだ、と参考サイトを読んで納得しました。
(間違いありましたら指摘お願いします)
gtag.tsxを作成
こちらも参考サイト確認しながら作成します。
ディレクトリ直下に/lib/
を作成して配下gtag.tsxを作成します。
GAのトラッキングコードとオプティマイズスニペット用のIDもここで記載します。
ここで2つとも記載するのはIDを別々で管理するよりひとつのファイルで管理するほうが煩雑にならないで良い、という判断です。
ページビューの送信とイベント送信の記述もします。
export const GA_TRACKING_ID = process.env.NEXT_PUBLIC_GA_TRACKING_ID || ''
export const OPT_TRACKING_ID = <YOUR_OPT_ID>;
// https://developers.google.com/analytics/devguides/collection/gtagjs/pages
export const pageview = (url: string) => {
window.gtag('config', GA_TRACKING_ID, {
page_path: url,
})
}
// https://developers.google.com/analytics/devguides/collection/gtagjs/events
type GaEventProps = {
action: string
category: string
label: string
value?: number
}
export const event = ({ action, category, label, value }: GaEventProps) => {
window.gtag('event', action, {
event_category: category,
event_label: label,
value: value,
})
}
_document.tsxへ記述
_document.tsxはmeta要素などheadの中で共通呼び出しをするものなどに使用するのでこちらでスクリプトの記述をします。
gtag.tsxを_document.tsxで呼び出してhead内に呼び出す記述をします。
import Document, { Html, Head, Main, NextScript } from 'next/document'
import { GA_TRACKING_ID, OPT_TRACKING_ID } from '../lib/gtag'
class MyDocument extends Document {
static async getInitialProps(ctx) {
const initialProps = await Document.getInitialProps(ctx)
return { ...initialProps }
}
render() {
return (
<Html lang="ja">
<Head>
{/* GA_TRACKING_IDがあればスクリプトを呼び出す記述 */}
{GA_TRACKING_ID && (
<>
<script async={true} src={`https://www.googletagmanager.com/gtag/js?id=${GA_TRACKING_ID}`} />
<script dangerouslySetInnerHTML={{
__html: `
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', '${GA_TRACKING_ID}', {
page_path: window.location.pathname,
});`,
}}
/>
<script src={`https://www.googleoptimize.com/optimize.js?id=${OPT_TRACKING_ID}`}></script>
</>
)}
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
}
export default MyDocument
_app.tsxに共通処理を書く
下記の処理を書いていきます。
- PVをカウントするイベント
- アクティベーションイベントの処理と発火タイミングを記載
PVはRouterのURL書き換えが完了した時に発火するrouteChangeCompleteイベント
というときに発火しないとサイトを回遊したときにちゃんと取ってくれないので設定します。
アクティベーションイベントはオプティマイズの機能で、エクスペリエンスがトリガーされるタイミング
つまりABテストが反映されるタイミングを指定できます。
最初はページが読み込まれたときなのですが、これをカスタムイベントにしないとSPAの仕様上
ABテスト反映→オリジナル→ABテスト反映
となってしまい正常な数値が取れなかったり、新しく追加したABテスト用の文言が反映されなかったりと正常な数値が取れない、ABテストの表示がうまくいかないなど不具合が出ますので発火タイミングをカスタムイベント後に設定してあげる必要があります。
まずオプティマイズ側のアクティベーションをカスタムイベントにします。
その後_app.tsxにふたつのイベントを記載します。
Googleの公式サイトにカスタムイベントをするときの記述がありますがそれをそのまま入れてもTypeScriptにてプロパティ 'dataLayer' は型 'Window & typeof globalThis' に存在しません。
というのが表示されます。
window.dataLayer.push({ event: "optimize.activate" });
このWEB上のグローバル変数を動かせる記述はあるのですがあちこちで動かせるように記載すると保守性が下がるのでラッパーのところで記載してあげます。
declare const window: Window['window'] & {
dataLayer: object[];
};
上記の記載をしてあげることでこの内部だけでグローバル変数を動作するようにすることができます。
import '../styles/globals.css'
import { useRouter } from "next/router";
import * as gtag from "../lib/gtag";
import { useEffect } from "react";
declare const window: Window["window"] & {
dataLayer: object[];
};
function MyApp({ Component, pageProps }) {
const router = useRouter();
const pathName = router.pathname;
// PVイベント用
useEffect(() => {
const handleRouteChange = (url: string) => {
gtag.pageview(url)
}
// ルートの変化が完了したときに発火
router.events.on('routeChangeComplete', handleRouteChange)
return () => {
router.events.off('routeChangeComplete', handleRouteChange)
}
}, [router.events])
// カスタムイベント用
useEffect(() => {
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({ event: "optimize.activate" });
}, [pathName]);
return <Component {...pageProps} />
}
export default MyApp
これでNext.jsでGoogle Optimaizeの実装が完了です!
インストールされているか確認して成功していれば問題なくABテストを開始することが出来るはずです!
一応Githubにサンプルを出していますのでよければ参考にしてください。
サンプル
分からないなりに調べながらやりましたが、
すごく時間かかりましたが結構かんたんに搭載できる!!
とそう思ったのですが結構調べるのに苦労したので参考になればなと思います。
Discussion