# 基础知识

# 客户端埋点

客户端接入目前有以下方案:

直接使用凡泰客户端 SDK。这个方案相对简单、易用,并且凡泰 SDK 提供了更多内置的功能(例如 采集 PV/UV 等)和可靠性保证。一般情况下,我们建议采用此方案。

# 数据模型

# 数据模型简介

在凡泰分析中,我们使用事件模型(Event 模型)来描述用户在产品上的各种行为,这也是凡泰分析所有的接口和功能设计的核心依据。

简单来说,事件模型包括事件(Event)和用户(User)两个核心实体,同时配合物品(Item)实体可以做各种维度分析,在凡泰分析中,分别提供了接口供使用者上传和修改这两类相应的数据,在使用产品的各个功能时,这两类数据也可以分别或者贯通起来参与具体的分析和查询。对这两个概念,我们会在后文做具体的描述。

# 1.1 Event Model Vs. enter_page

在传统的 Web 时代,通常使用 PV(Page View 的简写,也即页面访问量)来衡量和分析一个产品的好坏,然后,到了移动互联网以及 O2O 电商时代,PV 已经远远不能满足产品和运营人员的分析需求了。

在这个年代,每个产品都有着独一无二的核心指标用来衡量产品是否成功,这个指标可能是发帖数量、视频播放数量、订单量或者其它的可以体现产品核心价值的指标,这些都是一个简单的 PV 无法衡量的。

除此之外,PV 模型也无法满足一些更加细节的、更加精细化的分析。例如,我们想分析哪类产品销量最好,访问网站的用户的年龄和性别构成,每个渠道过来的用户的转化率、留存和重复购买率分别如何,新老用户的客单价、流水、补贴比例分别是多少等等。这些问题,都是以 PV 为核心的传统统计分析没办法解答的问题。

因此,凡泰分析采用事件模型作为基本的数据模型。事件模型可以给我们更多的信息,让我们知道用户用我们的产品具体做了什么事情。事件模型给予我们更全面且更具体的视野,指导我们做出更好的决策。

当然,采用凡泰分析的事件模型,依然是可以完成 PV 统计的,并且实现起来也很简单,使用 SDK 即可。

{
  event_id: "367924340"
  event_name: "enter_page"
  event_type: "enter"
  params:
    app_session_id: "1600403123516-4391917-0c290949b8dbd4-23428557"
    mid: "M00000"
    page_session_id: "1600403124339-1556755-0ceba96518b8f2-16836773"
    path: "pages/tweet/tweet"
    query: "{"fcid":"@staff_staff10:000000.finogeeks.com","timelineId":"f4aaa067-a6ae-4c57-9cc8-6e4a5804329d","from":"HOME"}"
  referrer: "直接打开"
  timestamp: 1600403124340
}

# 1.2 Event 实体

简单来说,一个 Event 就是描述了:一个用户在某个时间点、某个地方,以某种方式完成了某个具体的事情。从这可以看出,一个完整的 Event,包含如下的几个关键因素:

  • Who:即参与这个事件的用户是谁。在我们的数据接口中,使用 device_info 中的 device_id 来设置用户的唯一 ID:对于未登录用户,这个 ID 可以是 cookie_id、设备 ID 等匿名 ID;对于登录用户,则建议使用后台分配的实际用户 ID。同时,我们也提供了 setUserInfo 这个接口,在用户注册的时候调用,用来将同一个用户注册之前的匿名 ID 和注册之后的实际 ID 贯通起来进行分析。

  • When:即这个事件发生的实际时间。在我们的数据接口中,使用 timestamp 字段来记录精确到毫秒的事件发生时间。如果调用者不主动设置,则各个 SDK 会自动获取当前时间作为 timestamp 字段的取值。

  • Where:即事件发生的地点。使用者可以设置 network_info 中的 ip 属性,这样系统会自动根据 ip 来解析相应的省份和城市,当然,使用者也可以根据应用的 GPS 定位结果,或者其它方式来获取地理位置信息,然后手动设置 city 和 province。除了 city 和 province 这两个字段以外,也可以自己设置一些其它地域相关的字段。例如,某个从事社区 O2O 的产品,可能需要关心每个小区的情况,则可以添加自定义字段 “HousingEstate”;或者某个从事跨国业务的产品,需要关心不同国家的情况,则可以添加自定义字段 “Country”。

  • How:即用户从事这个事件的方式。这个概念就比较广了,包括用户使用的设备、使用的浏览器、使用的 App 版本、操作系统版本、进入的渠道、跳转过来时的 referer 等,目前,凡泰分析预置了如下字段用来描述这类信息,使用者也可以根据自己的需要来增加相应的自定义字段。

