前端埋点总结

用户行为分析

随着互联网发展,企业对于网站的PV、UV、用户的转化、新增和留存也越来越关注。而完整的数据采集是一切的前提。

埋点即监控用户在应用表现层的行为,于产品迭代而言至关重要,运营,产品,数据分析基于此来对用户行为进行分析统计,同时埋点也可作为一种前端监控的手段,检验功能是否达预期的佐证。

基于埋点数据进行用户行为分析,可以得到包含页面点击量、用户访问量、用户访问路径、用户转化率、导流转化率、用户访问时长和用户访问内容分析等重要数据。

  • 用户怎么找到该产品的

通过埋点网站访问来源,可以统计用户入口分布,统计什么推广最有效,产品用户的聚集地方分布。

  • 用户感兴趣的是什么

通过产品功能点击的埋点,统计知道用户感兴趣的是什么,便于产品运营更好的更新产品,取消或改进不感兴趣的产品。

  • 用户有什么特征

地理分布浏览器类型、网站停留时常、寻找产品用户群体,针对群体进行改进更新,以及对其他群体进行吸引等等。

  • 其他

通过访问页面的注册用户数和页面 PV 的比值了解用户转化率。
通过导流页面PV和源页面 PV 的比值统计导流转化率。

可埋点数据

type - 上报类型
appid - 设备id
screen - 屏幕信息
userAgent - 浏览器信息
userInfo - 用户身份信息
timestamp - 上报时间
document.referrer - 访问来源
action - 上报事件的动作类型
element - 触发上报的元素
地理位置
访问渠道
以及其他自定义数据params等等

埋点方案

前端埋点大致分为:代码埋点、可视化埋点、无痕埋点三种。

  • 代码埋点也叫手动埋点属于侵入式埋点,由开发手动在代码内植入预埋点,完全由开发控制埋点的位置时间和触发机制。
  • 可视化埋点即以业务代码为输入,通过可视化系统配置埋点,最后以耦合的形式输出业务代码和埋点代码。
  • 无痕埋点即无差别地对全局所有事件和页面加载生命周期等进行拦截全埋点。

代码埋点

  • 使用第三方sdk埋点
如百度统计、友盟、TalkingData、Google Analytics、Sensors Analytics等都提供了这一方案。

使用相对简单,在APP或者界面初始化的时候,初始化第三方数据分析服务商的SDK,然后在某个事件发生时就调用SDK里面相应的数据发送接口发送数据。例如,我们想统计APP里面某个按钮的点击次数,则在APP的某个按钮被点击时,可以在这个按钮对应的 OnClick 函数里面调用SDK提供的数据发送接口来发送数据。

除此针对特定需求也可以统一封装数据上报通用sdk,各页面各业务模块按需调用,同时埋点的形式也是多种多样的

  • 基于事件点击埋点
// 上报sdk
export const sdk = {
  params: null,
  initParams() {
    const params={};
    params.domain = document.domain || '';
    params.title = document.title || '';
    params.referrer = document.referrer || '';
    params.sw = window.screen.width || 0;
    params.sh = window.screen.height || 0;
    params.lang = navigator.language || '';
    params.ua = navigator.userAgent || '';
    params.loadT = window.performance.timing.domContentLoadedEventEnd - window.performance.timing.navigationStart || 0;
    params.timestamp= new Date();
    sdk.params = params;
  },
  report(params = {}) {
    // 上报
     if(!sdk.params){
        sdk.initParams();
    }
    const _params = merge({},sdk.params,params);
    request('/api/report',{params:_params});
  }
};

// react wapper组件式
// 封装埋点包裹组件
export default function TrackerClick(props) {
  const { children, type } = props;

  return React.Children.map(children, child => {
    React.cloneElement(child, {
      onClick: (e) => {
        const originClick = child.props.onClick;
        typeof originClick==='function' && originClick.call(child, e);
        sdk.dispatch({type});
      }
    })
  });
}

// 页面使用
<TrackerClick type="namespace.click">
    <Button onClick={handleClick}>查看</Button>
</TrackerClick>
// 通用方式
//上报事件的绑定类型对应的绑定名称
const REPORT_EVENT_FUNC = 'data-reporteventfunc';
//上报事件数据对应的绑定参数名称
const REPORT_EVENT_DATA = 'data-reporteventdata';
document.body.addEventListener('click',function(e){
   if(e.target.getAttribute(REPORT_EVENT_FUNC)==='click'){
        const str=e.target.getAttribute(REPORT_EVENT_DATA);
        sdk.report(JSON.stringify(str));
   }
})

