使用 Google Analytics 对单页应用(WebApp)进行数据统计

这是一篇迟到很久的文章,自从去年5月份开始,我就一直在折腾 GA 了,到现在大半年也过去了,当作一篇小结吧。

都知道数据统计对产品至关重要,精益创业中也将开发-认知-测量作为一个非常重要的产品流程

先不提很多产品经理们糟糕的数据意识,国内的网站数据统计真是一个比一个糟糕,最糟糕的是它们都不支持这两年很火的SPA(如有可以指出)。所以本文将会关于如何使用 Google Analytics 对 SPA 进行传统的 PV、UV 等统计进行介绍,由于我一直使用的 MVVM 框架是 Angular.js,所以下面的代码都是基于 Angular + UI-router 的,其他框架应该也是大同小异。

1. 初始化

SPA 中 GA 的初始化与传统多页应用并没有什么区别,也就是在框架页面中插入跟踪代码,GA 的代码早就改成异步加载的了,所以放在页面头部或者底部都没有什么关系,官方推荐是放在头部,不仅可以提早加载时间,也可以通过这段代码进行Search Console的认证(说的这里要吐槽一下百度统计,非异步也就算了,最近还特别卡,上很多网站都会阻塞掉)。这段代码无非就是在文档里插入了一个异步加载的 script 标签,似乎这段代码的历史可以追溯到旧版 GA 时期,当时 GA 还是同步加载的,于是有个小伙写了一段异步加载 GA 的代码,最终似乎被 Google 给吸收了。当然以上是我意淫的,具体可以见这里 Optimizing the asynchronous Google Analytics snippet

<script>  
  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
  })(window,document,'script','//www.google-analytics.com/analytics.js','ga');

  ga('create', 'UA-xxxxxx-1', 'auto');
  // 注意下面这行要删除或注释掉,否则数据会不准
  // ga('send', 'pageview');

</script>  

2.统计PV

我们知道单页应用实际只加载一个HTML文件,跳转是通过监听 hashchange 或者 pushstate 来完成的,因此传统的页面加载统计完全无法统计到用户在 SPA 中的跳转。

所以我们需要在代码中手动添加跳转时发送 PV 的代码。

创建一个app.analytics.js,内容如下

angular.module('TestApp')  
  .run(PVHandler);

function PVHandler($rootScope, $location, $timeout) {  
  $rootScope.$on('$stateChangeSuccess', function() {
    $timeout(function () {
      ga && ga('send', 'pageview', {
        page: $location.url(), // 手动设置 path
        title: document.title // 也可以手动设置页面标题
      });
    }, 0, false);
  });
}

这里需要注意两点,

第一:发送 PV 要在页面完全加载完之后,所以需要一个 timeout 保证页面加载完;

第二:要手动指定当前 URL,也就是 page 这个字段,否则没有使用 HTML5Mode 的话,统计中的路径将会错误,会影响到行为分析等。

访问一下,应该就能在 实时 页面中看到效果了,页面的地址也显示正常

小结:

那么到这里,GA 在 SPA 中的基础用法已经讲完了。

单页应用与多页应用在统计中最大的不同就是需要 手动发送 PV 并修改路径,也不需要在框架初始化时发送 PV,这需要有 API 支持才能做到,国内的统计像百度、CNZZ、TA等都没有提供相应的 API,友盟应该有但是不太适合用在 WebApp 上所以就没有试。

下一篇文章会将介绍更多高级的用法。

以上。

参考资料:

单页应用跟踪 - Google Analytics


补充 Vue 的跟踪代码:以下代码一般在 router.js 中

router.afterEach(({to}) => {  
  setTimeout(() => {
    try {
      ga('send', 'pageview', to.path)
    } catch (err) {
      console.error(new ReferenceError('ga initialize error'))
    }
  }, 100)
})