代码埋点,并且阐述我们自己对于这些技术的理

作者: 前端  发布:2019-11-20

揭开JS无埋点技术的神秘面纱

2018/07/09 · JavaScript · 埋点

原文出处: UncleChen   

在这篇文章里面,我们会对数据采集的一些基本概念进行阐述,然后,会针对目前市面上新增的一些前端埋点技术,如可视化埋点与“无埋点”的技术细节做一个具体的介绍,并且阐述我们自己对于这些技术的理解和认识。

由于工作安排原因,有幸二次接触产品运营的埋点任务。二次埋点发现自身对埋点机理未彻底弄清、明晰,因此整理了部分工作中的笔记及相关资料。如有错误之处,望请不吝赐教。

埋点技术简介

埋点就是数据收集,数据采集是大数据核心要素,方式也不尽相同,移动端常见的埋点技术有3种:代码埋点,可视化埋点,无埋点。

一、背景

相信很多人都接触过“埋点”这个概念,无论是前端还是后端开发,我们都可以使用这门技术来生产出一些运营性质的原始数据(接口耗时、程序安装/启动、用户交互行为等等),然后分析它们得到一些抽象指标(例如留存率、转化率),进而决定产品运营或者代码优化的方向。现在业界有许多比较知名数据平台,比如Google Analytics、Facebook Pixel、Mixpanel、GrowingIO、诸葛IO、TalkingData、神策数据等数不胜数一大票,这些平台有单纯做数据分析的,也有服务于特定领域例如广告监测转化的,都提供了多端(Android、iOS、Web、小程序、ReactNative)的埋点SDK和比较全面的BI服务。这一两年,不少平台都开始宣传一种叫“无埋点”的技术,下面以Web端为例,揭开它的神秘面纱。

1. 数据采集是核心问题

一个典型的数据平台,对于数据的处理,是由如下的5个步骤组成的:

图片 1

其中,我们认为,第一个步骤,也即数据采集是最核心的问题。数据采集是否丰富,采集的数据是否准确,采集是否及时,都直接影响整个数据平台的应用的效果。

在确定数据采集方案时应该遵循的两个基本原则:

优先在后端收集数据;

属性尽可能采集全面。

虽然我们之前已经详细描述过前端埋点的一些问题。例如,需要等待网络情况良好才能发送数据,需要积攒一定的量才发送数据,需要在本地暂存而本地暂存空间有限等一系列在数据传输性和数据可靠性上的一些问题。但是,前端埋点毕竟有一些后端采集数据所无法替代的地方,例如,分析前端界面设计是否合理,分析一些在与后端没有交互的前端行为等,还是必须采用前端埋点方案的。前端埋点作为一个比较成熟并且被广泛采用的数据接入手段,Sensors Analytics 也提供了一系列相应的解决方案。因此,在这里,我们觉得有必要详细介绍一下目前市面上主流的前端埋点方案的技术细节,并且结合我们的产品,来阐述我们对于这些埋点方案的一些看法。

本文将着重讨论对数据的埋点方式和上报收集,而非对数据的分析。前者对于现行使用的方式有较为统一的认识,后者数据分析在不同行业、企业有特定独立的规则,又由于企业保密性原因,在此不撰写了。

代码埋点:

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

优点:精准控制, 准确的发送数据,可以自定义事件、属性,传递丰富的数据到服务端;缺点:埋点代价比较大,每一个控件的埋点都需要添加相应的代码,不仅工作量大,而且限定了必须是技术人员才能完成;其次是更新的代价比较大,每一次更新埋点方案,都必须改代码,然后通过各个应用市场进行分发,并且总会有相当多数量的用户不喜欢更新APP,这样埋点代码也就得不到更新了。

二、什么是无埋点?

“无埋点”在国外一些平台被叫做Codeless Tracking,顾名思义就是可以写“更少”的埋点代码。而“代码埋点”一般需要开发人员编写代码,监听某个html元素的产生的事件,然后调用上报数据的接口,发送数据。而无埋点则可以由非技术人员(例如运营、产品),在可视化的工具中作出配置,然后就可以将html元素中产生的行为上报到后台。下面是Mixpanel平台的可视化工具的截图。

图片 2

在这个工具里,需要首先输入页面的url,页面加载完成后,会出现可视化配置的工具条。点击创建事件,就可以进入元素选择模式,用鼠标点击页面上的某个元素(例如button、a这些element),就可以在弹出的对话框里面,设置这个事件的名称(比如叫TEST)。保存这个配置之后,如果页面在浏览器中被浏览,刚才配置的那个按钮发生点击时,就会向后台上报一个TEST事件。我们还可以设置上报TEST事件的时候,带上一些属性(properties),这些属性同样也是在页面中用鼠标去选择,然后保存起来的。

看到这里,首先从产品层面上,我们比较具体的了解到“无埋点”到底是干什么的了,无埋点就是用可视化工具配置页面中需要被监测的元素,并设置这个元素产生行为的时候需要上报的数据。但是还有非常关键的一点必须提到,要让“无埋点”工作起来,页面里面还是必须嵌入了一段JS SDK的基础代码,只是不需要再去调用SDK具体的数据上报接口罢了。

所以,“无埋点”技术的关键是:

  • 操作可视化配置工具,保存配置
  • SDK基础代码如何根据配置上报行为

下面介绍一下如何实现这两个关键。

2. 前端埋点技术介绍

目前常见的前端埋点技术,有三类:在某个控件操作发生时通过预先写好的代码来发数据的代码埋点;通过可视化界面配置控件操作与事件发生关系的可视化埋点;先收集所有数据再在后端筛选需要分析的对象的“无埋点”。下面,我们分别对这三种方案进行介绍,然后再阐述我们的观点。

