Google アナリティクス 4 を使用

このチュートリアルでは、Google アナリティクスを使用して拡張機能の使用状況をトラッキングする方法について説明します。GitHub で実用的な Google アナリティクス 4 サンプルを入手できます。ここで google-analytics.js には Google アナリティクス関連のコードがすべて含まれています。

要件

このチュートリアルは、Chrome 拡張機能の記述に精通していることを前提としています。拡張機能の記述方法については、スタートガイド チュートリアルをご覧ください。

拡張機能をトラッキングするには、Google アナリティクス 4 アカウントも設定する必要があります。拡張機能には独自の URL がないため、アカウントの設定時に [ウェブサイトの URL] フィールドの任意の値を使用できます。

Google アナリティクスの Measurement Protocol を使用する

Manifest V3 以降、Chrome 拡張機能ではリモートでホストされるコードを実行できません。つまり、拡張機能イベントのトラッキングには Google アナリティクスの Measurement Protocol を使用する必要があります。Measurement Protocol を使用すると、HTTP リクエストを介して Google アナリティクスのサーバーに直接イベントを送信できます。このアプローチの利点は、Service Worker を含め、拡張機能のどこからでも分析イベントを送信できることです。

API 認証情報を設定する

まず、api_secretmeasurement_id を取得します。アナリティクス アカウントでこれらを取得する方法については、Measurement Protocol に関するドキュメントをご覧ください。

client_id を生成する

2 つ目のステップでは、特定のデバイス/ユーザーの一意の識別子である client_id を生成します。ユーザーのブラウザに拡張機能がインストールされている限り、ID は同じである必要があります。任意の文字列を指定できますが、クライアントに対して一意である必要があります。URL を生成するには、self.crypto.randomUUID() を呼び出します。client_idchrome.storage.local に保存し、拡張機能がインストールされている間同じままになるようにします。

chrome.storage.local を使用するには、マニフェスト ファイルで storage 権限が必要です。

manifest.json:

{
  …
  "permissions": ["storage"],
  …
}

次に、chrome.storage.local を使用して client_id を保存します。

async function getOrCreateClientId() {
  const result = await chrome.storage.local.get('clientId');
  let clientId = result.clientId;
  if (!clientId) {
    // Generate a unique client ID, the actual value is not relevant
    clientId = self.crypto.randomUUID();
    await chrome.storage.local.set({clientId});
  }
  return clientId;
}

アナリティクス イベントを送信する

API の認証情報と client_id を使用すると、fetch リクエストを使って Google アナリティクスにイベントを送信できます。

const GA_ENDPOINT = 'https://www.google-analytics.com/mp/collect';
const MEASUREMENT_ID = `G-...`;
const API_SECRET = `...`;

fetch(
  `${GA_ENDPOINT}?measurement_id=${MEASUREMENT_ID}&api_secret=${API_SECRET}`,
  {
    method: 'POST',
    body: JSON.stringify({
      client_id: await getOrCreateClientId(),
      events: [
        {
          name: 'button_clicked',
          params: {
            id: 'my-button',
          },
        },
      ],
    }),
  }
);

これにより button_clicked イベントが送信され、Google アナリティクスのイベント レポートに表示されます。Google アナリティクスのリアルタイム レポートにイベントを表示するには、session_idengagement_time_msec の 2 つのパラメータを追加で指定する必要があります。

推奨パラメータ session_idengagement_time_msec を使用する

session_idengagement_time_msec はどちらも、リアルタイムなどの標準レポートにユーザー アクティビティを表示するために必要なため、Google アナリティクスの Measurement Protocol を使用する際に推奨されるパラメータです。

session_id は、ユーザーが拡張機能と継続的にやり取りする期間を表します。デフォルトでは、30 分間操作がなければセッションは終了します。セッションの継続時間に制限はありません。

Chrome 拡張機能では、通常のウェブサイトとは異なり、ユーザー セッションを明確に表す概念はありません。そのため、拡張機能でユーザー セッションの意味を定義する必要があります。たとえば、新しいユーザー操作はすべて新しいセッションとしてカウントされ、その場合は、新しいセッション ID をイベントごとに生成するだけです(タイムスタンプを使用します)。

次の例は、イベントが報告されない 30 分が経過すると新しいセッションがタイムアウトするアプローチを示しています(この時間は拡張機能のユーザーの行動に応じてカスタマイズできます)。この例では、chrome.storage.session を使用して、ブラウザの実行中にアクティブなセッションを保存します。イベントが最後に発生した時刻をセッションとともに保存します。これにより、アクティブなセッションの有効期限が切れているかどうかを判断できます。

const SESSION_EXPIRATION_IN_MIN = 30;

