衡量离线使用情况

如何跟踪网站的离线使用情况,以便了解您的网站为何需要更好的离线体验。

Stephan Giesau
Stephan Giesau
Martin Schierle
Martin Schierle

本文介绍了如何跟踪网站的离线使用情况,以便您证明自己的网站需要更好的离线模式。此外,还说明了实现离线使用情况分析时应避免的陷阱和问题。

在线和离线浏览器事件的误区

用于跟踪离线使用情况的显而易见解决方案是为 onlineoffline 事件(许多浏览器支持)创建事件监听器,并将分析跟踪逻辑放入这些监听器中。遗憾的是,这种方法存在一些问题和限制:

  • 一般来说,跟踪每项网络连接状态事件可能过于繁琐,在以隐私保护为中心的世界中,应尽可能少收集数据,因此这不利于应用。此外,onlineoffline 事件可能会在网络丢失的一秒内触发,用户可能根本看不到或注意到这一点。
  • 离线活动的分析跟踪数据永远不会到达分析服务器,因为用户处于离线状态。
  • 在用户离线时在本地跟踪时间戳,并在用户重新上线时将离线活动发送到 Google Analytics 服务器,这取决于用户是否会再次访问您的网站。如果用户因缺少离线模式而离开您的网站,并且从未回访,您将无法跟踪这一情况。能够跟踪离线流失情况是证明您的网站需要更好的离线模式的重要数据。
  • online 事件的可靠性不高,因为它仅知道网络访问,而不知道互联网访问。因此,用户可能仍处于离线状态,并且发送跟踪 ping 仍可能失败。
  • 即使用户在离线状态下仍留在当前网页上,系统也不会跟踪任何其他 Google Analytics 事件(例如滚动事件、点击等),而这些事件可能更相关、更实用。
  • 一般来说,离线本身也并不太有意义。作为网站开发者,了解哪些类型的资源未能加载可能更重要。这在 SPA 中尤其重要。在 SPA 中,网络连接断开可能不会导致浏览器离线错误页面(用户能理解),但更有可能导致页面的随机动态部分静默失败。

您仍然可以使用此解决方案来基本了解线下使用情况,但需要仔细考虑其众多缺点和限制。

更好的方法:Service Worker

启用离线模式的解决方案最终被证明是跟踪离线使用情况的更好解决方案。基本思路是,只要用户处于离线状态,就将 Google Analytics ping 存储到 IndexedDB 中,并在用户重新上线时重新发送。对于 Google Analytics,此功能已通过 Workbox 模块作为现成的提供,但请注意,如果发送的命中延迟了 4 小时以上,则可能无法处理。最简单的形式是,您可以通过以下两行代码在基于 Workbox 的服务 worker 中启用它:

import * as googleAnalytics from 'workbox-google-analytics';

googleAnalytics.initialize();

这样一来,系统就会在离线状态下跟踪所有现有事件和网页浏览 ping,但您不会知道这些事件是在离线状态下发生的(因为它们只是按原样重放)。为此,您可以使用 Workbox 操控跟踪请求,方法是使用自定义维度(以下代码示例中的 cd1)向 Google Analytics ping 添加 offline 标志:

import * as googleAnalytics from 'workbox-google-analytics';

googleAnalytics.initialize({
  parameterOverrides: {
    cd1: 'offline',
  },
});

如果用户在互联网连接恢复之前因处于离线状态而离开了页面,该怎么办?尽管这通常会使 Service Worker 进入休眠状态(因为它无法在连接恢复时发送数据),但 Workbox Google Analytics 模块使用 Background Sync API,该 API 稍后在连接恢复时发送分析数据,即使用户关闭标签页或浏览器也是如此。

但仍有缺点:虽然这让现有跟踪功能支持离线模式,但在您实现基本离线模式之前,您很可能不会看到太多相关数据。即使连接中断,用户仍会快速离开您的网站。不过,现在您至少可以通过比较应用了线下维度的用户与常规用户的平均会话时长和用户互动情况,来衡量和量化这一点。

SPA 和延迟加载

如果访问以多页网站形式构建的网页的用户离线并尝试浏览,浏览器的默认离线页面会显示,帮助用户了解所发生的情况。不过,以单页应用构建的页面的工作方式有所不同。用户会留在同一页面上,而新内容会通过 AJAX 动态加载,无需任何浏览器导航。用户在离线状态下不会看到浏览器错误页面相反,网页的动态部分会出现错误、进入未定义状态,或者停止动态呈现。