2.1 代码埋点

代码埋点出现的时间很早了,在 Google Analytics 年代,就已经出现了类似的方案了。目前,国内的主要第三方数据分析服务商,如百度统计、友盟、TalkingData 等都提供了这一方案。Sensors Analytics 也一样提供了 iOS、Android、Web 等主流平台的代码埋点方案。

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

下面,我们看友盟提供的两个例子。

第一个例子是在使用者的某个 Android APP 里面,统计某个由 Activity 构成的页面的访问次数,下面是友盟官方给出的例子:

public void onResume() {

      super.onResume();

              MobclickAgent.onPageStart("SplashScreen"); //统计页面(仅有Activity的应用中SDK自动调用,不需要单独写。"SplashScreen"为页面名称,可自定义)

    MobclickAgent.onResume(this);          //统计时长

}

public void onPause() {
      super.onPause();
    MobclickAgent.onPageEnd("SplashScreen"); // (仅有Activity的应用中SDK自动调用,不需要单独写)保证 onPageEnd 在onPause 之前调用,因为 onPause 中会保存信息。"SplashScreen"为页面名称,可自定义    MobclickAgent.onPause(this);
}

这个例子其实非常简单,就是在 Activity 控件相应的触发器函数里面,调用友盟提供的接口统计数据即可。

第二个例子稍微复杂点,它不再是统计页面访问这样一个默认的事件,而是统计一个自定义事件。例如,一个电商APP,在用户点击“购买”按钮时,想统计“购买”这个自定义事件的相应信息,那么,可以使用下面的代码:

HashMapmap = new HashMap();

map.put("type","book");

map.put("quantity","3");

MobclickAgent.onEvent(mContext, "purchase", map);

必须说明的是,友盟归根结底还是一个统计工具,并没有提供完整的多维分析功能,姑且不算数据传输的时效性以及对自定义属性上的各种限制,仅仅是为了统计某个数值,友盟还要单独区分出“计数事件”和“计算事件”,这一点上,就远远不如 Sensors Analytics 的灵活了。

从上面这两个例子可以看出,代码埋点的优点是一方面使用者控制精准,可以非常精确地选择什么时候发送数据;同时使用者可以比较方便地设置自定义属性、自定义事件,传递比较丰富的数据到服务端。

当然,代码埋点也有一些劣势。首先,埋点代价比较大,每一个控件的埋点都需要添加相应的代码,不仅工作量大,而且限定了必须是技术人员才能完成;其次是更新的代价比较大,每一次更新埋点方案,都必须改代码,然后通过各个应用市场进行分发,并且总会有相当多数量的用户不喜欢更新APP,这样埋点代码也就得不到更新了;最后,就是所有前端埋点方案都会面临的数据传输时效性和可靠性的问题了,这个问题就只能通过在后端收集数据来解决了。

2.2 可视化埋点

从前端埋点到可视化埋点其实是一个非常顺理成章的演进。既然埋点代价大,每一个埋点都需要写代码,那么,就参考 Visual Studio 等一系列现代 IDE 的做法,用可视化交互手段来代替写代码即可;既然每次埋点更新都需要等待APP的更新,那么,就参考现在很多手游的做法,把核心代码和配置、资源分开,在APP启动的时候通过网络更新配置和资源即可。

正是出于这种自然而然的做法,在国外,以 Mixpanel 为首的数据分析服务商,都相继提供了可视化埋点的方案,Mixpanel将之称作为 codeless。而国内的 TalkingData、诸葛IO 等也都提供了类似的技术手段。 顺带一提,Sensors Analytics 在1.3版本的更新中,也已经给使用者提供可视化埋点方案,以降低使用者的数据接入成本。

特别需要强调的是,Mixpanel 非常无私地开源了它们的iOS 和 Android 端的 SDK 的源代码,我们在开发中也参考了它们的贡献,并且也贡献了一些 bug 的提交,非常感谢 Mixpanel 对整个领域的贡献。

2.2.1 iOS 和 Android 平台的可视化埋点

下图是演示一个简单的 iOS SDK 使用 Mixpanel 的 codeless 埋点功能:

图片 3

从这个界面可以看出,使用起来还是非常简单的,点击某个支持的控件类型的实例,这个例子中是右上角的刷新按钮,然后在弹出的窗口中,设置点击这个按钮是发送 “Refresh” 事件。然后点击 Deploy 按钮,把这个配置下发下去。那么,所有安装有嵌入了 Mixpanel 的 SDK 的这个 APP ,则都会在 APP 启动时或者定时获取相应的配置。以后,真实的用户使用时,点击这个按钮,就会真正地发送 “Refresh” 事件到后端了。

下面我们以 iOS 端为例,进一步阐述可视化埋点的实现细节。

在嵌入了 SDK 的 APP 开启可视化埋点模式,与后端联通时,SDK 会应后端的要求,定期(例如每秒)做一次截图,而 SDK 在为 App 截图的同时,会从 keyWindow 对象开始进行遍历它的subviews(),得到当前视图下所有 UIView、UIResponder 对象的层级关系。对于屏幕上的任何一个UIView对象,如 Button、Textfield 等,它都有一条唯一的从 keyWindow 到它的路径,这个路径上每个节点,都由 ClassName、它是父节点的第几个subview、.text()等属性的值等标识。相对于父节点的坐标、长宽高等可视化方面的信息,是作为这个节点的属性存在。

服务端根据截屏和可视化信息来重新进行页面渲染,并且根据控件的类型,来识别哪些控件是可以增加可埋点的,并且将之标识出来。