async function getOrCreateSessionId() {
  // Store session in memory storage
  let {sessionData} = await chrome.storage.session.get('sessionData');
  // Check if session exists and is still valid
  const currentTimeInMs = Date.now();
  if (sessionData && sessionData.timestamp) {
    // Calculate how long ago the session was last updated
    const durationInMin = (currentTimeInMs - sessionData.timestamp) / 60000;
    // Check if last update lays past the session expiration threshold
    if (durationInMin > SESSION_EXPIRATION_IN_MIN) {
      // Delete old session id to start a new session
      sessionData = null;
    } else {
      // Update timestamp to keep session alive
      sessionData.timestamp = currentTimeInMs;
      await chrome.storage.session.set({sessionData});
    }
  }
  if (!sessionData) {
    // Create and store a new session
    sessionData = {
      session_id: currentTimeInMs.toString(),
      timestamp: currentTimeInMs.toString(),
    };
    await chrome.storage.session.set({sessionData});
  }
  return sessionData.session_id;
}

次の例では、session_idengagement_time_msec を前のボタンクリック イベント リクエストに追加します。engagement_time_msec には、デフォルト値の 100 ms を指定できます。

const GA_ENDPOINT = "https://www.google-analytics.com/mp/collect";
const MEASUREMENT_ID = `G-...`;
const API_SECRET = `...`;
const DEFAULT_ENGAGEMENT_TIME_IN_MSEC = 100;

fetch(
`${GA_ENDPOINT}?measurement_id=${MEASUREMENT_ID}&api_secret=${API_SECRET}`,
  {
    method: "POST",
    body: JSON.stringify({
      client_id: await getOrCreateClientId(),
      events: [
        {
          name: "button_clicked",
          params: {
            session_id: await this.getOrCreateSessionId(),
            engagement_time_msec: DEFAULT_ENGAGEMENT_TIME_IN_MSEC,
            id: "my-button",
          },
        },
      ],
    }),
  }
);

Google アナリティクスのリアルタイム レポートでは、イベントは次のように表示されます。

Google アナリティクスのリアルタイム イベント

ポップアップ ページ、サイドパネル ページ、拡張機能ページでページビューをトラッキングする

Google アナリティクスの Measurement Protocol では、ページビューをトラッキングするための特別な page_view イベントがサポートされています。ポップアップ ページ、サイドパネル、新しいタブで拡張機能ページにアクセスしたユーザーをトラッキングするときに使用します。page_view イベントには、page_title パラメータと page_location パラメータも必要です。次の例では、拡張機能のポップアップについて、ドキュメントの load イベントでページビュー イベントを発生させます。

popup.js:

window.addEventListener("load", async () => {
  fetch(`${GA_ENDPOINT}?measurement_id=${MEASUREMENT_ID}&api_secret=${API_SECRET}`,
  {
    method: "POST",
    body: JSON.stringify({
      client_id: await getOrCreateClientId(),
      events: [
        {
          name: "page_view",
          params: {
            session_id: await getOrCreateSessionId(),
            engagement_time_msec: DEFAULT_ENGAGEMENT_TIME_IN_MSEC,
            page_title: document.title,
            page_location: document.location.href
          },
        },
      ],
    }),
  });
});

popup.js スクリプトは、ポップアップの html ファイルにインポートし、他のスクリプトの前に実行する必要があります。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Analytics Demo Popup</title>
    <script src="./popup.js" type="module"></script>
  </head>
  <body>
    <h1>Analytics Demo</h1>
  </body>
</html>

ポップアップ ビューは、Google アナリティクスのリアルタイム レポートの他のページビューと同様に表示されます。

Google アナリティクスのリアルタイム ダッシュボードに表示されているページビュー イベント。

Service Worker での分析イベントのトラッキング

Google アナリティクスの Measurement Protocol を使用すると、拡張機能 Service Worker で分析イベントを追跡できます。たとえば、Service Worker で unhandledrejection event をリッスンすることで、Service Worker でキャッチされなかった例外を Google アナリティクスに記録できます。これは、ユーザーから報告された問題のデバッグに大いに役立ちます。

service-worker.js:

addEventListener("unhandledrejection", async (event) => {
  `${GA_ENDPOINT}?measurement_id=${MEASUREMENT_ID}&api_secret=${API_SECRET}`,
  {
    method: "POST",
    body: JSON.stringify({
      client_id: getOrCreateClientId(),
      events: [
        {
          // Note: 'error' is a reserved event name and cannot be used
          // see https://developers.google.com/analytics/devguides/collection/protocol/ga4/reference?client_type=gtag#reserved_names
          name: "extension_error",
          params: {
            session_id: await this.getOrCreateSessionId(),
            engagement_time_msec: DEFAULT_ENGAGEMENT_TIME_IN_MSEC,
            message: error.message,
            stack: error.stack,
          },
        },
      ],
    }),
  }
});

Google アナリティクスのレポートにエラーイベントが表示されるようになりました。

Google アナリティクス イベント ダッシュボードに表示されているエラーイベント。

デバッグ

Google アナリティクスには、アナリティクス イベントを拡張機能にデバッグする際に役立つ 2 つの機能があります。

  1. 特別なデバッグ エンドポイント https://www.google-analytics.com**/debug**/mp/collect: イベント定義のエラーを報告します。
  2. Google アナリティクスのリアルタイム レポート: 発生したイベントを表示します。