⚒️

[Next.js] Google Analytics コンポーネントではオプションが設定できないので、今は自作して対応しよう

2024/09/17に公開

next.js では、next/third-parties を使うことによって Google Analytics や Google Maps Embed などのサードパーティーライブラリを効率よく導入することができます。

Next.js | Third Party Libraries

ただし、Google Analytics の場合は、2024 年の 9 月の段階では利用しない方がいいケースがあります。それが、send pageview events を false にしたり、共通パラメーターを設定したい場合です。デフォルトパラメータを設定しない場合は、Third Party Libraries | Google Analytics を参照して導入しても特に問題はありません。

改善提案 は Next.js に出していますので、そのうち改善される可能性はあります。

では、なぜ利用しない方がいいケースがあるのか見ていきましょう。

GoogleAnalytics コンポーネントは、gtag の config の第 3 引数に対応をしていない

Google Analytics コンポーネントでは、内部的に gtag.js を使っています。

この gtag の configgtag のドキュメントでは、第 3 引数も設定できるようになっており、この引数にオブジェクトを設定することによって、send pageview events を false にしたり、全てのイベントで共有して設定したいパラメーター(例: ユーザーの権限)を設定することができます。

ただし、Next.js Third Party Libraries の GoogleAnalytics コンポーネントでは、引数の gaId のみを gtag の config に渡すようになっています。そのため、send pageview events を false にしたり、共通パラメーターを設定することができません。

Next.js の Google Analytics コンポーネントのコード

export function GoogleAnalytics(props: GAParams) {
  const { gaId, dataLayerName = 'dataLayer' } = props

  if (currDataLayerName === undefined) {
    currDataLayerName = dataLayerName
  }

  useEffect(() => {
    // performance.mark is being used as a feature use signal. While it is traditionally used for performance
    // benchmarking it is low overhead and thus considered safe to use in production and it is a widely available
    // existing API.
    // The performance measurement will be handled by Chrome Aurora

    performance.mark('mark_feature_usage', {
      detail: {
        feature: 'next-third-parties-ga',
      },
    })
  }, [])

  return (
    <>
      <Script
        id="_next-ga-init"
        dangerouslySetInnerHTML={{
          __html: `
          window['${dataLayerName}'] = window['${dataLayerName}'] || [];
          function gtag(){window['${dataLayerName}'].push(arguments);}
          gtag('js', new Date());
          // gtag に第 3 引数が設定されていない
          gtag('config', '${gaId}');`,
        }}
      />
      <Script
        id="_next-ga"
        src={`https://www.googletagmanager.com/gtag/js?id=${gaId}`}
      />
    </>
  )
}

もし、send pageview events を false にしたり、共通パラメーターを設定したい場合は、GoogleAnalytics を使わずに、gtag.js を直接使いましょう。

import Script from 'next/script';
import { useMemo } from 'react';

type Props = {
  /**
   * Google AnalyticsのトラッキングID
   * @example G-XXXXXXXXXX
   */
  gaId: string,
  /**
   * Google Analytics の設定オプション
   * キーは camelCase 形式で指定し、内部で snake_case に変換されます。
   * @example { sendPageView: false, customParam: 'value' }
   */
  options: Record<string, string | number | boolean>
}

const OriginalGoogleAnalytics = ({ gaId, options }: Props) => {

  const snakeCaseOptions = useMemo(() => convertKeysToSnakeCase(options), [options]);

  return (
    <>
      <Script
        src={`https://www.googletagmanager.com/gtag/js?id=${gaId}`}
        strategy="afterInteractive"
      />
      <Script
        id="ga-init"
        strategy="afterInteractive"
      >
        {`
          window.dataLayer = window.dataLayer || [];
          function gtag(){window.dataLayer.push(arguments);}
          gtag('js', new Date());
          gtag('config', '${gaId}', ${JSON.stringify(snakeCaseOptions)});
        `}
      </Script>
    </>
  );
}

export default OriginalGoogleAnalytics;

const toSnakeCase = (str: string) => str.replace(/([A-Z])/g, '_$1').toLowerCase();

const convertKeysToSnakeCase = (obj: Record<string, string | number | boolean>) => {
  return Object.entries(obj).reduce((acc, [key, value]) => {
    acc[toSnakeCase(key)] = value;
    return acc;
  }, {} as Record<string, string | number | boolean>);
}

Discussion