当使用者在后台的截屏画面上点击了某个可埋点的控件时,后台会要求使用者做一些事件关联方面的配置,并且将配置信息进行保存和部署。

SDK 在启动或者例行轮询时拿到这些配置信息,则会通过.addTarget:action:forControlEvents:接口,为每个关联的控件添加的点击或者编辑行为的监听,并且在回掉函数里面调用 Sensors Analytics SDK 的接口发送相应事件的 track 信息。

整个 iOS 端的埋点的流程图,如下图所示:

图片 4

Android 端的可视化埋点方案,与 iOS 端基本一致。

必须说明的是,上面描述的这一套可视化埋点的配置方案,其实也可以让开发者在 iOS 或者 Android 的可视化 IDE 里面完成,但是考虑到可视化埋点主要面临的是非技术人员,所以最终业内都采用了 Mixpanel 的这种后台截屏操作的方案。

2.2.2 Web 端的可视化埋点

Mixpanel 没有提供 Web 端的可视化埋点方案,在这里,我们以 Sensors Analytics 的 Web 端可视化埋点方案来举例:

图片 5

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

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

附带一提,虽然 Mixpanel 比较早就推出了可视化埋点方案,但是却一直没有重点宣传,并且也并不是它们的推荐数据接入方案,这种做法也是与 Mixpanel 一直强调的 "Actions speak louder than page views." 是一致的。

2.3 “无埋点”

与可视化埋点一样,“无埋点”这个方案也出来的比较早,Heap作为一个第三方数据分析服务商,在2013年就已经推出了“无埋点”这个技术方案。而如果不局限于第三方,百度在2009年就已经有了“点击猴子”这个技术,用无埋点的方案分析一个页面各个元素的点击情况;在2011年,百度质量部也推出了一项内部服务,用以录制安卓 App 的全部操作,并且进行回放,以便找出 App 崩溃的原因;而豌豆荚大约也在2013年左右,在自己的 App 内部,添加了对所有控件的操作情况的记录。第三方数据分析服务GrowingIO 在2015年,也推出了类似于 Heap 的服务。

下图是一个使用 Heap 的例子:

图片 6

从界面上看,和可视化埋点很像。而从实际的实现上看,二者的区别就是可视化埋点先通过界面配置哪些控件的操作数据需要收集;“无埋点”则是先尽可能收集所有的控件的操作数据,然后再通过界面配置哪些数据需要在系统里面进行分析。

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

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

2.4 各种不同采集方案的数据获取能力的对比

在前面,我们已经介绍了代码埋点、可视化埋点、“无埋点”三种前端埋点方案,而也强调了我们一直推荐在后端采集数据。因此,在这里,我们觉得有必要比较一些可视化埋点、代码埋点与后端采集数据三种方案在数据获取能力上的差异,“无埋点”的数据获取能力与可视化埋点基本相当,在这里不再单独罗列。

我们以京东的一个订单提交页面为例来进行对比:

图片 7

对于可视化埋点,在这个地方,基本只能采集到某时某刻某人提交了一个订单;对于前端代码埋点,则还能拿到订单金额、商品名称、用户级别等在前端有记录的一些信息;而如果在后端接入数据,则还能拿到商品库存、商品成本、用户风险级别等只在后端有记录的一些信息。

由此可以看出,可视化埋点虽然使用和部署比较简单,但是在数据获取能力上相比代码埋点还有一定的劣势;而前端埋点天然的劣势,则是拿不到在前端不保存的信息。这也是为什么,我们一直推崇后端数据采集数据这一方案的重要原因。

一、埋点是什么

定时、定点地在目标应用/网站上采集数据,将数据以日志的方式上报至服务器的过程。

可视化埋点:

用可视化的方法来代替代码埋点把代码和业务逻辑分开。举个例子,像游戏公司现在开发会把资源文件和配置信息和代码分开,用户更新游戏只要下载资源文件和配置就可以了。

在国外,以 Mixpanel 为首的数据分析服务商,都相继提供了可视化埋点的方案,Mixpanel将之称作为 codeless。而国内的 TalkingData、诸葛IO 等也都提供了类似的技术手段。

三、关键技术

3. 我们的观点

Sensors Analytics 一贯认为,数据采集是构建数据平台的核心要素。为了方便使用者采集数据,我们完全开放了全功能的数据接入 API,基于 API 封装了代码埋点和可视化埋点两种前端接入方案,并且提供了 PHP、Java、Python 等常见后端语言的 SDK 以方便在后端接入数据,同时,为了满足使用者导入已有文件或者格式化数据的需要,我们也封装了 LogAgent、BatchImporter、FormatImporter 等各式导入工具。同时为了降低使用者的安全方面的疑虑,并且回馈业内,我们的相关 SDK 的代码也在github上全部开源,可视化埋点的具体实现的代码会随着1.3版本的发布 release,敬请期待。

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

仅仅是分析UV、PV、点击量等基本指标,可以选择代码埋点或者可视化埋点等前端埋点方案;

精细化分析核心转化流程,则可能需要利用后端 SDK 或者 LogAgent 接入后端日志;

活动/新功能快速上线迭代时的效果评估,则可以利用可视化埋点快速完成;

对客服服务质量的考核,或者不同快递在不同省份运送不同品类产品的速度的比较,则需要使用后端 SDK 来对接第三方系统以便导入数据。

一个产品首次使用 Sensors Analytics 时,初期采用可视化埋点方案,快速完成部署,以便快速评估分析效果,做出快速决策;而对可视化埋点得到的数据,在分析解读后,再针对性地逐步采用其它数据采集方案,获取更详尽、更全面的数据分析结果。

