怎样统计用户在当前页面停留的时间

页面停留时间(Time on Page)简称 Tp,是网站分析中很常见的一个指标,用于反映用户在某些页面上停留时间的长短,传统的Tp统计方法会存在一定的统计盲区,比如无法监控单页应用,没有考虑用户切换Tab、最小化窗口等操作场景。基于上述背景,重新调研和实现了精确统计页面停留时长的方案,需要 兼容单页应用和多页应用,并且不耦合或入侵业务代码。

虽然百度统计之类的也可以记录用户的浏览行为,但是这类统计是全部跟踪用户,而无法精确的跟踪到注册的用户之前一系列的行为,而我们只需要针对注册用户进行有目的性的行为分析。。。

针对哪些应用?

  • 多页面应用
  • 单页面应用(本文以vue为例子)

对于单页应用内部的跳转可以转化为两个问题:

  • 监听路由变化
  • 判断变化的URL是否为不同页面 。

首先确定一下需求:

  • 用户一进来,记录用户进入页面的开始时间;
  • 用户在新的标签页打开页面,如果其他标签页已经打开了页面,这时候的开始时间还是算第一次进入的页面的时间;
  • 用户关闭该网页的全部标签页时,需要记录关闭的结束时间,调用接口传数据给后台;

如何监听页面的进入和离开

对于常规页面的 首次加载、页面关闭、刷新 等操作都可以通过 window.onload 和window.onbeforeunload 事件来监听页面进入和离开,浏览器前进后退可以通过 pageshow 和 pagehide 处理。

  • load / beforeunload
  • pageshow / pagehide

首先,进入页面的时候,浏览器会调用onload事件,浏览器关闭时,浏览器会调用beforeunload事件,可以从这两个事件入手。

但是这里有几个问题,那就是浏览器刷新的时候,也会调用beforeunload,还有就是如何知道用户在其它标签页也打开了网页呢?

有什么可以记录浏览器是否刷新呢?这时候我想到了sessionStorage。

sessionStorage,用于临时保存同一窗口(或标签页)的数据,在关闭窗口或标签页之后将会删除这些数据。也就是说数据存储在sessionStorage中,在当前标签页会一直存在。

首先在初次进入页面时在onload事件中往sessionStorage存入一个标识

window.addEventListener("load",function(){
    if(sessionStorage.getItem("flag")){
        return;
    }
    sessionStorage.setItem("flag", true);
})

上面说的还有一个问题,就是如何统计用户打开了多个标签页呢?

在本地缓存中,localStorage中的数据是整个网站都可以共享的,也就是具有相同域名、ip的网站,localStorage里的数据在不同标签页中也是相同的。

这时候可以往localStorage里存一个计数器,当用户进入页面时,计数器加1,当用户离开页面时计数器减1。当计数器为0时,标志页面全部关闭,此时可以记录页面关闭的结束时间。同时访问网站的开始时间也存到localStorage中。

window.addEventListener("load",function(){
    let nowTime = getNowTime()
    let openPageCount = localStorage.getItem("openPageCount")
    openPageCount += 1
    localStorage.setItem("openPageCount",openPageCount)
    //其实说明是页面是刷新后加载的,不应该统计开始时间
    if(sessionStorage.getItem("flag")){
        return;
    }
    localStorage.setItem("startTime",nowTime)
    sessionStorage.setItem("flag", true);
})

window.addEventListener("beforeunload",function(){
    let nowTime = getNowTime()
    let openPageCount = localStorage.getItem("openPageCount")
    openPageCount -= 1
    localStorage.setItem("endTime",nowTime)
    localStorage.setItem("openPageCount",openPageCount)
    if(openPageCount == 0){
        //说明页面全部关闭,这时候可以传数据给后台
    }
})

function getNowTime(){
    let nowTime = new Date().getTime()
    return nowTime
}

这里还有个问题,就是用户意外关掉电脑或者突然断电了,这时候是不会执行beforeunload是不会执行,此时这个数据是不正确,是应该抛弃的。

