記事一覧
Topに戻る
  • TOP
  • Next.js
  • Next.jsでGoogle Analyticsを使えるようにする

Next.jsでGoogle Analyticsを使えるようにする

更新日:

by @Panda_Program

目次

Next.jsでGoogle Analyticsを使えるようにする

Next.jsとはVercelが作成しているReactのフレームワークです。面倒な設定を書かなくてもすぐに使えるZero Configを標榜しており、実際にwebpackやTypeScriptと一緒にReactを書く際にも特別な準備は不要です。SSRにも対応しており、Reactで開発するならNext.jsかFacebook製のCreate React Appを使うのがスタンダードになってます。

私は実務でNext.jsを使っており、このフレームワークはとても便利だと思っています。私はNext.jsの大ファンなので、Reactでの開発時にNext.jsを使う現場が増えるといいなと思って記事を書いています。

関連記事: Next.js + esa.io + VercelでJAMStackな爆速ブログを構築する

この記事では、Next.jsでReactアプリケーションを作成する時に、Google Analytics(以下、GA)の設定をする方法をご紹介します。一通り設定した後、TypeScript化していきます。

基本的にはNext.jsのExampleを参考にしています。ただ、実務で使うとこれだけでは足りないところがあるので、記事内では実務への橋渡しとなるような内容を盛り込んでいます。

なお、Google Analyticsのアカウント取得方法やスニペットの取得方法は記載していません。

Google AnalyticsのIDを.envに記述する

まず、ルートディレクトリに.envファイルを作成し、GAのIDを.envに記述します。

.env
NEXT_PUBLIC_GOOGLE_ANALYTICS_ID=UA-SOME_ANALYTICS_ID-1

Next.jsでは、.envに記述した環境変数をprocess.env.NEXT_PUBLIC_GOOGLE_ANALYTICS_IDで取得できます。この値はビルド時に注入されます。これが最初の設定です。

NEXT_PUBLIC_という接頭辞をつけると、ブラウザにも露出する値になります。

GAイベントを発火させる関数を作成する

次に、GAイベントを発火させる関数を作成します。関数はsrc/lib/gtag.jsというファイルに記述していきます。

src/lib/gtag.js
export const GA_ID = process.env.NEXT_PUBLIC_GOOGLE_ANALYTICS_ID

// IDが取得できない場合を想定する
export const existsGaId = GA_ID !== ''

// PVを測定する
export const pageview = (path) => {
  window.gtag('config', GA_ID, {
    page_path: path,
  })
}

// GAイベントを発火させる
export const event = ({action, category, label, value = ''}) => {
  if (!existsGaId) {
    return
  }

  window.gtag('event', action, {
    event_category: category,
    event_label: JSON.stringify(label)
    value,
  })
}

このファイルではgtagというGAのメソッドをラップする関数を作ります。

pageviewという関数でページビューを送信するには、configコマンドを使用します。引数でパスを受け取り、page_pathでURLのパスを送信します。

eventという関数でGAイベントを送信する関数を記述します。例えば、DOMのクリックイベントやSubmitのイベントなどを取得する時に使います。

なお、GAに関する詳しい内容はGoogleの公式ドキュメントをご覧ください。

_document.jsxにGAのスクリプトを書き込む

_document.jsxは全てのページで共通のHTMLを書くコンポーネントです。この_document.jsxにGA用のscriptタグを記述します。

pages/document.jsx
import Document, { Head, Main, NextScript } from 'next/document'
import { existsGaId, GA_ID } from '~/src/lib/gtag'

export default class MyDocument extends Document {
  render() {
    return (
      <html lang="ja">
        <Head>
          {/* Google Analytics */}
          {existsGaId && (
            <>
              <script async src={`https://www.googletagmanager.com/gtag/js?id=${GA_ID}`} />
              <script
                dangerouslySetInnerHTML={{
                  __html: `
                  window.dataLayer = window.dataLayer || [];
                  function gtag(){dataLayer.push(arguments);}
                  gtag('js', new Date());
                  gtag('config', '${GA_ID}', {
                    page_path: window.location.pathname,
                  });`,
                }}
              />
            </>
          )}
        </Head>
        <body>
          <Main />
          <NextScript />
        </body>
      </html>
    )
  }
}

なお、_document.jsxはサイト内で共通のmetaタグ(<meta property="og:type" content="website" />など)を記述するような使い方をします。

_app.jsにPVをカウントするイベントを記述する

Next.js製のサイトはSPAであるため、ページを遷移するときにJavaScriptでURLを書き換えます。その際、Google Analyticsはアクセスした最初のページしかページビュー測定のイベントを送信しません。つまり、ユーザーがサイト内を回遊したときの各ページのPVを測定できないのです。

この問題は、Next.jsのRouterを使えば解決できます。RouterのURL書き換えが完了した時に発火するrouteChangeCompleteイベントのコールバックとしてpageview関数を設定します。

これをpages/_app.jsに記述します。

pages/_app.js
import React from 'react'

import * as gtag from '~/src/lib/gtag'