由于延迟加载,多页网站中也可能会出现类似情况。例如,初始加载可能在线下发生,但用户在滚动之前就已离线。折叠线下方的所有延迟加载内容都将静默失败并缺失。

由于这些情况会给用户带来极大的不便,因此有必要对其进行跟踪。服务工作线程是捕获网络错误的理想位置,最终可使用分析来跟踪这些错误。借助 Workbox,您可以配置全局捕获处理脚本,以便通过发送消息事件告知网页请求失败:

import { setCatchHandler } from 'workbox-routing';

setCatchHandler(({ event }) => {
  // https://developer.mozilla.org/docs/Web/API/Client/postMessage
  event.waitUntil(async function () {
    // Exit early if we don't have access to the client.
    // Eg, if it's cross-origin.
    if (!event.clientId) return;

    // Get the client.
    const client = await clients.get(event.clientId);
    // Exit early if we don't get the client.
    // Eg, if it closed.
    if (!client) return;

    // Send a message to the client.
    client.postMessage({
      action: "network_fail",
      url: event.request.url,
      destination: event.request.destination
    });

    return Response.error();

  }());
});

另一种方法是仅捕获特定路由上的错误,而不是监听所有失败的请求。例如,如果我们只想报告发生在指向 /products/* 的路线上的错误,则可以在 setCatchHandler 中添加一个检查,以使用正则表达式过滤 URI。更简洁的解决方案是使用自定义处理程序实现 registerRoute。这样可以将业务逻辑封装到单独的路线中,从而在更复杂的服务工作线程中提高可维护性:

import { registerRoute } from 'workbox-routing';
import { NetworkOnly } from 'workbox-strategies';

const networkOnly = new NetworkOnly();
registerRoute(
  new RegExp('https:\/\/example\.com\/products\/.+'),
  async (params) => {
    try {
      // Attempt a network request.
      return await networkOnly.handle(params);
    } catch (error) {
      // If it fails, report the error.
      const event = params.event;
      if (!event.clientId) return;
      const client = await clients.get(event.clientId);
      if (!client) return;

      client.postMessage({
        action: "network_fail",
        url: event.request.url,
        destination: "products"
      });

      return Response.error();
    }
  }
);

最后一步是,网页需要监听 message 事件并发送 Google Analytics ping。再次提醒,请务必在服务工作器中缓冲离线发生的分析请求。如前所述,初始化 workbox-google-analytics 插件以实现内置 Google Analytics 支持。

以下示例使用 Google Analytics,但同样适用于其他分析服务提供商。

if ("serviceWorker" in navigator) {
  // ... SW registration here

  // track offline error events
  navigator.serviceWorker.addEventListener("message", event => {
    if (gtag && event.data && event.data.action === "network_fail") {
      gtag("event", "network_fail", {
        event_category: event.data.destination,
        // event_label: event.data.url,
        // value: event.data.value
      });
    }
  });
}

这将在 Google Analytics 中跟踪资源加载失败情况,您可以在 Google Analytics 中使用报告对其进行分析。通常,派生的分析洞见可用于改进服务工作器缓存和错误处理,以便在网络状况不稳定的情况下使网页更稳健、更可靠。

后续步骤

本文介绍了跟踪线下使用情况的不同方法及其优缺点。 虽然这有助于量化有多少用户离线并因此而遇到问题,但这只是一个开始。只要您的网站未提供完善的离线模式,您在 Google Analytics 中就肯定不会看到太多的离线使用情况。

我们建议您先完成完整的跟踪设置,然后再逐步扩展线下功能,同时关注跟踪数据。首先,从简单的离线错误页面开始(使用 Workbox 很容易实现);无论如何,这都应被视为与自定义 404 页面类似的用户体验最佳实践。然后,尝试实现更高级的离线回退,最后实现真正的离线内容。请务必向用户明确进行广告宣传和说明,您会发现使用率会越来越高。毕竟,每个人都会偶尔离线。

如需了解如何说服跨职能利益相关方在您的网站上投入更多资源,请参阅如何报告指标并打造卓越成效文化跨职能团队共同解决网站速度问题。虽然这些帖子侧重于效果,但应该能帮助您大致了解如何吸引利益相关方。

主打照片由 Unsplash 用户 JC Gellidon 拍摄。