たくさんの自由帳

Next.jsへGoogleアナリティクスのGA4とUAを共存させる

投稿日 : | 0 日前

文字数(だいたい) : 9566

どうもこんばんわ。

キスから始まるギャルの恋 〜くるみのウワサとホントのキモチ〜 攻略しました。

いいね!次回作も予約した

Imgur

丁寧に書かれてて?良かったと思います

Imgur

本題

GoogleアナリティクスからGA4を使ってみませんかって定期的にメールでお知らせしてくるので対応してみた。
Next.jsで作り直した記念に

環境

なまえあたい
Windows10 Pro
Next.js記述時時点最新版
React17
言語TypeScript。JavaScriptの場合はコピペ出来ないのでにらめっこして書き換えて;;

参考

thx!!!!!

https://github.com/vercel/next.js/tree/main/examples/with-google-analytics

https://panda-program.com/posts/nextjs-google-analytics

GA4 と UA はぜんぜん違う?

なんか後継みたいな雰囲気(なぜか変換できない(できてる))出してますが、UIからして結構違うシステムらしい?
なんならユニバーサルアナリティクス (UA)時代に集計したデータはGoogle アナリティクス 4 (GA4)には引き継げないみたいですよ?

データがGA4に引き継げないのはしんどいので、とりあえずはユニバーサルアナリティクスGoogle アナリティクス 4の同時利用で行きます(同じ結果が集計されるはず)。

(ちょっと時間が経っちゃったからうろ覚え)

単語集

きーばりゅー
ユニバーサルアナリティクス略してUA。設定を開いた際にGA4 設定アシスタントがあればUA
Google アナリティクス 4略してGA4。リアルタイムのページに地図が表示されていればGA4
測定 IDGA4で使うID。 G- から始まる
トラッキングコードUAで使うID。 UA- から始まる

既存のユニバーサルアナリティクスでGA4を有効にする

ブラウザでUAの方の設定画面を開いて、Google アナリティクス 4 プロパティの設定アシスタントを選んで、始めます

Imgur

こんな画面が出るけど、今回は UA → GA4 へイベントの転送は行わずに、それぞれ対応するのでチェックマークはそのままにして、プロパティを作成をおします。
(自分でHTMLを書き換えることが出来ない場合のための処置だと思う)

Imgur

作成できるとGA4の管理ページへ移動できるボタンが現れるのでそのままおします。

Imgur

移動したら、タグの設定を押して、一つだけデータストリームがあると思うのでそれを選択します。

Imgur

そしたら、表示されている測定 IDを控えます。G-から始まるやつですね。

Imgur

Next.js(のnext/router)でも動くように対応する

測定 IDを控えた画面にある歯車マーク⚙を押して、拡張計測機能の設定をします。
ここのページビュー数詳細設定を押して、ブラウザの履歴イベントに基づくページの変更のチェックマークを外して、保存を押します。

Imgur

なぜ?

Next.js 等のJSフレームワークでは画面を動的に書き換えて(ブラウザのロードを挟まない)画面遷移が行われるため、Googleアナリティクスではページ遷移イベントを捕捉出来ません。
ので、自分でページ遷移イベントを送信する必要があるのですが、なんかGA4にロードを挟まない遷移を捕まえることが出来るようになったらしく、このままでは二重で計測されてしまう。
そこでGA4の計測の設定を変えます。

もしかしたら、上記のチェックマークをONにしておくと、ページの変更イベントをわざわざ送信する必要もなくなるかもしれないけど、UAと合わせたいので今回はOFFで行きます。

(analytics.js から gtag.js へ移行する)

もしgtag.jsで書いていた場合はここは飛ばしていいと思います。

UAの方の設定画面を開いて、トラッキング情報 > トラッキングコードへ進み、トラッキング IDをコピーします。UA-から始まるやつですね。

Next.js での作業

_app.tsx(jsxかもしれん)を開きます。
作っていない場合は他調べて作って下さい。

そしたら、以下を参考に書いて下さい(まるなげ)
analytics.js時代のコードは消しちゃえ~。
定数UA_TRACKING_IDの中には各自UAのトラッキングIDを入れて下さい。


// 各自ここに UA トラッキング ID
const UA_TRACKING_ID = `UA-`

const App = ({ Component, pageProps }) => {
    return (
        <>            
            {/* Google アナリティクス GA4 / UA */}
            <Head>
                <script async src={`https://www.googletagmanager.com/gtag/js?id=${UA_TRACKING_ID}`}></script>
                <script dangerouslySetInnerHTML={{
                    __html: `
                        window.dataLayer = window.dataLayer || [];
                        function gtag(){dataLayer.push(arguments);}
                        gtag('js', new Date());
                        gtag('config', '${UA_TRACKING_ID}');
                    `}}
                />
            </Head>

            <Component {...pageProps} />
        </>
    )
}
export default App

gtag.js に GA4 も計測するように書き足す

gtag('config', '${UA_TRACKING_ID}');と同じ様にGA4の測定 IDを登録します。
gtag.jsを読み込んでる<script>タグはそのままUAのを使えるみたいです。

以下例:

// 各自ここに UA トラッキング ID
const UA_TRACKING_ID = `UA-`
// 各自ここに GA4 測定 ID
const GA_TRACKING_ID = `G-`

const App = ({ Component, pageProps }) => {
    return (
        <>            
            {/* Google アナリティクス GA4 / UA */}
            <Head>
                <script async src={`https://www.googletagmanager.com/gtag/js?id=${UA_TRACKING_ID}`}></script>
                <script dangerouslySetInnerHTML={{
                    __html: `
                        window.dataLayer = window.dataLayer || [];
                        function gtag(){dataLayer.push(arguments);}
                        gtag('js', new Date());
                        gtag('config', '${UA_TRACKING_ID}');
                        gtag('config', '${GA_TRACKING_ID}');
                    `}}
                />
            </Head>

            <Component {...pageProps} />
        </>
    )
}
export default App