app_info: {
  app_id: 应用ID;
  app_key_id: 应用渠道;
  app_version: 应用版本;
  sdk_type: SDK类型;
  sdk_version: SDK版本;
}
device_info:{
  brand: "devtools" 设备系统
  device_id: "fdsferewrfds" 设备ID
  model: "iPhone 6/7/8" 设备型号
  os: "iOS" 操作系统
  os_version: "10.0.1" 操作系统版本
  screen_size: "375*667"屏幕宽度*高度
}
network_info:{
  ns: "4g"  WIFI4G
  ip: IP地址
}

提示

  • What:描述用户所做的这个事件的具体内容。在我们的数据接口中,首先是使用 event 这个事件名称,来对用户所做的内容做初步的分类。event 的划分和设计也有一定的指导原则,我们会在后文详细描述。除了 event 这个至关重要的字段以外,我们并没有设置太多预置字段,而是请使用者根据每个产品以及每个事件的实际情况和分析的需求,来进行具体的设置,下面给出一些典型的例子:

  • 对于一个“购买”类型的事件,则可能需要记录的字段有:商品名称、商品类型、购买数量、购买金额、 付款方式等;

  • 对于一个“搜索”类型的事件,则可能需要记录的字段有:搜索关键词、搜索类型等;

  • 对于一个“点击”类型的事件,则可能需要记录的字段有:点击 URL、点击 title、点击位置等;

  • 对于一个“用户注册”类型的事件,则可能需要记录的字段有:注册渠道、注册邀请码等;

  • 对于一个“用户投诉”类型的事件,则可能需要记录的字段有:投诉内容、投诉对象、投诉渠道、投诉方式等;

  • 对于一个“申请退货”类型的事件,则可能需要记录的字段有:退货金额、退货原因、退货方式等。

# 1.3 Event 的划分和字段设计原则

为了更好地使用凡泰分析提供的强大、便捷的分析功能,我们强烈建议使用者花费一定的时间,梳理自己的数据使用需求,并据此做好 Event 的划分和字段设计。

在 Event 的划分和设计过程中,凡泰分析团队也会提供相应的技术支持和服务。

# 1.3. User 实体

每个 User 实体对应一个真实的用户。

对于未登录用户 用 device_id 进行标识,并且通过 device_id 与这个用户所从事的行为,也即 Event 进行关联。

对于登录用户,则建议使用后台分配的实际用户 ID。同时,我们也提供了 setUserInfo 和 setDeviceId 接口,用来将同一个用户注册之前的匿名 ID 和注册之后的实际 ID 贯通起来进行分析。

# 全埋点采集逻辑

# 小程序采集事件方案

# 实现思路:代理模式技术 --> 监听各个小程序生命周期 --> 重写各个小程序生命周期的预置事件数据 --> 上报数据

# SDK 默认使用代理并自动上报小程序的 APP 启动 、隐藏和 Page 启动、离开、分享事件,下面表格是上报数据详细说明

# 数据表格

事件类型 事件名称 生命周期->映射关系 采集时机 说明
enter(启动) enter_app(应用启动) App.onLaunch 对应 appLaunch 小程序进程被杀死,重新打开时会触发 小程序初始化完成时,全局只触发一次
leave(离开) leave_app (应用离开) App.onHide 对应 appHide 点击小程序右上角退出按钮、微信进入后台、手机锁屏、小程序进程被杀死时 小程序从前台进入后台
enter(启动) enter_page (页面启动) Page.onLoad 对应 pageLoad Page.onShow 对应 pageShow 小程序启动打开页面、小程序内打开页面、从后台进入前台打开页面时触发 每次打开页面都会调用一次
leave(离开) leave_page (页面离开) Page.onHide 对应 pageHide Page.onUnload 对应 pageHide 小程序离开页面、小程序内离开页面、从前台进入后台离开页面时触发 每次离开页面都会调用一次
share(分享) shareToFriend(小程序分享) Page.onShareAppMessage 对应 pageShare 设置这个函数后,点击分享按钮触发 暂时只能获取到用户触发分享,无法监听是否分享成功的反馈
click(点击) 根据开发者进行定义 (点击元素名称) / 当 Page 中定义的事件处理函数被触发时采集 目前只支持 'tap', 'click','longtap' 事件
custom(自定义) 根据开发者进行自定义(自定义事件) / / 开发者自定义事件