要解决这个问题,可以往localStorage里存一个刷新时间,每30秒更新这个刷新时间,用户加载网站时,读取这个刷新时间,如果当前时间和这个刷新时间相差大于1分钟,说明数据有断层,此时应该抛弃这一条记录数据。

window.addEventListener("load",function(){
    let nowTime = getNowTime()
    let openPageCount = localStorage.getItem("openPageCount")
    openPageCount = openPageCount ? parseInt(openPageCount) : 0
    openPageCount += 1
    localStorage.setItem("openPageCount",openPageCount)
    refreshTime()
    let isRightTime =  compareRefreshTime()
    //其实说明是页面是刷新后加载的,不需要统计开始时间
    if(sessionStorage.getItem("flag") && isRightTime){
        return;
    }
    localStorage.setItem("startTime",nowTime)
    localStorage.setItem("refreshTime",nowTime)
    sessionStorage.setItem("flag", true);
})

window.addEventListener("beforeunload",function(){
    let nowTime = getNowTime()
    let openPageCount = localStorage.getItem("openPageCount")
    openPageCount -= 1
    localStorage.setItem("endTime",nowTime)
    localStorage.setItem("openPageCount",openPageCount)
    if(openPageCount == 0){
        //说明页面全部关闭,这时候可以传数据给后台
    }
})

function getNowTime(){
    let nowTime = new Date().getTime()
    return nowTime
}

function compareRefreshTime(){
   let nowTime = getNowTime()
   let refreshTime = localStorage.getItem("refreshTime")
   return nowTime - refreshTime < 60 * 1000
}

function refreshTime(){
    setTimeout(refreshTime ,30 * 1000)
    let nowTime = getNowTime()
    localStorage.setItem("refreshTime",nowTime)
}

如何监听页面活跃状态切换?

可以通过 Page Visibility API 以及在 window 上声明 onblur/onfocus 事件来处理。

Page Visibility API

一个网页的可见状态可以通过 Page Visibility API 获取,比如当用户 切换浏览器Tab、最小化窗口、电脑睡眠 的时候,系统API会派发一个当前页面可见状态变化的 visibilitychange 事件,然后在事件绑定函数中通过 document.hidden 或者 document.visibilityState 读取当前状态。

document.addEventListener('visibilitychange',  function (event) {  
  console.log(document.hidden, document.visibilityState)
})

onblur/onfocus

可以通过 Page Visibility API 以及在 window 上声明 onblur/onfocus 事件来处理。对于PC端来说,除了监听上述相关事件外,还可以考虑监听鼠标行为,比如当一定时间内鼠标没有操作则认为用户处于非活跃状态。

什么时机上报数据

页面离开时上报

对于页面刷新或者关闭窗口触发的操作可能会造成数据丢失

下次打开页面时上报

会丢失历史访问记录中的最后一个页面数据

目前采用的方案2,对于单页内部跳转是即时上报,对于单页/多页应用触发 window.onbeforeunload 事件的时候会把当前页面数据暂存在 localStorage 中,当用户下次进入页面的时候会把暂存数据上报。有个细节问题,如果用户下次打开页面是在第二天,对于统计当天的活跃时长会有一定的误差,所以在数据上报的同时会把该条数据的页面进入时间/离开时间带上。

以上就是统计用户停留网站时长思路的全部代码。

对于页面停留时长的定义可能在不同场景会有差异,比如内部业务系统或者OA系统,产品可能更关心用户在页面的活跃时长;而对于资讯类型的产品,页面可见时长会更有价值。单一的数据对业务分析是有限的,所以在具体的代码实过程中我们会把停留时长分三个指标,这样能更好的帮助产品/运营分析。

  • active 页面活跃时长
  • visible 页面可见时长 //仅支持Desktop
  • duration 页面总停留时长
上一篇:彻底弄清楚session,cookie,WebStorage(LocalStorage,SessionStorage)的区别及应用场景


下一篇:使用命令wsimport构建WebService客户端