// 页面-react
<span 
    data-reporteventfunc="click" 
    data-reporteventdata={JSON.stringify({code:1,id:2})}></span>
// 页面-vue
<span 
    data-reporteventfunc="click" 
    :data-reporteventdata="JSON.stringify({code:1,id:2})"></span>
// 使用装饰器,剥离埋点与业务逻辑实现上的耦合,实现低侵入埋点
@tracker((params)=>request('/api/report',{params}))
click(params){
 // click业务...
}

const tracker = partical=>(target, key, descriptor)=>{
    if (typeof partical!=='function') {
        throw new Error('tracker arguments is not a function ' + partical)
    }
    const oldValue=descriptor.value;
    descriptor.value=function(...args){
        partical.apply(this,args);
        return oldValue.apply(this,args);
    }
    return descriptor;
}
  • 页面访问埋点-统计页面曝光时长
// Vue中通过mixin
beforeRouteEnter(to, from, next) {
    this.enterTime=+ new Date();
},
beforeRouteLeave(to, from, next) {
     sdk.report({
         type: 'visit',
         name: to.name,
         enterTime: this.enterTime,
         leaveTime: +new Date(),
         params: {
             from: {
                 name: from.name,
                 path: from.path,
                 query: from.query
             },
             to: {
                 name: to.name,
                 path: to.path,
                 query: to.query
             },
         } 
     })
}
传统基于DOMContentLoaded、beforeunload、onload等也可以实现
  • css埋点
<style>
.tracker:active::after{ 
    content: url("http://www.yzw.com/api/tracker/report?action=yourdata"); 
}
</style>
<a class="tracker">点击我,会发埋点数据</a>

埋点数据上报的形式

  • xhr上报

适用于需要接受数据上报后的返回结果进行回调处理

  • img/iframe/script上报
