携程机票埋点随着业务复杂度的增加而在做加法,先后上的埋点包括ctm、action、trace、pv、服务端埋点等五个大类,每个埋点均符合其时代属性,但现在规整起来其相互间存在一定的交叉,即使冗余但有些埋点一部分还存在价值,转移起来造成的数据问题谁都不想背锅,所以埋点一直在做加法。直至在app减size的大趋势下,才顺便把无效的埋点做部分清理。
接下来介绍的埋点在携程机票有其存在的意义,但并不代表是全局最优,如果刚开始埋点的童鞋,可以参考下面各埋点的优劣势,结合自身的需要来取其糟粕取其精华。
ubt是什么?
全称User Behavior Tracking system,是由携程首席科学家叶亚明(Eric Ye,前携程CTO)先生发起的一套数据框架,最早从online的埋点落入和上传机制体系开始,逐步扩展至无线端app/hybrid/h5,后又增加abtest体系,现在支持携程的众多分析项目。包括数据埋点的格式、上送契约、落库、ETL以及最后的报表数据,是数据体系的总称,本文主要对于ubt体系在携程机票的埋点应用以及指标应用做说明。
客户端埋点
客户端埋点:ctm,action,trace,pv
ctm埋点:
玩过GA(Google Analytics)的童鞋对utm埋点肯定不陌生,它以get方式记录页面来源,被广泛使用营销活动的收益结算,Ctripのutm即为ctm,主要用于online和h5平台,不仅对落地页面的uv评估,同时需要根据规则计算其转化。因ctm只向后传递一次,未能直接关联创单(或者hybrid页面带到native页面面临中断)。
以机票特价页面为例,通常会根据同一天访问过特价首页的vid、sid来关联同一session的下单行为,且下单时间在页面访问时间之后,记为间接订单;在此基础上再限制访问特价页面的出发到达城市(从url截取)与订单对应,并限制下单前至最近一次访问特价页面之间未再次到访过首页(排除看完特价页面后从首页主流程正常下单的情况),记为直接订单。间接订单的含义是计算特价页面影响的用户下单意愿的程度,而直接订单是计算从特价页面而下单情况。正常情况下都是以直接订单为主要指标,间接订单作为参考指标。
pv埋点:
PV埋点因存在时间最久、埋点方式最简单(调用logpage方法发送pageid),所以被接受程度最高,同时也作为新上埋点验证丢失率的基石数据。app页面实现方式有native/hybrid/rn,其均申请独立pageid,对于计算页面性能影响不大(除了停留时间)。
报表合作机制:作为基础数据,新页面上线第二天就需要在基础报表UIP中查到(BI域数据T+1)。数据流为,新页面在上线之前开发童鞋会在公司的资源平台cms申请pageid,在页面加载的时候调用logpage接口上传pageid,行为数据经ETL落入hive库,经过清洗(去爬虫、去测试账号等),统计结果数据进入sqlserver,基础报表平台读取数据做汇总展示。其中筛选字段可以通过channelid来将机票页面区分。整个流程数据流不需要人工干预,完整的流程保证最小的人力和最快的效率。
页面基础指标:在数据报表中每个页面维度会有UV、visits、PV、退出次数、页面停留时间。visits代表session/会话数,退出次数具体释义请参考百度。页面停留时间,是该页面与下一面的starttime之差,一般取中位数(屏蔽异常值)。
业务影响uv:携程机票首页是区分国际和国内的(pageid不同),如果用户进入时是”北京“->"上海",则为国内机票的首页,切换到达城市为”墨尔本“时候,则为国际机票的首页。如果用户上一次是购买的国内商务出行的机票,本次想搜出国玩的机票,进来被默认是记忆上一次的国内机票首页,这样国内首页的uv将被多计算一遍,计算结果将高于实际数据,所以在计算机票主流程转化率的时候,都是从列表页作为起点。
action点击/埋点:
点击埋点平台区别较大,按照native、hybrid、online顺序说明
native埋点
埋点格式:为c_****,比如搜索页面是c_search,c代表click,后面为名称的英文简称,有开发人员自行定义。点击埋点的hive表内有pageid字段,命名时只要保证同一页面无重复名称即可。
埋点流程:app的native默认是有点击按钮即埋点,除非是pm特殊指定埋点附加信息(比如列表页记录筛选N次,但不记录筛选内容,如果需要记录筛选内容,需PM在PRD中说明)。因为native发布周期平均一个月,在之前曾遇到过重大问题没有及时解决因其领导高度重视,故决定今后所有点击一律埋点,逐步形成习惯。
报表数据流:这个报表暂时还没有上公司的cms系统,现在前台产品在维护其埋点简称和中文名称,由bi来调用,生成每天T+1的报表。后期考虑维护进入cms系统,像pv表一样进入全自动流程
报表字段:点击的报表是计算点击量(PV)、点击用户量(UV)、页面用户量(页面UV),点击uv比(点击UV/页面UV),人均点击次数(点击pv/点击UV)。虽然指标很简单呢,但是如果是跨BU或跨公司来核对数据,需要对比计算标准,曾经在和友商核对数据的过程之红,因对方是服务端埋点、根据服务请求来计算pv;我方是客户端埋点、根据客户端页面刷新计算pv,导致人均pv数据明显对不上,后来经过face to face的沟通才发现虽然同样说pv,但计算方式明显不同。
hybrid埋点
起源:hybrid埋点在2016年9月份以前并没有统一的埋点格式,不同的业务开发团队采用的js不完全相同,经过多方push统一一套,因speed处是点击名称,又俗称“speed”埋点。
报表数据流:speed埋点因均为中文,所以不需要人工维护维表,bi对结果表进行distinct即可生成点击筛选框。但这需要开发在speed处不可添加变量字段,否则下拉列表将会是一个灾难。
解决的业务问题:speed埋点包含订单信息,以hybrid订单详情页为例,我们可以通过orderid的信息将用户在订单详情页的行为和来电行为关联起来,如果用户在订单详情页上点击“退票”操作后当天来电“退票”,说明该按钮没有完全解决客户问题,可以在这个点上深挖需求,改进体验。在快速迭代页面的过程中,关注每个功能的点击后来电的比例,来深究每个页面细节,,对于快速迭代、精细化数据运营非常有帮助。
面对的挑战:因每次上传内容较多,包含系统自带信息,比如设备型号、user-agent和报错埋点信息等,导致用户流量消耗较大,待逐步改进。
online埋点
online埋点采用比较节省流量的方式,即在页面离开(包括进入下一个页面和当前页面刷新)的时候,将页面上所有的点击信息以{点击名称:点击数量}的json格式发送,这样可以节省流量,但是对于orderid等的记录就会缺失,如果增加额外信息需要改变结构,有利有弊。
trace埋点:
bi分析人员希望每个埋点都可以从开始带到创单,这样计算转化率就会比较方便;但开发认为每个页面埋点重复劳动、浪费时间和精力,而且有可能会影响页面加载速度。为了解决这个问题,推出了trace埋点,这个埋点的特点是每个主流程页面仅有一个,但将所有的业务信息记录在案。
埋点格式:每个主流程页面均有trace埋点,在页面加载或离开时发送,由bi统一管理,app/online/h5格式基本一致,所有trace修改都需要经过bi的审核,主流程页面包括首页、列表页、中间页、填写页、完成页。
作用效果:可以根据业务属性来区分具体人群的行为转化,故又称“业务埋点”。比如在首页勾选儿童之后,通过这个"children"的标识位可以看到有儿童购票意愿的细分人群在各个主流程页面间的转化(该标志位只有回到首页重新取消勾选的时候才会刷新这个标识位,否则都是从首页一直带下去)。这样对于细分人群的体验改进效果具有可观测性。
服务端埋点
机票OTA承担航司很多政策任务,会在列表及中间页通过标签的形式来给客户不同产品体验,但这些政策标签能够带来多少销量的提升,以及如何决定其之间的相互影响,成为一个课题。于是在服务端从列表页开始,将所有的显示报文埋点记录下来。
效果:对于所有产品可以根据政策维度和航司维度进行筛选,通过展示转化比来观测各个阶段的转化,同时对于后台对应的政策业务人员可以发送针对性报表,各取所需,节省大量时间。后期将利用机器学习方法针对不同政策、价格和排序的相互关系进行测算,希望找到最优转化的显示方式。
指标理解
携程机票的埋点体系基本如上所列,能够清楚明白每种埋点的优劣势对于分析问题选用数据的时候非常有益。通过埋点反映出来的指标,尤其是二次计算指标,很多在网络上已经有详细定义和说明,我将就结合携程机票的应用以及复盘过程中的思考做一下说明,希望能有所启发。
数据关联:
关联需要注意的是,不同的埋点的缺失率是不相同的,以下的关联准则是经过作者在部门实践中的反复验证所得,不一定具备普适性。
行为和订单的关联,以app为例,关联同一人,行为主要是clientcode设备号,订单主要是uid,这两者之间通过临时订单表关联(在填写页创单的时候创建临时单),把clientcode、uid、orderid订单号记录下来(如果拆单的话,仅记录主订单),然后需要通过订单主表o_orders来把实际下单数据过滤出来,最后可以拿到clientcode在每个session中的下单记录以及uid映射。
行为和行为的关联,一般是通过clientcode,sid,pvid来定位同一个页面的行为,如果是核心数据,如订单号建议直接埋点,不建议通过关联拿到。尤其是在小众人群的匹配上,数据的缺失的基础上进行关联可能会造成数据异常波动。
数据缺失:
现状:公司的pv表的存在时间最久,而且埋点最简单,结构最稳定,所有的验证数据都是以pv表的数据为基准。经过验证下来,根据按天计算的uv数据,trace的埋点准确率在97%左右,服务端的埋点在103%左右。如果都是在同一类埋点的情况下计算转化率,分子分母是每个页面的uv,影响不大,但是跨埋点计算的时候,需要特别小心。在数量级明确之后,还存在数据格式的问题,尤其是string和int的转化,特殊字符造成的解析困难等,这些都需要在使用过程中不断验证,bi和开发相互磨合。
埋点的准确率受很多因素的影响,主要是不畅沟通带来的各方gap,最后体现在开发对埋点的重视程度不足。每个开发对于埋点的认识不同,对于埋点上送的逻辑也不尽相同,再加上心态不同可能导致结果也会差别很大。
常见的几个埋点问题:
不该触发的时候而被触发:hybrid页面曾遇到过只要是手指划过按钮埋点就被触发,导致新页面上线后点击数据异常暴增,其实是开发在判断触发事件的阈值设置错误,停留时间超过200ms以上才算点击,小于200ms算滑动,但是在上面那个例子中开发未做限制,导致问题。
埋点触发相互抑制:在一个新埋点上线后,发现一个毫不相关的点击数据下降明显,从业务上找不到原因,后来开发查找代码的时候发现,两个埋点的上送逻辑存在ifelse关系,只有一个被上传。
开发与埋点不是同一人导致逻辑异常:这主要存在于开发交接时候对于埋点的上送逻辑一般不太重视,所以在业务发生变化的时候,并没有及时更改埋点的逻辑,比如pm希望某个默认埋点的默认显示被记录,最早是由服务端直接下发,客户端不做筛选,所以客户端买点直接读取服务端下发内容,但一段时间后默认逻辑在客户端加一层个性化接口,埋点方式还是直接读取服务端内容,未做更改,导致数据一直异常,经过好长时间的努力才定位问题。
部门开发和框架之间的冲突:有时候部门开发逻辑做的很完整,但是被框架的一些逻辑所限制,被背黑锅。比如为了优化速度,hybrid页面在本地app打包的过程中有些文件已经放入,在hybrid请求的时候,有些文件优先以本地为主,而公共框架部门做了一些拦截,但业务的开发可能就存在没考虑到这层逻辑,埋点数据就会全部丢失。
开发对埋点的误解
为什么每个页面都要埋这么多点,难道不能通过关联来实现吗?
在开发本身的任务都很重的情况下,埋点相对次要,在不了解其意义的情况下,往往意愿不强,怨声载道。这就需要pm或者bi很清楚地知道哪些埋点数据一定要有,哪些是可有可无,同时在整个项目上的最终数据表现上跟开发童鞋分享数据,强化埋点的价值。另外对于开发童鞋本身比较关注的kpi,如页面性能埋点,包括报错信息、加载时间、白屏等,可以辅助其建立报表来增强对数据的关注度。
为什么埋点动不动就要增加,能不能一次性提好?
这是个历史性的难题,因为在分析问题的时候,维度在不断地细致化,而这些维度是在当初并没有想到的、或者说可能认为没有必要的埋点(没有必要的埋点不增加开发的工作量),但是问题发生之后就需要增加埋点,这也是需要与开发保持密切的沟通。
新老用户:
定义:从访问维度上看,该设备号历史上从未访问过携程app,则该设备为访问维度上的新用户;从订单维度上看,该uiv历史上从未在携程app上成功下单,则该设备为订单维度上的新用户。
uv的区别:从访问维度上看,是通过设备号vid/clientcode来看;从订单维度,是通过uid来看。
设备平台的区别:即使该uid在机票online上已下单,某天在app上第一次下单,则也被认定为app的下单新用户。
辩证关系:如果一个人是app平台的下单新用户,则该设备号一般为访问新用户(一般很少有人把自己手机借给别人登陆携程账号,因为如果是帮朋友代订可以用自己账号下单,如果有的话成为异常用户的概率比较高);一个设备号被认定为某天的app新用户,则该uid不一定是下单新用户(因为不一定下单,且有可能是该uid买了新手机。)携程机票是相对成熟的app,新老用户的比例基本保持动态平衡。
留存率/回购回访率:
回购率:季度回购率,机票是低频消费产品,回购率的比率经过长期观察发现季度的周期比较有指导意义。
回访率:月度回访率。
停留时间:
定义:该页面与pvid+1下一页面的starttime之差,计算方式一般采用中位数(规避异常值影响整体表现)。
session时长计算:首次搜索->下单时间、末次搜索->下单时间,反映用户决策时长的两个指标,计算方式为同一session。但机票的购买决策时间比较长,从起意到最后下单在一个session完成的比例比较低,未来考虑在跨session的情况下计算其时间,尽量接近真实的停留时间。
native和hybrid混用的停留时间之殇:停留时长的计算是利用pvid+1的页面与本页面的访问时间差来计算的(艾瑞在online端的访问时间是duration,表示激活时间,能够实际表示当前页面的停留时间),而如果native和内嵌hybrid(已申请pageid)先后加载的时候,填写页的停留时间其实就变成hybrid页面starttime-native页面的starttime,这中间的时间差其实是两页面加载的时间差,并不是用户真实的停留时间。
停留时间是否越短越好?(最好自己先思考一下再看我的回答)
对于携程机票的电商网站来讲,停留时间是一个辅助的指标,而非一个决定性的指标,需要和一些决定性的指标一起来推测用户的行为。
比如同样是填写页的停留时间变短,在填写页之后的转化率上升的情况下,可以理解为该页面让用户非常放心,用户需要填写和核对的信息很少,对携程的网站非常熟悉和自信,下单迅速,这是一件正向的事情;
而如果是填写页之后的转化率下降,就有可能是页面冗余信息很多,用户想关注的信息没有找到,或者造成用户反感的信息非常醒目,导致用户立即离开而没有下单,这就成为一件棘手的事情。结合业务可能会找到很多原因,但有一点可以肯定,单纯追求停留时间的上升或者下降是没有意义的,TA需要核心指标一起来定位原因。
行为流可视化的必要性:
可以建立每个用户的行为流表,方便pm根据uid、手机号等常用字段可以搜索到用户的页面和点击行为流,方便查找问题以及找到问题解决的灵感。因为解决问题是从特殊到一般的过程,可以通过行为流找到灵感,然后用sql来验证是否具有普适性,分析能力螺旋式上升的过程。
在埋点新上线测试环境进行对比,实际看到埋点的数据格式是否符合预期。
附录
vid/clientcode/clientid:设备标识字段,vid应用于online和h5(受浏览器和cookie限制,换浏览器或清除cookie之后会更新vid),clientcode代表app/native和hybrid(仅与设备有关,在不换设备的情况下标识唯一)
sid:sessionid,又称为会话id,以online为例,同一设备访问同一网站30min之内为同一session。
pvid:pv的计数,同一用户在一天之内的携程页面访问pv从1开始标识,记录该人当天内的所有访问页面的先后顺序,再根据30min来切session。
starttime:事件发生时间,在pv表指页面浏览时间,在action表指按钮触发时间。
UV:在考虑行为的时候都用设备号来标识,在考虑订单的额时候都用uid来标识。
总结
携程市值从2014年的60亿到2016年的140亿美金,其中2016年机票的贡献利润超过40%,快速发展的业务必然需要大量的数据作支撑来推进整体向前发展,而发展的问题需要通过发展来解决。整体埋点体系其实比较复杂,其中的困难也不必多说。在整体趋势下,我一直秉承两个原则:
用户产生交互的埋点一般放在前端,因为客户端离用户最近,且有些逻辑是放在客户端,点击后不一定都会发送服务;而服务端是以展示为主,可以记录整个下发的报文数据,详细分析显示转化比。
概念非常复杂时,将相似的概念放在一起对比理解,防止概念混淆,比如退出率和跳出率;UV数/会话数/PV数;回购率和回访率等。
【本文为51CTO专栏作者“李宁”的原创稿件,转载请通过51CTO联系作者获取授权】