const App = ({ Component, pageProps }) => {
  useEffect(() => {
    if (!gtag.existsGaId) {
      return
    }

    const handleRouteChange = (path) => {
      gtag.pageview(path)
    }

    router.events.on('routeChangeComplete', handleRouteChange)
    return () => {
      router.events.off('routeChangeComplete', handleRouteChange)
    }
  }, [router.events])

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

これで、ページ遷移時のPVイベントをGAに送信できました。

_app.jsの記述は長くなりがちなので、Custom Hooks に切り出しておくと便利です。

src/hooks/usePageView.js
import { useEffect } from 'react'
import { useRouter } from 'next/router'

import * as gtag from '~/src/lib/gtag'

export default function usePageView() {
  useEffect(() => {
    if (!gtag.existsGaId) {
      return
    }

    const handleRouteChange = (path) => {
      gtag.pageview(path)
    }

    router.events.on('routeChangeComplete', handleRouteChange)
    return () => {
      router.events.off('routeChangeComplete', handleRouteChange)
    }
  }, [router.events])
}

_app.jsは以下のようにリファクタリングできます。

pages/_app.js
import React from 'react'

import * as gtag from '~/src/lib/gtag'
import usePageView from '~/src/hooks/usePageView'

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

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

GAイベントをReactコンポーネントに設定する

では、実際にReactコンポーネントでGAイベントの設定をしましょう。以下ではContactコンポーネントでのボタンをクリックした時に、inputタグに入力されたメッセージをGAに送信します。

Contact.jsx
import React from 'react'
import Layout from '../components/Layout'

import * as gtag from '../lib/gtag'

const Contact = () => {
  const [message, setMessage] = React.useState('')

  const handleInput = e => setMessage(e.target.value)
  const handleSubmit = e => {
    e.preventDefault()

    gtag.event({
      action: 'submit_form',
      category: 'Contact',
      label: message,
    })

    setMessage('')
  }

  return (
    <Layout>
      <h1>This is the Contact page</h1>
      <form onSubmit={handleSubmit}>
        <label>
          <span>Message:</span>
          <textarea onChange={handleInput} value={message} />
        </label>
        <button type="submit">submit</button>
      </form>
    </Layout>
  )
}

export default Contact

今回はhandleSubmitの中でeventを発火しています。同様にclickイベントならhandleClickの中に、onChangeイベントならhandleChangeの中にevent`関数を記述します。Reactでは取得したいイベントに応じて、GAイベントを柔軟に記述できます。

ここまででNext.jsでGoogle Analyticsを使うための設定ができました。以下では、より実務に即した内容をご紹介します。

TypeScript対応をする

実務ではReactとTypeScriptの環境で開発している方も多いと思います。そのような方のために、Next.js + Google Analytics + TypeScriptの対応方法をご紹介します。

なお、GAに関するメソッドのために@types/google.analyticsという型定義があります。しかし、型定義ではgaというメソッドにしか対応しておらず、gtagという書き方は存在しないのです。

そこで、このライブラリを参照しながらTS用の対応をすることにしました。

windowからGAイベントのプロパティを使うための型定義を書く

Next.jsでTypeScriptを使えるようにすると、ルートディレクトリにnext-env.d.tsというファイルが作成されます。これはNext.jsでTSを使うなら必須のファイルで、削除してはいけません。

前の章lib/gtag.jswindow.gtag()をラップする関数を作りましたね。

gtag.jsgtag.tsに書き換えると、windowオブジェクトにgtagというプロパティは存在しないという意味のエラーが表示されます。

TS2339: Property 'gtag' does not exist on type 'Window'.

TypeScriptでwindowにプロパティを追加するために、next-env.d.tsにWindowオブジェクトはgtagというプロパティを持っているのだという型定義を記述しましょう。

next-env.d.ts
interface Window {
  // pageviewのため
  gtag(type: 'config', googleAnalyticsId: string, { page_path: string })
  // eventのため
  gtag(
    type: 'event',
    eventAction: string,
    fieldObject: {
      event_label: string
      event_category: string
      value?: string
    }
  )
}

これでgtag.tsでエラーが出なくなりました。

発火させるイベントを型で管理する

TypeScriptに対応したため、gtagをラップする関数に型をつけていきます。

まず、gtag.jsの拡張子をgtag.tsに変更します。そして、1行目の import 文を加えます。

src/lib/gtag.ts
import { Event } from 'src/types/googleAnalytics/event'

export const event = ({action, category, label}: Event) => {
  if (!existsGaId) {
    return
  }

  window.gtag('event', action, {
    event_category: category,
    event_label: JSON.stringify(label)
  })
}

この時点では、src/types/googleAnalytics/event.tsを作成していないため、型Eventをインポートできずエラーになります。

そこで、src/types/googleAnalytics/event.tsを作成し、以下のように記述します。

src/types/googleAnalytics/event.ts
type ContactEvent = {
  action: 'submit_form'
  category: 'contact'
  label: string
}

type ClickEvent = {
  action: 'click'
  category: 'other'
  label: string
}

export type Event = ContactEvent | ClickEvent

event.tsでGAイベントで送信する値に予め型をつけることにより、イベント設定時のスペルミスや値がundefinedになるミスを未然に防ぐことができます。

こうすることでEvent.jsがサイト全体のGAイベントのドキュメント代わりになります。

しかも、イベント名等のタイポにより GA イベントが発火しないミスを未然に防ぐこともできます。

まとめ

Next.jsでGoogle Analyticsを使えるようにした上で、TypeScriptに対応しました。

Next.jsを本番環境で使用する場合、Google Analyticsは必須です。Google Analyticsを使ってユーザー行動を取得し、プロダクトの改善にぜひ役立ててください。

日本でNext.jsが現場で使われるケースが増えることを願っています。

Happy Coding 🎉