sdk.report=(params){
    // 1.img标签
    var img = document.createElement("img");
    img.src = '/api/report?' + querystring.stringify(params);
    // 2.img对象
    const img = new Image();
    img.src='/api/report?' + querystring.stringify(params);
    // 3.script标签
    var script = document.createElement("script");
    script.src = src;
    (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(script);
}

可视化埋点

方案有Mixpanel、TalkingData、诸葛IO、腾讯MTA,Sensors AnalyticsV1.3+等

可视化埋点通常流程为:

输入页面的url =>
页面加载完成后 =>
配置可视化的工具 =>
点击创建事件(click) =>
进入元素选择模式 =>
用鼠标点击页面上的某个元素(例如button、a这些element)=>
就可以在弹出的对话框里面 =>
设置这个事件的名称(比如叫TEST),选上报数据属性(properties)=>
保存配置 =>
用户访问点击按钮 =>
数据上报

其中针对元素标记多是利用xpath,是在xml文档中查找信息的语言,如下所示

const getPath = function (elem) {
     if (elem.id != '') {
        return '//*[@id="' + elem.id + '"]';
     } 
     if (elem == document.body) {
        return '/html/' + elem.tagName.toLowerCase();
     } 
     let index = 1, siblings = elem.parentNode.childNodes;
     for (const i = 0, len = siblings.length; i < len; i++) {
        const sibling = siblings[i];
         if (sibling === elem) {
            return arguments.callee(elem.parentNode) + '/' + elem.tagName.toLowerCase() + '[' + (index) + ']';
         } else if (sibling.nodeType === 1 && sibling.tagName === elem.tagName) {
            index++;
         } 
     }
 }
通过上述方法,当我们点击某个元素时,将触发的元素event.target传入,即可得到完整的xpath。
如果将其换做dom的选择器,类似:div#container>div:nth-of-type(2)>p:nth-of-type(1),由此,可以定位到具体的DOM节点

mixpanel 分为三层结构:

  • 基本工具层:提供类型判断、遍历、继承、bind 等基本的工具函数;json、base64、utf8 编解码能力;url 参数读写函数;cookie、localStorage 读写能力;dom 事件绑定能力;dom 节点查询能力;info 浏览器信息获取能力。
  • 功能模块层:提供基于 DomTracker 实现的 LinkTracker 跳链接埋点、FormTracker 提交数据埋点功能;autotrack 自动埋点功能;基于 cookie 或 localStorage 的 MixpanelPersistence 持久化功能;MixpanelNotification 提示功能;gdbr 依据欧盟《通用数据保护条例》,首先判断用户是否设置了 navigator.doNotTrack 避免数据被追踪,其次判断持久层是否禁止数据被追踪,当两者同时允许追踪埋点数据时,mixpanel 才会上报埋点数据。
  • 核心实现层:MixpanelLib 串联功能、处理选项、发送埋点数据等;MaxpanelGroup;MaxpanelPeople

Sensors Analytics

使用者在自己的网页引入 Sensors Analytics 的 JavaScript SDK 代码后,从 Sensors Analytics 的后台可视化埋点管理界面跳转到使用者的网站界面时,会自动进入到可视化埋点模式。在这个模式下,使用者在网页上点击任意 html元素时,Sensors Analytics 都会取到这个元素的url,层级关系等信息来描述这个 html 元素,当使用者设置了这个元素和某个事件相关联时,SDK 会把这些关联信息和客户生成配置信息,并且存放在 Sensors Analytics 提供的相应保存位置。当真正的用户以普通模式访问这个网页时,SDK 会自动加载配置信息,从而在相应的元素被点击时,使用 Sensors Analytics 的数据发送接口来 track 事件。

从上面我们介绍的可视化埋点的方案可以看出,可视化埋点很好地解决了代码埋点的埋点代价大和更新代价大两个问题。但是,可视化埋点能够覆盖的功能有限,目前并不是所有的控件操作都可以通过这种方案进行定制;同时,Mixpanel 为首的可视化埋点方案是不能自己设置属性的,例如,一个界面上有一个文本框和一个按钮,通过可视化埋点设置点击按钮为一个“提交”事件时,并不能将文本框的内容作为事件的属性进行上传的,因此,对于可视化埋点这种方案,在上传事件时,就只能上传 SDK 自动收集的设备、地域、网络等默认属性,以及一些通过代码设置的全局公共属性了;最后,作为前端埋点的一种方案,可视化埋点也依然没有解决传输时效性和数据可靠性的问题。

无埋点

Heap、百度(点击猴子)、GrowingIO等
与可视化埋点又类似,二者的区别就是可视化埋点先通过界面配置哪些控件的操作数据需要收集;“无埋点”则是先尽可能收集所有的控件的操作数据,然后再通过界面配置哪些数据需要在系统里面进行分析。

“无埋点”相比可视化埋点的优点,一方面是解决了数据“回溯”的问题,例如,在某一天,突然想增加某个控件的点击的分析,如果是可视化埋点方案,则只能从这一时刻向后收集数据,而如果是“无埋点”,则从部署 SDK 的时候数据就一直都在收集了;另一方面,“无埋点”方案也可以自动获取很多启发性的信息,例如,“无埋点”可以告诉使用者这个界面上每个控件分别被点击的概率是多大,哪些控件值得做更进一步的分析等等。

当然,与可视化埋点一样,“无埋点”依然没有解决覆盖的功能优先,不能灵活地自定义属性,传输时效性和数据可靠性欠佳这几个缺点。甚至由于所有的控件事件都全部搜集,反而会给服务器和网络传输带来更大的负载。

技术实现上也可以通过拦截全局页面访问和事件响应,分析用户访问全流程路径,上报所有触发埋点,因此无埋点也叫全埋点。
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2Jsb2cvMTY4MzQyMS8yMDE5MDUvMTY4MzQyMS0yMDE5MDUyNDE2MzYzMjQ5NS0yMTI2ODU4OTA3LnBuZw==.png

总结

&nbsp代码埋点可视化埋点无埋点
优点可控性强,灵活性高,可定制各种特殊埋点需求,监测数据准确。通过集成sdk,运营可自主选择,操作便捷,满足大部分场景数据全面,不需要关注埋点逻辑,前端开发量轻
缺点侵入型强,需要开发手动在相应位置进行埋点,增加维护成本通常需要引入第三方,控件有限,技术上推广和实现起来有难度,需要运营配合流量和采集的数据过于庞大,存在浪费、服务器性能压力大、难以特殊化定制
适用场景适用于埋点量少、定制化程度高的需求埋点量多,需要对数据深度整合分析网站需要全埋点监控

每种方案各有优劣,并不存在某种普遍完美的可以适应一切场景的埋点方案,而是应该根据不同的产品,不同的分析需求,不同的系统架构,不同的使用场景,选择最合适的一种接入方案。下面是一些典型的例子:

  1. 仅仅是分析UV、PV、点击量等基本指标,可以选择代码埋点或者可视化埋点等前端埋点方案;
  2. 精细化分析核心转化流程,则可能需要利用后端 SDK 或者 LogAgent 接入后端日志;
  3. 活动/新功能快速上线迭代时的效果评估,则可以利用可视化埋点快速完成;
  4. 对客服服务质量的考核,或者不同快递在不同省份运送不同品类产品的速度的比较,则需要使用后端 SDK 来对接第三方系统以便导入数据。
阅读 1.1k

推荐阅读