《看完就懂系列》谈谈数据埋点的原理与实现

2,817 阅读11分钟

这是大冰块2021年第7篇原创文章,和大冰块一起在前端领域努力吧!!!💪


写在前面

之前公司接了个做广告的业务,甲方财大气粗,沟通也特别顺利。刚开始的时候,大家都摩拳擦掌兴致满满,觉得这个项目奖金一定会翻一番。于是第一版赶得很急,上线之后,点击率与转化率却一直不温不火。眼瞅着到嘴的项目奖金要飞走,leader说如果运维的小伙伴能根据具体原因快速定位,还怕点击率和转化率不“噌噌噌”的上涨吗?所以第二版先做个数据埋点吧~

那么什么是数据埋点呢?数据的原理是什么?数据埋点又该如何实现呢?

什么是数据埋点

数据埋点针对客户端或者网页应用,对其中某些或全部流程记录用户操作的日志信息,用来分析当前应用的使用情况,建立用户画像等。根据用户的日志信息,对产品提供优化 支持,对运营提供数据支持,对开发提供快速debug的支持。 比如访问数(Visits),访客数(Visitor),用户停留时长(Time On Site),页面浏览数(Page Views)和跳出率(Bounce Rate)都可以通过数据埋点来获取。

什么?上面的说明太正式?还是看不明白?那么以大冰块开的商场为例来通俗的讲一下:

大冰块有一座自己的商场(目前还在梦里),商场入驻了100家品牌商户,商场中安装了300个摄像头,招聘了100名安保监视人员,他们统计每天各个时间段的人流量以及消费金额,哪个商户人最多,哪个商户人流量最少,甚至门口的摄像头还会监视顾客从哪来的,出了商场又去了哪个商场,统计完了都会拿小本本记下来。

有一天大冰块来逛商场,首先商场大门摄像头记录了大冰块进入的信息,是车库上来的还是地铁口进来的。然后大冰块乘坐手扶电梯到了2楼。电梯记录了大冰块乘坐电梯的时间,以及大冰块的体重。大冰块到了二楼的服饰店,买了一件99的卫衣。商场店铺记录了大冰块的支付方式,支付方记录了大冰块的经济状况。

大冰块走的时候,商场就把大冰块的这些信息存了起来,至此大冰块的用户画像已经建立起来了。

怎么听起来和监视差不多?没错,就是和监视差不多,毕竟大数据下没有隐私~ 不然怎么杀熟/割韭菜 为我们提供更好的服务?不过技术无罪,有罪的只会是使用者。啊跑题了,我们只谈技术~

数据埋点的方式

数据埋点的三个级别:

初级的数据埋点: 在产品部分关键流程部位植相关统计代码,用来追踪统计用户的操作行为,统计关键流程的使用程度。

中级的数据埋点: 在产品整体流程中植入多段代码追踪用户连续的操作行为,建立用户操作模型来分析用户在使用产品中的各种操作行为。

高级的数据埋点: 与研发及数据分析师团队合作,通过数据埋点还原出用户画像及用户行为,建立独立的数据分析后台,通过数据分析、优化支持产品。

这么说吧,初级的数据埋点相当于一个点,点与点之间可能毫无关系,每个埋点都对应一个独立的功能点。而中级的数据埋点相当于把点连成了线,每一部分埋点对应一个独立的流程。高级的数据埋点相当于一个面,能够涵盖多个流程,正是多个流程才组成了一个整体的业务功能。

数据埋点的方式:

操作信息收集可以大致分为两种:页面访问统计统计操作行为,而现在埋点的主流有两种方式:

  1. 公司研发时在项目中注入统计代码,并搭建起相应的后台查询。
  2. 直接使用第三方统计工具。

如果是产品早期,通常会使用第二种方式来采集数据,方便快捷,也不用担心维护问题。常见的统计平台如百度,阿里云,神策等,这些第三方还提供分析工具进行基本的分析。

而对于那些对数据安全比较重视,业务又相对复杂的公司则通常是使用第一种方式采集数据,并搭建相应的数据产品实现其数据应用或是分析的诉求。

代码埋点的优缺点

优点

使用者控制精准,可以非常精确地选择什么时候发送数据。

使用者可以比较方便地设置自定义属性、自定义事件,传递比较丰富的数据到服务端。

缺点

埋点代价比较大,每一个控件的埋点都需要添加相应的代码,不仅工作量大,而且限定了必须是技术人员才能完成。

更新代价比较大,每一次更新,都需要更新埋点方案,如果是非网页应用,需要通过各个应用市场进行分发,同时并不是所有用户都会更新,这样你就获取不到这批用户的数据。