Next.jsの next/script 使えないの?

これ使うと<body>内に<script>埋め込んでるっぽいんだけどどうなんだろう。Googleアナリティクスは<head>内に書いてって言われてるので...

UAの gtag.js 転用して使えんのかよwww

既存の gtag.js を読み込んでいる場合はGA4の測定IDを登録する一行をそのまま書き足せばOKらしい。やるやん

https://support.google.com/analytics/answer/9310895?hl=ja&utm_id=ad#which_product&zippy=%2Cこの記事の内容

next/router のページ遷移イベントを登録する

このままだと初回の読み込みは正しく送信されますが、ページを切り替えた際には対応できません。
のでnext/routerの遷移イベントをGA4とUAへ飛ばします。

以下例:
TSなのにas anyしてるから参考にするには良くないかも。
JavaScript派閥の方はTypeScriptの型注釈(とキャスト)を消して、どうぞ。

// 各自ここに UA トラッキング ID
const UA_TRACKING_ID = `UA-`
// 各自ここに GA4 測定 ID
const GA_TRACKING_ID = `G-`

/**
 * ページ遷移のたびに呼ぶ
 * 
 * @param {string} url うらる
 */
const pageview = (url: string) => {
    // 多分 UA と GA4 両方それぞれ送信しないといけない
    (window as any).gtag('config', UA_TRACKING_ID, {
        page_path: url,
    });
    (window as any).gtag('config', GA_TRACKING_ID, {
        page_path: url,
    });
}

const App = ({ Component, pageProps }) => {

    // Google アナリティクスへページ遷移を通知
    const router = useRouter()
    useEffect(() => {
        const handleRouteChange = (url: string) => {
            pageview(url)
        }
        router.events.on('routeChangeComplete', handleRouteChange)
        return () => {
            router.events.off('routeChangeComplete', handleRouteChange)
        }
    }, [router.events])

    return (
        <>            
            {/* Google アナリティクス GA4 / UA */}
            <Head>
                <script async src={`https://www.googletagmanager.com/gtag/js?id=${UA_TRACKING_ID}`}></script>
                <script dangerouslySetInnerHTML={{
                    __html: `
                        window.dataLayer = window.dataLayer || [];
                        function gtag(){dataLayer.push(arguments);}
                        gtag('js', new Date());
                        gtag('config', '${UA_TRACKING_ID}');
                        gtag('config', '${GA_TRACKING_ID}');
                    `}}
                />
            </Head>

            <Component {...pageProps} />
        </>
    )
}
export default App

これで多分対応は終了です。
GA4とUAそれぞれ開いて、ちゃんとリアルタイムに現れたら成功だと思います。

番外編 GoogleAnalytics.tsx にまとめる編

_app.tsxが長くなるとしんどいので分けておくと良いと思います。
ついでに本番環境のみGoogle アナリティクスを動作させるようにしました。

// GoogleAnalytics.tsx

/** Google アナリティクス (UA) の 測定ID */
export const UA_TRACKING_ID = `UA-`

/** Google アナリティクス (GA4) の 測定ID */
export const GA_TRACKING_ID = `G-`

/** 開発モード。本番(意味深)だけアナリティクスを動作させるため */
const isDevelopment = process.env.NODE_ENV === 'development'

/**
 * ページ遷移のたびに呼ぶ
 * 
 * @param {string} url うらる
 */
const pageview = (url: string) => {
    // 本番のみ実行
    if (isDevelopment) {
        return
    }
    (window as any).gtag('config', UA_TRACKING_ID, {
        page_path: url,
    });
    (window as any).gtag('config', GA_TRACKING_ID, {
        page_path: url,
    });
}

/** Google Analytics へnext/routerのページ遷移の状態を通知する */
export const useGoogleAnalytics = () => {
    // Google アナリティクスへページ遷移を通知
    const router = useRouter()
    useEffect(() => {
        const handleRouteChange = (url: string) => {
            pageview(url)
        }
        router.events.on('routeChangeComplete', handleRouteChange)
        return () => {
            router.events.off('routeChangeComplete', handleRouteChange)
        }
    }, [router.events])
}

/** Google Analytics 4 で利用するJavaScriptを差し込むやつ。本番(意味深)のみ実行 */
export const GoogleAnalyticsHead = () => {
    return (
        <>
            {!isDevelopment && <Head>
                <script async src={`https://www.googletagmanager.com/gtag/js?id=${UA_TRACKING_ID}`}></script>
                <script dangerouslySetInnerHTML={{
                    __html: `
                        window.dataLayer = window.dataLayer || [];
                        function gtag(){dataLayer.push(arguments);}
                        gtag('js', new Date());
                        gtag('config', '${UA_TRACKING_ID}');
                        gtag('config', '${GA_TRACKING_ID}');
                    `}}
                />
            </Head>}
        </>
    )
}

これを_app.tsxで呼ぶようにすればおっけ

import { GoogleAnalyticsHead, useGoogleAnalytics } from '../src/GoogleAnalytics'

const App = ({ Component, pageProps }) => {

    // GoogleAnalyticsへnext/routerのページ遷移を通知する。
    useGoogleAnalytics()

    return (
        <>            
            {/* Google アナリティクス GA4 / UA */}
            <GoogleAnalyticsHead />

            <Component {...pageProps} />
        </>
    )
}

もしパクった場合は本番環境のみで動くので、動いてるか確認したい場合は

npm run build
npm run start

すれば本番環境のビルド成果物をホストした開発サーバーが立ち上がります。

Imgur