PV、UV、VV、IP的意思

经常分析数据,我们都知道PV、UV、VV、独立IP数是网站分析中最基础、最常见的指标。那么你清楚各指标的具体意义吗?

1.来访次数/访问次数(VV):

VV=VisitView(访问次数):记录所有访客1天内访问了多少次你的网站,相同的访客有可能多次访问您的网站。

从访客来到您网站到最终关闭网站的所有页面离开,计为1次访问。若访客连续30分钟没有新开和刷新页面,或者访客关闭了浏览器,则被计算为本次访问结束。那么上图A就是从搜索词“宫外孕有什么症状”进入网站的访问次数329.

2.独立访客(UV):

1天内相同访客多次访问网站,只计算为1个独立访客。上图数据就是1天内从搜索词“宫外孕有什么症状”进入网站的独立访客294.

3.浏览次数(PV):即通常说的PV(PageView)值,用户每打开1个网站页面,记录1个PV。用户多次打开同一页面PV累计多次。用以衡量网站用户访问的网页数量。上图数据意思从搜索词“宫外孕有什么症状”进入网站的访客浏览次数是360.

4.ip:1天(00:00-24:00)之内,访问网站的不重复IP数。一天内相同IP地址多次访问网站只被计算1次。

同一IP无论访问了几个页面,独立IP数均为1访问次数,上图数据意思从搜索词“宫外孕有什么症状”进入网站的访客ip是295.

PV、UV、VV、IP作为网站分析中最常见的基础指标,能够从宏观概括性地衡量网站的整体运营状况,也是监测网站运营是否正常的最直观的指标。基础指标数据了解清楚了,那么一些更重要的数据分析起来就明朗多了!

二、为什么要埋点

企业方获得用户在产品上的使用数据,分析后利于产品优化迭代。

无埋点:

和可视化埋点类似,二者的区别是可视化埋点通过界面配置来决定要统计的事件来源,而无埋点是经可能把所有能收集的数据全部收集一遍,再通过后台配置要留下哪些统计分析。

缺点是:不能自定义不够灵活,统计范围广量大会给服务器和网络传输带来负担。


1. 基础代码

和代码埋点一样,要让“无埋点”工作起来,网页里也必须有一段“基础代码”。

JavaScript