数据埋点的注意事项

  1. 尽量做到事无巨细,每一步用户行为全都需要获取数据。同级页面操作和同页面多来源为一个事件,不同的操作内容和页面来源作为事件的属性进行采集。用户的点击,若与下一个页面的浏览是直接触达可只埋一个事件。
  2. 数据埋点的前提是,团队需要首先明确产品的目标以及当下的首要问题。产品可能产生的用户行为数据纷繁复杂,清晰的目标能让项目团队避免迷失在数据的海洋中,从而耗费大量的时间和机会成本。
  3. 最开始进行需求梳理时,需要从整体进行考虑,要给给深层次和具体的需求。不要等到开发埋好指标结果出来时却不是自己想要的,需要重新埋点。另外,后续产品版本更新迭代了,原有埋点不可用,也需要重新埋点。
  4. 数据采集方案要想清楚,哪些应该在前端埋点,哪些应该在后端埋点,埋点采集SDK如何正确使用在还没了解清楚时就急于上手。数据统计口径需要确定清楚,且和开发保持良好沟通,将埋点的具体采集时机正确传达给开发,导致最终埋点实现的不是自己想要定义的指标。
  5. 在分析的一开始,建议采集少数的用户行为。选择少量、重要的用户行为开始记录和分析,这样很快就能有成果产出。另外用户行为不等同于应用的页面或点击操作,用户行为是更加具体的一个事件定义。
  6. 埋点结束后,测试一般只会看一下埋点是否有数据返回,而不会一个个是对数据是否有收到以及是否准确。这个时候需要我们在有一定数据量积累的时候,对数据的有无和准确性进行验证。

数据埋点的意义

数据埋点可以根据用户在应用上的一系列操作线索,提炼有用的信息,进行数据分析。重点不在于埋点的作用,其实在于获取埋点数据后的二次加工,如何分析输出业务分析结论。

  1. 分析运营机制的合理性

    如移动APP上大多都有用户分享的功能,一般的营销手段是通过老拉新的方式,运营设定一些奖励机制,用来提高APP的注册量。

    提前在用户分享键返回后台重新进入购买页面埋点,就能记录到页面的访问次数和转化率,用于分析奖励机制对用户的刺激性,指导策略方向。

  2. 分析产品功能的合理性

    如产品设计了新功能想提高下用户的满意度。提前在新功能的各个按钮上进行埋点,就能获取到用户使用新功能的次数,以及在新功能的使用行为,可以分析用户是否对新功能比较感兴趣,页面的跳转设置是否合理等。

  3. 分析用户消费行为,挖掘流失点

    如老板问你为什么最近收益这么少。在用户消费的核心页面和按钮进行埋点,就能记录到每个流程的转化率,用于分析用户漏斗的哪一个阶段出现了问题,结合业务输出解决方案。   

  4. 监控产品的流畅性

    如产品刚上线阶段,需要监控用户使用过程中,各个页面或按钮响应的流畅性是否存在问题。提前在核心功能页面和按钮进行埋点,就能记录到每个页面和按钮的衔接情况,发现问题及时解决,以免影响用户体验。

  5. 分析不同渠道的用户行为差异

    如市场推广常常需要分析不同渠道的用户转化情况,以便减少推广成本。提前在各个渠道进行埋点,记录各渠道用户在APP中的后续行为,调整推广策略。

前端实现的流程逻辑

前端的实现主要就是根据浏览器的API进行检测用户的操作,然后获取操作信息记录在sessionstorage,当用户关闭当前页面时将日志信息发送给后台,或者定时发送给后台。举个简单的例子吧~

以监听页面停留时长及事件点击操作为例:

逻辑图:

大冰块辛辛苦苦画的图

部分代码实现

监听多页面用户停留时长

let stopTime
window.onpageshow = ()=>{
  stopTime = new Date().getTime()
}
window.onpagehide = ()=>{
  stopTime = new Date().getTime() - stopTime
  localStorage.setItem(window.location.href+'stopTime', stopTime)
}

监听单页面用户停留时长

// 也可放在路由拦截中做
let stopTime
window.addEventListener('onload',(e)=>{
  stopTime = new Date().getTime()
})
window.addEventListener('popstate',()=>{
  let t = new Date().getTime() - stopTime
  stopTime = new Date().getTime()
  localStorage.setItem(window.location.href+'stopTime', stopTime)
})

监听用户点击事件

const myBtn = document.getElementById("myBtn")
myBtn.addEventListener("click", ()=>{
    localStorage.setItem('click', JSON.stringify({"myBtnclick":myBtn,"time":new Date().getTime()}))
})

监听请求响应时长

// 这部分代码应该在全局封装的Ajax中做,或者在前端框架里的http请求与相应拦截中做

let requestTime
// 请求拦截
myAjax.request.use(config => {
   ...
   requestTime = new Date().getTime()
   localStorage.setItem(res.url, JSON.stringify([{"startTime":requestTime,"endTime":0}]))
   ...
}, error => {
   ...
   return Promise.reject(error)
})

// 响应拦截
myAjax.response.use(res => {
   ...
   let data = JSON.parse(localStorage.getItem(res.url))
   let obj = data.requestTime.find(e=>e.startTime === requestTime)
   obj.endTime = new Date().getTime()
   localStorage.setItem(res.url+requestRandom, JSON.stringify(data))
   ...
}, error => {
   ...
   return Promise.reject(error)
})

以上的代码只是提供一个思路,具体的埋点还需要具体的分析与技术应用。不过只要掌握了整体的思路方法,代码实现起来就没什么难度了。

写在后面

这是大冰块《看完就懂系列》的第6篇文章,《看完就懂系列》旨在把一些常见的概念或方法以通俗易懂的方式呈现出来。欢迎大家点击其他文章一起讨论学习:

原创不易,如有错误,欢迎指出。

如果有帮助到你,请给大冰块来个三连(点赞收藏评论),让我们一起在前端的路上进步吧~🤭