使用 Google Analytics(分析)4

本教程演示了如何使用 Google Analytics 跟踪扩展程序的用量。您可以在 Github 上找到可正常运行的 Google Analytics 4 示例,其中 google-analytics.js 包含所有与 Google Analytics 相关的代码。

要求

本教程假定您熟悉如何编写 Chrome 扩展程序。如果您需要有关如何编写扩展程序的信息,请阅读入门教程

您还必须设置 Google Analytics 4 账号,才能跟踪扩展服务。请注意,在设置账号时,您可以在“网站的网址”字段中使用任意值,因为扩展程序本身没有网址。

使用 Google Analytics Measurement Protocol

自 Manifest V3 起,Chrome 扩展程序不得执行远程托管的代码。这意味着您必须使用 Google Analytics Measurement Protocol 来跟踪扩展程序事件。借助 Measurement Protocol,您可以通过 HTTP 请求直接将事件发送到 Google Analytics 服务器。这种方法的好处在于,您可以从扩展程序的任何位置(包括服务工作线程)发送分析事件。

设置 API 凭据

第一步是获取 api_secretmeasurement_id。请参阅 Measurement Protocol 文档,了解如何为您的 Google Analytics 账号获取这些信息。

生成 client_id

第二步是为特定设备/用户生成唯一标识符 client_id。只要扩展程序安装在用户的浏览器中,该 ID 就应保持不变。它可以是任意字符串,但对于客户端而言应该是唯一的。将 client_id 存储在 chrome.storage.local 中,以确保只要扩展程序已安装,该值就保持不变。

使用 chrome.storage.local 需要在清单文件中添加 storage 权限:

manifest.json:

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

然后,您可以使用 chrome.storage.local 存储 client_id

function getRandomId() {
  const digits = '123456789'.split('');
  let result = '';

  for (let i = 0; i < 10; i++) {
    result += digits[Math.floor(Math.random() * 9)];
  }

  return result;
}

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. We use
    // the <number>.<number> format since this is typical for GA client IDs.
    const unixTimestampSeconds = Math.floor(new Date().getTime() / 1000);
    clientId = `${this.getRandomId()}.${unixTimestampSeconds}`;
    await chrome.storage.local.set({clientId});
  }
  return clientId;
}

发送分析事件

借助 API 凭据和 client_id,您可以通过 fetch 请求向 Google Analytics 发送事件:

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 Analytics 事件报告中。如果您想在 Google Analytics 实时报告中查看事件,则需要提供两个额外的参数:session_idengagement_time_msec

使用推荐参数 session_idengagement_time_msec

session_idengagement_time_msec 都是使用 Google Analytics 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 Analytics 实时报告中会显示如下。

Google Analytics 中的实时事件。

跟踪弹出式窗口、侧边栏和扩展程序页面中的网页浏览

Google Analytics Measurement Protocol 支持一种特殊的 page_view 事件,用于跟踪网页浏览。使用此功能可跟踪用户在新标签页中访问弹出式页面、侧边栏或扩展程序页面的情况。page_view 事件还需要 page_titlepage_location 参数。以下示例在扩展程序弹出式窗口的 document 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
          },
        },
      ],
    }),
  });
});

需要在弹出式窗口的 HTML 文件中导入 popup.js 脚本,并且该脚本应在执行任何其他脚本之前运行:

<!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 Analytics 实时报告中的任何其他网页浏览一样显示:

网页浏览事件在 Google Analytics 实时信息中心内的显示方式。

在 Service Worker 中跟踪分析事件

使用 Google Analytics Measurement Protocol 可以在扩展程序服务工作线程中跟踪分析事件。例如,通过监听服务工作线程中的 unhandledrejection event,您可以将服务工作线程中的任何未捕获的异常记录到 Google Analytics 中,这有助于调试用户可能会报告的问题。

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 Analytics 报告中看到错误事件:

错误事件,如 Google Analytics 事件信息中心内所示。

调试

Google Analytics 提供了两项实用功能,可用于调试扩展程序中的分析事件:

  1. 一个特殊的调试端点 https://www.google-analytics.com**/debug**/mp/collect,用于报告事件定义中的任何错误。
  2. Google Analytics 实时报告,用于显示传入的事件。