# web 方案

# 数据发送数据时机逻辑

# 小程序方案

在我们的收集数据中,首先是把数据存在内存中,通过一些参数来进行具体的设置或者时机来触发把收集的数据发送给服务端。下面给出一些触发时机例子:

  1. 自动收集数据超过 30 条,就会触发发送数据时机。开发者可以通过配置来配置多少条数,系统默认 30 条(最多只能设置 300 条) 。
  2. 时间间隔 5 分钟,就会触发发送数据时机。开发者可以通过配置来配置时间间隔分钟,系统默认 5 分钟。
  3. 小程序从前台进入后台,就会触发发送数据时机。比如此 leave_app 和 shareToFriend 事件一定会触发。
  4. 开发者手动调用我们提供的立即上报方法,就会触发发送数据时机。 immedRequest()。
  5. 小程序应用启动初始化完成时,就会触发发送数据时机。但是提前需要本地存储有到存储到用户以前丢失的数据。

如果数据发送失败,SDK 会把发送数据的保存的用户本地存储中,下一次小程序应用启动初始化完成时,立即发送本地存储的数据。

代码示例

fctrack.setPara({
  // batch_send 数据类型 是 boolean 或 object  系统默认值 true
  // 如果是 true 代表 收集数据超过30条后,会通过请求发送到服务端。默认30条
  // 如果是 object max_length 代表收集多少条数据后,发送请求到服务端。默认30条
  batch_send: {
    max_length: 5,
  },
  // interval_timeout 发送数据时间间隔,默认是:300000 5 分钟 单位毫秒
  interval_timeout: 117000,
});

# 数据格式详细说明

名称 类型 描述
batch_send boolean 或 object 把收集好的数据发送请求到服务端,默认是:true。 如果是 true 代表 收集数据超过 30 条后,会通过请求发送到服务端。默认 30 条。 如果是 object max_length 代表收集多少条数据后,发送请求到服务端。默认 30 条
interval_timeout number 发送数据时间间隔,默认是:300000 5 分钟 单位毫秒

# 点击事件采集逻辑

实现思路:监听用户点击-->读取埋点配置 JOSN,判断是否需要上报--> 上报数据

# 通过配置表声明埋点

为了解决代码入侵问题,可以将所有埋点信息统一管理,通过配置表的方式,除了方便管理,以后还可以做到动态配置,在服务端配置完毕下发到客户端。

const tracks = {
  path: 'pages/tweet/detail' // 页面路径,
  methodTracks: [
    {
      method: 'goDetails', // 声明需要监听的方法
      chineseMethod: '点击名片', // 方法事件中文名称
      dataKeys: ['timelineid', '$APP.userId', '$QUERY.fcid'], // 声明需要获取Data下的哪些数据
    },
  ],
};

# 特殊前缀

dataKeys 里面的 key 定义 data-xxx 中的 xxx 值 $APP 表示读取App下定义的数据 $QUERY 表示读取页面加载 query 下定义的数据 需要获取 timelineid 时,需要在页面中加入 data-timelineid=标记

$APP 读取App下定义的数据
App({
  globalData: {
    userId: '123',
  }
})

$QUERY 读取QUERY下定义的数据
Page({
  // 比如当前完整页面路径 pages/home/index?fcid=789
  onLoad: function(options) {
      console.log(options);
      // 1. 打印日志看看 options参数有fcid,如果有,那么SDK就会自动收集fcid参数的值。
      // 2. 确保配置参数dataKeys 配置了 $QUERY.fcid。
    },
})

timelineid 读取data-timelineid
<view class='playing-item' data-timelineid="{{timelineid}}"'></view>