<!-- start Mixpanel --><script type="text/javascript">(function(e,a){if(!a.__SV){var b=window;try{var c,l,i,j=b.location,g=j.hash;c=function(a,b){return(l=a.match(RegExp(b+"=([^&]*)")))?l[1]:null};g&&c(g,"state")&&(i=JSON.parse(decodeURIComponent(c(g,"state"))),"mpeditor"===i.action&&(b.sessionStorage.setItem("_mpcehash",g),history.replaceState(i.desiredHash||"",e.title,j.pathname+j.search)))}catch(m){}var k,h;window.mixpanel=a;a._i=[];a.init=function(b,c,f){function e(b,a){var c=a.split(".");2==c.length&&(b=b[c[0]],a=c[1]);b[a]=function(){b.push([a].concat(Array.prototype.slice.call(arguments, 0)))}}var d=a;"undefined"!==typeof f?d=a[f]=[]:f="mixpanel";d.people=d.people||[];d.toString=function(b){var a="mixpanel";"mixpanel"!==f&&(a+="."+f);b||(a+=" (stub)");return a};d.people.toString=function(){return d.toString(1)+".people (stub)"};k="disable time_event track track_pageview track_links track_forms register register_once alias unregister identify name_tag set_config reset opt_in_tracking opt_out_tracking has_opted_in_tracking has_opted_out_tracking clear_opt_in_out_tracking people.set people.set_once people.unset people.increment people.append people.union people.track_charge people.clear_charges people.delete_user".split(" "); for(h=0;h<k.length;h++)e(d,k[h]);a._i.push([b,c,f])};a.__SV=1.2;b=e.createElement("script");b.type="text/javascript";b.async=!0;b.src="undefined"!==typeof MIXPANEL_CUSTOM_LIB_URL?MIXPANEL_CUSTOM_LIB_URL:"file:"===e.location.protocol&&"//cdn4.mxpnl.com/libs/mixpanel-2-latest.min.js".match(/^///)?"]); mixpanel.init("46042714e64a7536dde6f02af1aec923");</script><!-- end Mixpanel -->

1
2
3
4
<!-- start Mixpanel --><script type="text/javascript">(function(e,a){if(!a.__SV){var b=window;try{var c,l,i,j=b.location,g=j.hash;c=function(a,b){return(l=a.match(RegExp(b+"=([^&]*)")))?l[1]:null};g&&c(g,"state")&&(i=JSON.parse(decodeURIComponent(c(g,"state"))),"mpeditor"===i.action&&(b.sessionStorage.setItem("_mpcehash",g),history.replaceState(i.desiredHash||"",e.title,j.pathname+j.search)))}catch(m){}var k,h;window.mixpanel=a;a._i=[];a.init=function(b,c,f){function e(b,a){var c=a.split(".");2==c.length&&(b=b[c[0]],a=c[1]);b[a]=function(){b.push([a].concat(Array.prototype.slice.call(arguments,
0)))}}var d=a;"undefined"!==typeof f?d=a[f]=[]:f="mixpanel";d.people=d.people||[];d.toString=function(b){var a="mixpanel";"mixpanel"!==f&&(a+="."+f);b||(a+=" (stub)");return a};d.people.toString=function(){return d.toString(1)+".people (stub)"};k="disable time_event track track_pageview track_links track_forms register register_once alias unregister identify name_tag set_config reset opt_in_tracking opt_out_tracking has_opted_in_tracking has_opted_out_tracking clear_opt_in_out_tracking people.set people.set_once people.unset people.increment people.append people.union people.track_charge people.clear_charges people.delete_user".split(" ");
for(h=0;h<k.length;h++)e(d,k[h]);a._i.push([b,c,f])};a.__SV=1.2;b=e.createElement("script");b.type="text/javascript";b.async=!0;b.src="undefined"!==typeof MIXPANEL_CUSTOM_LIB_URL?MIXPANEL_CUSTOM_LIB_URL:"file:"===e.location.protocol&&"//cdn4.mxpnl.com/libs/mixpanel-2-latest.min.js".match(/^///)?"https://cdn4.mxpnl.com/libs/mixpanel-2-latest.min.js":"//cdn4.mxpnl.com/libs/mixpanel-2-latest.min.js";c=e.getElementsByTagName("script")[0];c.parentNode.insertBefore(b,c)}})(document,window.mixpanel||[]);
mixpanel.init("46042714e64a7536dde6f02af1aec923");</script><!-- end Mixpanel -->

上面是Mixpanel平台的基础代码,不同平台家的这段基础代码,大同小异,都是一段IIFE形式的、压缩过的js代码,执行完成之后,在head里面插入了一个新的script标签,异步去下载真正的核心SDK代码下来工作。所以并不是基础代码可以根据配置上报行为,而是基础代码会下载一段“更大”的SDK核心代码,这段代码才是SDK真正的功能实现。

这样子做的好处是,基础代码很短,加载的时候不会影响到网页的性能,而且核心SDK代码的更新也不需要用户去更新这段基础代码。

三、埋点有哪些方式

MixPanel项目准备

登录官方主页www.mixpanel.com,创建一个app项目:

图片 8

选项setting->project settings 获取你的token

图片 9

拿到token后即可接入SDK了,在 appdelegate  完成代码集成步骤:

[[NSUserDefaults standardUserDefaults] registerDefaults:@{@"mixpanelToken": MIXPANEL_TOKEN}];

    NSString *mixpanelToken = [[NSUserDefaults standardUserDefaults] stringForKey:@"mixpanelToken"];

之后选择setting->codeless tracking 进入web可视化调试页面,通过websocket连接手机服务,保持通信,这就能可视化埋点了。(要选中对应你的设备才能连接上,比如模拟器option+左键对应的web端模拟器设备选项,默认的是真机要切换一下)

图片 10

图片 11


2. 页面的唯一标识

在配置元素行为的时候,需要唯一标识一个页面,这样才能保证A页面的配置,不会下发给在B页面,不会导致B页面产生出A页面里配置的行为。在Web里面标识页面靠的是url,url由protocol、domain、port、path和参数组成,存储配置的时候要将url的参数提出来再存。而url的参数位置是可以变化的,比如urlA(http://a.b.com/c.html?pa=1&pb=2)和urlB(http://a.b.com/c.html?pb=2&pa=1)虽然urlA !== urlB,但是其实它们是一个页面。

(1) 代码埋点

原理:在应用App或界面初始化时,初始化埋点的SDK,在触发某个节点(如事件/页面)时调用SDK相应的方法,通过接口发送数据。通常为了减少用户上报数据时消耗过多流量,常见有两种解决方案:

(一) 进行数据映射(简化数据,不传具体参数值,而是根据MAP-KEY映射关系),如应用端发送(0/0、1/)数据,由服务端将根据约定文档映射为(首页/模块一、第二个点击事件);

(二) 非即时发送数据,将多条数据压缩打包,等待网络状况良好、或定时(5min)发送至服务端。

优点:

个性化自定义,能够根据企业自身业务特性自定义属性、事件,定制化获取数据。

缺点:

(一) 人力成本高,埋点工程涉及到由运营-产品-前端-服务端-后台一系列所有数据团队,不同系统/版本不易管理,所有方法均需人工注入,数据收集后需由服务端进行分析;

(二) 版本更新前后,容易发生数据紊乱(若发生重要负责人离职,无相关文档沉淀,则可能造成“前功尽弃”的情况);

(三) 起步难,前期为简单计数;需要企业长期且稳定地完善、不断根据业务更新。

事件点选和绑定

mixpanel会把手机屏幕做截图处理通过websocket发到web端接受展示在屏幕上,而web端还要做绘制控件操作,让屏幕的按钮可点选可绑定。

图片 12

可以看到绑定后的事件可编辑可删除,修改完后点击右下角的deploy部署按钮即可生效。取消则直接断开socket通信并退出当前页面。


3. 元素的唯一标识

唯一标识页面后,接下来就要唯一标识页面里面的元素,这样才能保证A页面中配置的元素A1可以被SDK找到,从而监听它产生的事件。

在html里面,元素是以DOM Tree组织的,如果沿着元素A1出发,一直向上记录它的parent和它在parent中的index,直到根节点body,那么就可以得到元素A1在DOM Tree中的唯一路径。

html的元素还会拥有很多属性,例如css class、id可以用来定位元素。通过Chrome开发者工具可以看到Mixpanel的可视化工具在配置元素的时候,使用的是这个库来生成element的唯一标识的。而Github上还有这样的库,也可以生成元素在DOM Tree中的唯一标识。

此外,还有平台在标识元素的时候,采用了xpath,这也是一个思路。

(2) 可视化埋点(又称为框架化埋点)

原理:将核心代码与资源、配置分开,当应用App启动时从服务端更新配置和资源(plist),应用获知后,根据配置和部署信息相上报数据内容。

实现方式:

(一) 在需埋点的App中嵌入SDK,开启可视化埋点模式,并联通后台。嵌入的SDK根据后台要求,定时制作截图,制作截图时会将页面上所有对象进行遍历,遍历该页面上所有对象(如按钮、列表、View视图),获取其类名、属性、页面下坐标、长宽高等各方面信息;

(二) 应用将以上数据上传至后台,后台根据截屏和数据重新渲染页面,并且将可埋点的对象标识出来;

(三) 埋点使用者在截屏画面上选择相应需埋点的对象,后台根据埋点进行事件关联方面的配置,并将其保存和部署;

(四) 应用中的SDK在启动或例行轮询时下载配置信息,根据配置信息,对相应对象添加行为监听,根据行为向服务端发送相应数据。

下图截取神策数据的可视化埋点的后台操作截图作为说明。

优点:

解决了代码埋点人力成本和更新代价大的问题,只要在版本内有相应SDK,即不存在老版本迭代后无埋点问题;且对于不懂代码的产品运营,可通过后台可视化界面进行配置操作,并且生效。

缺点:

(一) 无法做到自定义获取数据,可视化埋点覆盖的功能有限;

(二) 企业针对SDK开发难度相比代码埋点大,使用第三方SDK资源则有共同通病,下文说明。

验证我们的埋点数据

点击我们的埋点按钮,在web端左上角会看见带着事件名称的标记,红色圈圈里有2发事件,一个是代码埋的和另一个可视化埋点都会通过界面反馈。

图片 13

4. 如何查找元素

上面说到元素可以有唯一标识,那么有了唯一标识,就可以利用它的原理,找到这个元素。有一个很好用的API是document.querySelector(),这个API可以根据CSS选择器找到对应的元素。此外,根据元素的标识方法,还可以使用document.getElementById()document.getElementByName()来实现元素的查找。

这里需要重点强调的是,如果页面在配置完成之后又发生了修改,导致DOM Tree发生变化,此时需要被监测的元素的唯一标识可能也会发生改变。很可能导致根据之前的配置无法找到该元素了,或者找到的并不是我们希望监测的元素,从而导致产生的事件数量发生比较明显的变化。为了数据的稳定性和准确性,应该设有相应的监测告警处理这种case,并提示用户去重新配置页面。我个人认为这是无埋点最大的缺点。

(3) 无埋点(全埋点)

原理:在App中嵌入SDK,做统一的“全埋点”,将应用App中尽可能多的数据采集下来,通过界面配置的方式对关键行为进行定义,对定义的数据进行分析。

实现方式:

在应用中嵌入SDK,通过可视化方式(即上文可视化埋点方式),针对对象进行定义,服务端对定义的数据进行分析,后台加以展现。

优点:

提供了埋点的“后悔药”(数据回溯问题),只要部署了SDK,数据便开始采集;可以自动获取很多启发性的信息,可以通过热力图向用户展示各个控件、事件点击的概率更大;便于使用者发现页面僵尸按钮等等。

缺点:

(一) 缺点与可视化埋点相同,未解决个性化自定义获取数据的问题,缺乏数据获取的灵活性;

(二) 企业针对SDK开发难度较大,一般由数据分析企业研发提供,使用第三方提供的埋点方案,有如下缺陷:

1、数据源丢失,应用上报的数据上传至第三方服务端,可能造成企业泄密或用户的关键数据丢失;

2、供应商数据丢包问题,无法根据应用特性进行改善。

其他功能有待探索

5. 标记元素时的高亮效果和可视化交互实现

这是一个比较细节的点,其实熟悉js的大牛们都知道,有无数种方式去实现鼠标移动到元素上时的类hover效果,点击元素后弹出一个对话框,让用户输入配置的信息也so easy。但是我想说的是,一旦我们采用向页面中动态添加元素的方式去实现可视化工具的交互界面,那么有可能会破坏掉页面原来的DOM Tree结构。从而导致生成元素唯一标识的时候出现误差,所以这里必须要好好处理,保证生成的元素标识不会受到影响。

我看到Mixpanel采用了CustomElementShadowDOM,把可视化工具所有的功能都用自定义的Web Component实现了,虽然目前只有Chrome支持Web Component,但是真的有点叼。。这样自定义的元素和交互不会对用户的网页DOM产生影响。当然,如果你的可视化工具实现做的很轻,比如只是将用户的网页放在一个iframe里面,大部分交互都交给iframe的parent页面去处理,那也可以在配置的时候,最小程度的破坏用户的网页了。

四、埋点上报的通用数据信息

指的是通用数据信息,只要是涉及到代码埋点,一般都会获取如下数据。一般是在应用启动时,将相关数据进行上报。(也有许多应用如QQ空间,所有的日志上报参数仍包含通用数据信息)

(一) 无限局域网地址(MAC地址):定义网卡地址,又称为物理地址、硬件地址,具有全球唯一性,用于定义网络设备的位置。

(二) 手机设备号(IMEI):移动设备国际识别码,是手机的唯一标识码。用于区分终端唯一性,对于用户去重有一定意义;与MAC地址协同使用。

(三) 终端系统/系统版本号:获取终端系统以及版本号,在查询某些版本上出现特定bug,具有一定辅助意义;(其他用途待发现补充)

(四) 应用版本号:有利于版本迭代控制,作为数据的标记;

(五) 网络状态:获取当前网络为3G/4G/wifi等,可针对用户人群所处的网络环境,针对性开发流量节省模式,或线下活动的wifi支持等;应用终端可做到网络状态更迭及时上报;

(六) GPS地址:通过应用端获得GPS地址授权获得,用于分析不同地域人群的使用习惯,有利于绘制用户人群画像;

(七) 用户ID:终端用户的唯一身份标识;

(八) 触发时间:应用/事件触发时间,根据时间维度来分析某页面/事件等数据信息;

a/btest:

用于给非技术人员(运营人员、测试、产品)做实验设计,仅仅只是在元素、控件的层面的a/btest。当产品稳定后,更换app的局部控件,如背景颜色,文案,大小等属性,它的目的是点击次数的提升,先从一部分实验样本进行测试,如果优化的好可大规模的投放。

图片 14

实验数据可保存


6. 配置工具中如何控制页面的跳转

当进入可视化配置状态时,我们可以让用户点击一个元素,然后弹一个对话框,让用户对这个元素进行配置。此时,如果这个元素本身的click行为是页面跳转呢?我们应该怎么处理?

这里本质上是一个交互设计的问题。在可视化配置工具中,应该有两种基本交互操作。一种是让用户选中某一个元素,进行配置;另一种,是让用户可以触发页面原有的行为。

为什么要有第二种交互?因为我们的工具肯定要支持用户进行二级页面的可视化配置对不对?或者说,用户的页面中可能会弹出一个对话框,对话框里面有一个按钮,用户对监测这个按钮,对它做配置,对不对?简单来说,就是用户页面中原有的点击行为,可能会导致页面结构产生变化,例如跳转,页面内弹出对话框等等。

那问题就好解了,除了点击,再设计一种交互来支持用户网页中原有的点击行为不就好了。用“右键点击”或者“按住shift+点击”之类都可以。反正不要再和网页默认的交互很容易产生冲突的方式就行。

最后再提一下,之前想很久没有想明白,如何能够能防止用户点击的时候页面产生跳转。后来才知道,DOM的事件流分三个阶段:捕获、目标、冒泡。所以为了避免用户的点击产身页面跳转,给document在捕获阶段加一个listener,拦截掉这个事件的继续分发就行了。

图片 15

简单的示例代码如下:

JavaScript

document.addEventListener('click', e => { // 如果是按住shift的点击,那么保持原有的行为 if (e.shiftKey) { return; } // 如果是单纯的点击,那么拦截分发 e.preventDefault(); e.stopImmediatePropagation(); // 获取元素的唯一标识,然后让用户进行配置等等 this._selectElement(e.target); }, true); // useCapture必须为true

1
2
3
4
5
6
7
8
9
10
11
document.addEventListener('click', e => {
  // 如果是按住shift的点击,那么保持原有的行为
  if (e.shiftKey) {
    return;
  }
  // 如果是单纯的点击,那么拦截分发
  e.preventDefault();
  e.stopImmediatePropagation();
  // 获取元素的唯一标识,然后让用户进行配置等等
  this._selectElement(e.target);
}, true); // useCapture必须为true

五、代码埋点的意义与注意tips

在如今“大数据”时代,任何一家想发展壮大的企业,在考虑使用第三方SDK数据产品的数据源丢失问题后,都会优先考虑自建数据团队进行代码埋点。获取埋点数据,监测并分析数据信息。因此作为产品运营,必须掌握代码埋点的相关技能,做到埋点项目的需求描述说明清楚全面,跟进项目、不断优化、提出分析优化。有如下问题需注意:

1.明确所需数据内容,尽可能表述清楚每一个点击/页面所需监测的数据。否则,失之毫厘谬以千里。举个栗子:

对于电商行业,监测搜索转化率最为正常不过。若在搜索筛选页要求上报搜索参数,实际研发可由服务端根据前端接口请求,在接口直接获取参数,无须让应用进行上报;若需获取的是由该搜索筛选页触发进入详情页,应用端在商品详情页上报搜索参数。二者就大有不同,服务端获取的搜索参数并非实际转化参数(后者获得),可能发生用户对搜索结果不满意而最终未形成转化的情况。因此需要二者数据进行纵向对比。

总而言之,获取每一个数据,须描述清细节,研发团队才能对其有针对的、最优处理方案。

2.向服务端明确说明每个指标的详细定义是什么,定义不清、不明,将导致最终数据分析结果的正确与否。比如最常见的PV(页面浏览量),不同的定义对最终后台显示的结果大有不同,对于用户进入该页面计为浏览量加一,或者用户进入该页,停留时长超过5s计为浏览量加一,不同定义方式,就会有不同的PV结果。

3.确定各上下级页面的埋点是否覆盖完全,若发现页面离开应用占比极高:极有可能是该页面的下一级页面未进行埋点,导致没有数据上报,服务端分析为离开应用。若发现了漏埋点的情况,尽管能在更新版本中补充,但老版本的数据就永远丢失。所以在埋点规划时,产品运营确保埋点事项无遗漏。

代码的构建方面

sdk 整体分几个模块,大致是按照业务逻辑划分的,总体感觉还算比较清晰

四、总结

可以看到“无埋点”并不是零侵入,用户的网页中依然需要加载SDK的代码(除非你是浏览器厂商,可以在加载网页的时候,给网页加inject基础代码)。只是每一个行为事件的上报代码不需要开发人员手动编写,而是由运营人员用可视化工具配置,所以叫它“可视化埋点”也许更加合适。我们知道数据采集是数据分析的基础和先决条件,数据采集做不好,其他的东西都是空中楼阁。

这里可以小结一下“无埋点”技术的优劣。无埋点的好处是技术成本低,对用户非常友好,不需要重新部署,配置完成就可以生效。但是其缺点也非常明显,不具有代码埋点的灵活性和深度,只能采集到用户肉眼可见的数据,无法获取内存里的数据,同时也无法适应页面结构的变化,所以在实际生产中,要选择性地在合适的地方使用无埋点技术。

多扯一点产品设计和技术方案的选择,产品上是否可以支持采集内存数据呢?当然可以,比如微信小程序的“自定义分析”,就可以支持上报页面data下面的属性,这时虽然同样是可视化配置,运营人员肯定不会知道代码里面的变量名字,必须得有开发人员参与配置才行。关于页面结构发生变化之后的数据丢失,也是有方案可以破的。比如Mixpanel平台的Codeless Tracking,实际上采集了页面中所有页面的点击事件上报,然后在后台再去根据用户的配置计算转化数量。这样做的好处就是如果页面变化后,用户接到告警,修改了配置,那么用于数据上报方案是全量的,所以平台是由能力将过去的数据回溯出来的。而上面我们说的根据配置下发,查找监测指定元素,再上报数据的方案属于按需上报,数据出现误差是无法回溯的。不过全量上报数据大家也知道,太不友好了,这个数据量太大,不仅前端消耗资源多,如果为了做数据回溯,后台的存储压力也会加大,而存储的数据大部分还是无效的,这个成本有点高了。

六、其他

(1) 个人使用过的第三方数据产品体验

(一) Umeng,阿里旗下的数据分析产品,通用性功能均有覆盖,在部分特定页面上有缺失,定制化弱,适合初创起步的企业应用。

(二) Google Analytics,个人使用体验较好,对个人网页、应用所需的数据埋点都能满足,对数据结果展示较为喜欢,缺点是需翻墙查看;

(三) 神策数据。位于上海的神策公司,可根据企业部署特定服务器,针对个性化定制,并且有对应业务员、开发工程师进行企业一对一对接,服务体验较为良好;但数据分析后台非工作范围内,未详细体验、研究过;

(四) 诸葛io,国内领先、先行的数据分析公司,2013年是国内首家最早推出无埋点方案,但有运营朋友说丢包较为严重,未确认翔实与否。

其他较为知名的数据产品:TalkingData、Mixpanel未使用过,希望有大神分享,或之后使用后补充。

最后的叮嘱,数据埋点团队一定要留好数据埋点的规范定义文档,若发生团队埋点相关负责人离职,就会形成大坑。

Ps:其他思考问题整理如下:

(1) 为什么上报的数据颗粒级最好是“原子”最小化上报而非关系链上报?

虽然关系链上报对于还原用户的真实操作非常方便,服务端根据用户访问的时间序列,将事件串联,一步步分析,对于关系跳转挖掘很是方便;但对于快速迭代的应用产品,一旦产品相关逻辑变动,则所有业务分析(服务端)、逻辑关系(前端)须重写,对于前端-服务端都将是巨大的人力投入,以及新老版本的数据关系链冲突问题。

(2) 需要有专门负责人长期且稳定对代码埋点方式进行“买单”

一旦数据进行埋点,且产品运营形成数据量化结果、以数据驱动决策的习惯后,则必须进行持续维护。因为数据埋点研发团队,需花费较高的人力资源;测试点位时,要求完整覆盖性测试,确保无遗漏。

source:

主要的功能都在这,和其他的模块有紧密关联,如初始化代码埋点和发送日志mixpanel,给用户添加属性的超类mixpanelPeople,网络类MPNetwork,资源管理MPResource以及MPSwizzler和MPWebSocket

五、参考资料

  • JS埋点技术分析
  • 1 赞 1 收藏 评论

图片 16

推荐阅读:

(个人在简书上觉得较好的文章,以及部分文章内容有所参照)

从0入门篇:http://www.jianshu.com/p/0a9263ea9671

应用机理篇:http://www.jianshu.com/p/69859d580354(建议有代码基础或计算机机理基础看,对于理解埋点实现原理很受用)

可视化埋点的流程展示、便于理解:http://www.jianshu.com/p/c2cb80a342c2

无埋点好处:http://www.jianshu.com/p/6f47fc648e69

可看下无埋点机理,以及了解iOS的runtime机制

iOS的runtime机理:http://www.jianshu.com/p/98f39c4d0df8

http://www.jianshu.com/p/69859d580354

简单可理解为,runtime机制就是在应用中事件都会调用的方法中注入上报数据的埋点代码,知晓该点便于理解文章中的内容。

codelesss:

主要是绑定事件模型类和绑定事件反馈响应,MPEventBinding把json解析成模型(主要是path和事件名字),bindingWithJSONObject方法event_type决定它用哪个子类做模型, 他包括2个子类MPUIControlBinding和MPUITableViewBinding分别处理uicontrol和uitableview下的可交互事件,其中有execute和stop方法用于绑定事件和解除绑定。

messages:

用于接受和转发前端的数据。MPABTestDesignerConnection 它相当于是websocket代理,用来实现websocket的开启连接,数据接受,发送数据,关闭连接。MPAbstractABTestDesignerMessage抽象类,他派生出来的类可分2种,request和response,request是didReceiveMessage根据web端传来json的type字段确定所属的派生类,并在类中做功能相应的处理,完成后创建发送response对象消息。

{"type":"change_response","payload":{"status":"OK"}}

Serialization:

序列化对象,把对象的信息转化成描述信息。MPObjectSerializerContext序列化上下文,即把已经序列化完成的对象放入enque队列,未序列化的放入deque队列,遍历deque队列将所有对象序列化。

图片 17

本文由9159.com发布于前端,转载请注明出处:代码埋点,并且阐述我们自己对于这些技术的理

关键词:

上一篇:原文出处,原文出处9159.com
下一篇:没有了