前端埋点的那些事
为什么要埋点?现在的互联网公司越来越关注转化、新增、留存,而不是简单的统计PV、UV。而完整的数据采集是一切的前提。
埋点包括在IOS、Android、H5、小程序等前端埋点,也包括后端业务埋点。这里仅仅讲讲这些年和产品经理、运营撕逼上百个回合的前端埋点内容。
说说手工埋点
、可视化埋点
、无埋点
区别
手动埋点(代码埋点)
纯手动写代码,调用埋点SDK的函数,在需要埋点的业务逻辑功能位置调用接口上报埋点数据,友盟、百度统计等第三方数据统计服务商大都采用这种方案;
手动埋点让使用者可以方便地设置自定义属性、自定义事件。所以当你需要深入下钻,并精细化自定义分析时,比较适合使用手动埋点。
手动埋点的缺陷就是,项目工程量大,需要埋点的位置太多,而且需要产品开发运营之间相互反复沟通,容易出现手动差错,如果错误,重新埋点的成本也很高。这会导致整个数据收集周期变的很长,收集成本变的很高,而且效率很低。因为手动埋点需要开发人员完成,所以每次有埋点更新,或者漏埋点,都需要重新走上线发布流程,更新成本也高,对线上系统稳定性也有一定危害。
手动埋点的技术本质是什么呢?
我们看看从javascript中能轻松获得哪些信息:
- 域名:document.domainURLdocument.URL
- 页面标题:document.title
- 分辨率:window.screen.height & window.screen.width
- 颜色深度:window.screen.colorDepth
- Referrer:document.referrer
- 客户端语言:navigator.language
除了上面的列举的常规信息以外,还有大量的业务数据,都需要通过手动写javascript去实现。
代码手动埋点常用的方式有以下几种:
-
命令式
$(document).ready(()=>{ // ... 这里是你的业务逻辑代码 sendData(params); //这里是发送你的埋点数据,params是你封装的埋点数据 }); // 按钮点击时发送埋点请求 $('button').click(()=>{ // ... 业务逻辑 sendData(params); //同上 });
这里的sendData有很多种方式,比如基于ajax发送json数据,或者使用url连接带上params,或者使用一像素图片带上数据,在或者使用head带上埋点也可以。封装方式多种多样。
- 声明式
<button data-mydata="{key:'uber_comt_share_ck', act: 'click',msg:{}}">打车</button>
这里声明了自定义属性data-mydata
,你可以在你的SDK中去扫描和识别这些自定义属性,并解析封装数据,在SDK中按照自定义规则去绑定事件并发送埋点数据。
-
前端框架式
如果使用Vue
或者React
等前端框架,这些框架都有自己的各种生命周期,为了减少重复性的手动埋点次数,可以在各个生命周期位置,根据你的需求封装你所需的埋点。比如你是SPA
单页应用,你希望在每一个页面的componentDidMount
埋点,并由此确定用户已经打开了页面。 - css埋点:
.link:active::after{ content: url("http://www.example.com?action=yourdata"); } <a class="link">点击我,会发埋点数据</a>
这里使用了很巧妙的css的某些特征,这些可以触发发送请求的特征。
以上是比较常见的手动埋点方案,当然还有很多其他方式和有待挖掘的方案。也请大家补充。
可视化埋点(框架式埋点、无痕埋点)
解决了纯手动埋点的开发成本和更新成本,通过可视化工具快速配置采集节点(圈点),在前端自动解析配置,并根据配置上传埋点数据,比起手动埋点看起来更无痕
,这里的配置数据可以设置过滤条件,避免针对所有元素(比如全埋点),可以在调用开启自动监控API时通过设置一些特征属性,来过滤不符合条件的元素,实现只针对某些元素进行自动上报数据的需求。
比如国外比较早做可视化的是Mixpanel,国内较早支持可视化埋点的有TalkingData、诸葛IO,2017年腾讯的MTA也宣布支持可视化埋点;相比于手动埋点更新困难,埋点成本高的问题,可视化埋点优化了移动运营中数据采集的流程,能够支持产品运营随时调整埋点,无需再走发版流程,直接把配置结果推入到前端,数据采集流程更简化,也更方便产品的迭代。
可视化埋点中多数基于Xpath的方案,XPath 是一门在 XML 文档中查找信息的语言。XPath 可用来在 XML 文档中对元素和属性进行遍历。
比如上图中标识的位置,其中的xpath是://*[@id="projects"]/a4/img,如果换成DOM的selector:#projects > a:nth-child(4) > img。通过这些信息可以精准定位到一个DOM节点,xpath方案分为精确路径和概略路径两种做法,精确路径从被点击的元素不断向上冒泡查找到根节点,并记录过程中每个节点的。如果用户阻止了冒泡会导致失效,概略路径是在前者的基础仅仅向上查找白名单中的节点。但是如果DOM节点有任何变化,对应的xpath数组就是被打乱,很容易影响采集。
可视化埋点配置化能力相对手动埋点更强,是对手动埋点的补充而不是代替,很多手动埋点点都可以通过好的规划和架构变为可视化埋点。
无埋点(自动埋点、全埋点)
无埋点并不是没有任何埋点,所谓无
只是不需要工程师在业务代码里面插入侵入式的代码。只需要简单的加载了一段定义好的SDK代码,技术门槛更低,使用与部署也简单,避免了需求变更,埋点错误导致的重新埋点。
通过这个SDK代码,前端会自动全量采集全部事件并上报埋点数据,能够呈现用户行为的每一次点击、每一次跳转、每一次登录等全量、实时用户行为数据,这些数据传到后端后,可通过用户分群、漏斗对比等功能,分析不同访问来源、不同城市、不同广告来源等多维度的不同转化细节,细而全。
图中可以看到无埋点会发送大量的请求,因为无埋点会针对很多DOM节点添加事件。当用户在页面中有交互时,就会触发大量的数据请求。
无埋点相比可视化埋点,在解决数据“回溯”问题上更有优势,如果你想分析某一天某个控件的点击情况,如果你没有针对这个按钮做可视化埋点,则只能从你针对这个按钮做可视化配置的这一时刻之后才有埋点数据,而无埋点,则从你部署SDK那一刻就一直有数据在收集;无埋点做热力图也更有优势,无埋点可以告诉使用者这个界面上每个控件分别被点击的概率是多大,通过热力图清晰可见。
无埋点的劣势是自定义属性不灵活,传输时效性差,数据可靠性欠佳,耗费网络流量,还会增加服务器负载,而且兼容性也不佳。
据说Heap Analytics在2013左右较早推出了无埋点方案,但是网上有人透露百度在2009年就有类似技术,后来2011年,百度质量部也推出过一个内部服务,用以录制安卓 App 的全部操作,通过回放定位App崩溃的原因;豌豆荚也在2013年左右在自己的 App 内,也记录了所有控件操作情况。国内GrowingIO在2015年也较早支持了无埋点方案,后面神策等其他第三方也陆续支持了此技术。
我们看看神策和Mixpanel对无埋点的实现方案。
-
神策: 根据官方的介绍,设置AutoTrack之后,SDK就会自动解析HTML页面上的( a 、 button 、 input )标签。 并记录这些标签的点击情况,一旦页面某一个按钮发生了点击行为,SDK就会去采集此按钮的一些信息,例如: 这个按钮的标签类型,这个按钮的文本内容,这个按钮的 name ,这个按钮的 id 、 class 名,还有一些按钮特有的属性如 href等。
- Mixpanel: 设置AutoTrack之后,SDK会监测页面上的所有 form表单 、 input标签 、 select和textarea标签 产生的 submit 、 change 、 click 事件,并采集这些标签上的属性一起上报。
无埋点确实发送的埋点数量很巨大,比如知乎上就有很多人质疑无埋点解决方案。很多用户对无埋点发送大量埋点请求表示不理解,但是由于无埋点技术方案的限制,无埋点的可交互元素众多,每一次交互都会发送请求,所以会导致网络请求过重。神策等官方文档中也建议无埋点最好使用在那些按钮不是很多的,相对简单的页面。
数据采集能力比较比如这个页面,点击确认按钮,如果使用无埋点和可视化埋点,在这里可能只能获取到某时刻某个人点击了确认,提交了一个订单,仅此而已。如果你希望拿到里面的首付款,月供,车型车款、用户详情等深度业务信息,就只能靠手动埋点获取。
无埋点和可视化埋点虽然使用和部署都很简单,但是在数据精确度和详细程度的获取能力上代码埋点更强大。一般来说,我们的产品都是根据业务场景混合使用三种埋点模式来完成我们的数据收集。
感性认识一些数据上报格式和接入代码上报方式提到过,基本就是json、url params、head等,为了数据分析的关联性,会带上cookie、还有一些数据可能是在localstorage等具有生命周期管控的客户端存储里。
GA的接入代码:
GA的上报格式:
Talkingdata的接入代码:
Talkingdata的上报格式:
埋点技术除了刚才的方式划分,还可以划分为前端埋点和后端埋点,后端埋点数据更可靠、更集中(且没有前端的多端问题)、更实时。这篇文章主要是讨论前端埋点。
根据工作中对埋点的对比和整理,我们简单比较部分埋点方案:
对于语义明确的UI事件,自动埋点的数据一般会比手动埋点更加准确,更贴近用户行为,也更节省开发成本,侵入性更低。
主要是因为自动埋点语义简单明确,不像手动埋点由于开发习惯、代码风格、人的理解误差、分支处理等各种不确定因素变得没那么清晰明了。
比如:“下单”事件,自动埋点的PV肯定是>=手动埋点的,而UV差别可能不大。分析开发代码发现在onClick Listener中包含其他未覆盖到的分支,差别很可能就在代码分支当中。如果更进一步分析下代码可以发现,为什么开发不在分支当中埋点?可能这个分支会认为用户的这一次点击是“无效”的,但这只是程序逻辑的看法,用户可能不这么认为,用户很可能会觉得很奇怪没反应,然后再点一次。这些手动埋点不易察觉的细节,自动埋点都能记录,所以说,自动埋点在这些情况下会更贴近真正的用户行为。
自动埋点可降低原来手动埋点的个数和复杂性,使之更简化
比如:进入“商品详情页面”(展现),目前包括5个手动埋点,实际上用自动埋点只需要一个就够了,而且自动埋点不会遗漏。从数据来看,一个自动埋点的PV已经超过5个手动埋点之和。
自动埋点可采集界面环境数据,但是数据不够纯,需要进一步去噪
自动埋点能采集到大部分用户“看到的而且有用数据”。比如:“价格”这一属性,手动埋点可直接定义“amout: 5.2“来轻松获取数据,而自动埋点获取的是一串文本: “价格预估5.2元”,若要获取精确的5.2这个数值,就需要进一步解析。
自动埋点无法替代手动埋点,但可大大减少手动埋点工作量可预想的是,在用户行为分析上,自动埋点可以满足很大一部分需求函数级的埋点无法用自动埋点代替,后台非UI的事件也无法用自动埋点代替,自动埋点无法携带当时的业务场景数据,这些都表明了自动埋点无法完全替代手动埋点。
但单就用户行为分析来讲,自动埋点是可以覆盖用户的一些基本行为路径的,并能做一些较浅层次的分析。如果需要探究用户行为背后的原因、或需要进一步深入分析行为的时候,就是需要更多的后台逻辑事件、需要携带更多属性值的时候,就需要通过手动埋点来完成。所以,但是深层次的分析是你的重点,就需要使用手动埋点来解决。
埋点类型虽然当前也就这几类解决方案,而且真实的使用请求会根据业务混合使用多种埋点类型。但是我们除了选择好埋点类型外,要展开埋点工作,面临的沟通协调,如何准确多团队达成共识,并确保各方对业务和埋点深度理解,做要的工作和面临的挑战会更大。想要做好埋点工作,埋点需求的整理很重要,且需要遵守一定的原则,所以我们引用滴滴内部Omega团队针对这些原则的整理(本来很多内容均采用了Omega团队的日常工作整理,Omega是滴滴内部服务的强大数据采集和分析平台,期待Omega开源或开放的一天,在此感谢滴滴Omega团队的深度沉淀):
埋点需求整理原则
原则是基于一系列问题展开,并基于这些问题确定埋点需求,我作为FE的RD,针对这些原则,虽然至今也没有真正全面的做到,但是如果遵循这些原则,将会受益良多(也欢迎大家补充问题内容),当你能清楚的回答这些问题,埋点工作将会更顺利的开展:
3个H,5个W
HOW LONG:
- 埋点可用周期是多久,持续几个版本可以?
- 生命周期结束后是否可以考虑下掉?
HOW MUCH:
- 现有的埋点哪些可以满足我的部分埋点需求?
- 哪些现有的埋点可以替代我要的部分埋点?
- 新的埋点有多少?这些埋点是否是最必要的?
HOW:
- 怎样证明新功能效果?
- 需要哪些埋点?
- 我该怎么埋这些点?
- 部分埋点的计算逻辑是什么?
- 数据结果怎么看?漏斗?同环比?
WHO:
- 我的产品设计面对的用户群里是谁?
- 用户特征是什么?
- 这部分特征用户对功能预期的数据结果是什么?
- 用户习惯是什么?
WHAT:
- 我的新产品是什么?
- 新产品包含哪几个模块?
WHY:
- 涉及新产品的目的是什么,为了解决什么问题?
WHERE:
- 新功能展示在产品端的哪个位置?
- 在哪些版本生效?
- 哪些功能的展示或作用在哪里需要跟服务端等交互?
WHEN:
- 功能是在用户场景什么时候调用产生?
- 调用过程中什么时候和服务端交互?
- 功能调用正常情况下需要大概需要多长时间?
- 什么情况会影响调用结果?
- 调用有风险的时候,是否需要加监测?
理清楚了埋点的思路,要让埋点顺利进行,且不影响线上功能,则需求严格的埋点规范和治理方案。
埋点规范某些企业,保守估计,手动埋点的错误率可能会高达50%,比如一些简单页面的进入应该埋在 viewDidAppear(didMount...),按钮点击应该埋在 onClickListener等等都经常被开发弄错。埋点工作本身并不难,是纯粹的体力活,但是要展开一个好的埋点工作,需要BI先梳理,然后再传达给RD,然后RD再去开发实现,最后应该经过测试验收,因为没有统一的标准,每个人的理解不一样,就很容易弄错,后面会和大家在详细聊聊埋点规范的问题。
我们了解的一些大公司,像Facebook等硅谷公司已经将埋点看得与产品设计同等重要,新功能还在设计阶段就先把衡量指标及埋点梳理好,而具体负责埋点的RD也是团队中最资深的RD(如果不是专职的话),RD需要每天不断的与BI沟通确保语义一致。
而我待过的滴滴、陆金所等公司的现状是,埋点的RD很多时候都是随机任务分工的,甚至经常被安排给实习生,埋点质量难以保证。还有一种情况是产品为了快速上线需求,一味追求上线速度,在需求评审阶段没有梳理和提出埋点需求,上线后临时插入埋点需求,在未经过分析理解和测试验收的情况下匆匆加入埋点代码,而且测试经常也不重视测试(提出免测),导致埋点错误,甚至是业务代码错误等线上问题。这种情况下自动埋点既能减少沟通开发的工作量,又能降低埋点出错的概率。所以,自动埋点更适合公司在埋点规范没有完全建立,埋点质量普遍不高的阶段。但是公司体量到一定程度后,RD和产品经理将会更频繁的和手动埋点接触,我们作为一个手动埋点的深度用户团队,谈谈我自己的对手工埋点的痛点梳理:
- 埋点混乱
- 常常埋错,漏埋
- 业务变化后,老埋点数据失去意义
- 埋点数据无人使用,浪费资源
- 数据团队、研发团队、产品团队协作配合难度大
- 很多时候不太重视数据,而是重视业务的快速上线
- 埋点语义不明确,同一个按钮存在多种描述,不易检索
- 无用/重复埋点太多,干扰了正常埋点数据
- 大量存量埋点Owner离职或者转岗,导致大量僵尸埋点信息
那么如何避免以上问题呢?建立一个好的规范非常重要,包括命名规范和流程规范。
埋点命名规范
我们当前的做法是埋点名称只能是由字母、数字、下划线组成,并保证在应用内唯一,比如sw是展示,ck是点击。
常用规则的举例如下:
比如行为埋点:{团队|业务|角色}_{组件|页面}_{具体元素}_{动作}
示例:
yourteam_fc_all_msg_ck
autoplatform_flowtab_sw : autoplatform代表业务线,flowtab 代表功能,sw代表页面操作,sw是展示,ck是点击
uber_comt_share_ck :uber业务线,comt评价组件,share分享按钮,ck点击
埋点流程规范
如果你发现每天有大量埋点错误反馈,并导致很多错误的分析结论,一个错误的分析结果还不如没有数据分析结果。造成这个问题的原因包括:
- 前端埋点涉及复杂的交互,难以找准埋点位置;
- 埋点的验收流程不完善,没有经过测试和产品经理的测试和验收,验证不完备;
好的埋点需求应该和业务功能需求同等重要,也需要经历软件开发的整个生命周期,如果能严格按照一个规范的流程处理埋点,以上问题会得到更好的解决。
规范内容
需求阶段:
确定埋点信息,核心包括五方面信息:事件ID、埋点名称、埋点描述、埋点属性以及截图。
举例:
- 快车页面打车的埋点信息为:
- 埋点ID为:gulf_p_f_home_order_ck
- 埋点名称为:呼叫快车
- 埋点描述:在快车首页点击呼叫快车按钮。
如何落地:
如果不按照规则和流程埋点将不会上报相关数据,制定强制规定。
开发什么功能:
埋点全文检索能力、自动找到重复埋点(语义相近或者数据相近)功能。
开发阶段:
务必和开发沟通,并让开发在完全理解业务语义的情况下,在前端按照埋点代码规范进行埋点。
举例:
比如针对商品购买按钮,在前端点击方法的第一行调用SDK,最好也传入文本字面描述。
如何落地:
静态代码检查。
开发什么功能:
开发探测每个埋点对应到的代码文件和代码行,开发根据人均事件量级进行监控报警功能。
测试阶段:
务必和测试沟通,并让测试在完全理解业务语义的情况下,通过CodeReview和埋点测试两种方式对埋点正确性进行验证。
举例:
比如针对商品购买按钮埋点,需要检查埋点测试中上传数据中事件ID、属性是否符合定义,另外触发时机是否正确。
如何落地:
规定如果未经测试的埋点不允许上报埋点数据。
开发什么功能:
提供所见即所得的埋点测试平台。
验收阶段:
确保相关人员在完全理解业务语义的情况下,可以通过与自比较和他比较的方式来进行验证。
举例:
- 自比较验证:同一APP某一个业务线的购买冒泡数量一定要小于所有业务线的冒泡数合计;
- 他比较验证:前端某业务点数量和对应服务端数据应该基本相当。
如何落地:
规定如果未经验证的埋点不允许上报埋点数据。
开发什么功能:
提供埋点实时数据查询。
清理阶段:
确认完全理解语义的情况下,可对业务发生巨大变化或者不在维护的埋点进行废弃。
举例:
百度糯米合并饿了么后,埋点在经历产品大改版后已经和其他业务线合并,需要废弃之前的遗留埋点。
如何落地:
3个月以上未被使用的埋点、1个月以上数据为0的埋点自动废弃。3个月后使用次日会自动开启采集。
开发什么功能:
根据规则提供针对未使用埋点的计算、并自动废弃。
可以看出,规范要落地,需要整个公司的共识,也需要从上而下的压力,还有强势的制度。比如针对全公司个部门做评分,评分规则基于埋点和数据分析抽象出来。
另外我们在前端埋点中也遇到过一些注意事项,整理如下,希望对大家有所帮助。
注意事项:
一些埋点安全性问题:
如果你使用普通的http 协议,在数据传输的过程存在被劫持(包括不限于:JS代码注入等)的可能性,造成H5页面中出现诸如:未知的广告或者原网页被重定向等问题。为了降低此类事件发生的可能性,建议最好使用https 协议(倡导全站https),以确保数据传输过程的完整性,安全性。
版本迭代的时候埋点需要注意什么?
- 如果是公用模块,可以非常放心安全的全量迁移埋点;
- 如果是新增模块,那就需要注意是否遵循了最新的埋点规范,有没有重复的埋点命名存在,埋点是否符合业务逻辑;
- 如果是下线模块,那就需要评估下线后对数据的影响范围,而且要第一时间充分周知相关方,让各方参与评估;
- 如果是更新模块,需要评估在原有埋点上需要修改的埋点内容,是否需要重新埋点,删除不需要的埋点,而且要修改功能的数据承接。
关于埋点上报的解决方案
一般会实现上个模块,Event收集器,Event缓存器,和Event上报器。
Event上报模式
除了用户个人不希望耗费流量以外,也可能会因为弱网及断网情况,如果确保数据不丢失,基于这些问题而诞生的上传策略,来设计如何上报已收集的所有事件数据。上报一般包括针对内存实时数据的上报和本地持久化数据上报两个部分,分别介绍一下它们的上报策略与实现方式:
内存埋点数据的实时上报
针对内存埋点数据的上报策略一般如下:
- 基于时间间隔:每隔 n秒(时间间隔可以根据公司的业务情况自定义)
- 基于数据条数:每累积 n条数据(条数可以自定义)
- 不间断实时上报,如果是低频率,数据量小,实时性要求高的数据可以不设限制
上述条件满足时,便会触发从内存中读取数据,并执行上传操作。Native可以创建了一个并发队列,H5会基于浏览器并发发送。
本地持久化数据的延迟上报
为了尽早的上传本地持久化埋点数据,以防用户卸载 App或者关闭浏览器造成本地数据的丢失,针对本地持久化数据的上传策略如下:
Native相关:
- App 冷启动
- App 进入前台
- App入后台
HTML5、Hybrid相关:
- localstorage,浏览器关闭埋点数据并不会被删除,如果用户再次访问,会启动上报
- 基于Native提供的bridge,让Native帮忙持久化数据,并在再次进入时,启动上报
这里也可以创建一个单独的串行队列,来实现对本地持久化数据的逐个上报。
共同学习,写下你的评论
评论加载中...
作者其他优质文章