数据埋点 - 图1

案例:某Feed流产品的数据采集历程

业务背景

一家专注于互联网行业学习交流的社区媒体,产品之前的首页feed主要来自于用户关注的好友产生的数据。但存在问题:

  • 关注的好友不够多,刷不出新内容;
  • 关注的好友没动作,也刷不出新内容。

【问题】如何才能让用户的阅读范围跳出他关注圈子的限制?
【解决】上个性化推荐feed,基于用户的阅读历史、好友关系、关注话题、当下热门进行推荐。

数据采集流程

1、明确需求**

产品自身的指标建模 业务部门的分析需求
内容推荐模块 运营部门的需求 广告部门的需求

- content impression by user
- 各个内容的CTR
- 各个内容类型的曝光和点击需要能够分开查看
- 评论数和点赞数是否对阅读产生影响

- 每个卡片配[不感兴趣]按钮
- 用户主动刷新/加载内容
- 区分不同推荐理由

- 每天广告的曝光量及CTR效果
- 广告曝光时长(focus duration)

2、撰写埋点文档

2.1 埋点事件(指标)确认

需求 指标 埋点
image.png
- 内容卡片曝光量(可按内容类型和话题拆开)
- 内容卡片点击数(可按内容类型和话题拆开)
- 广告曝光量
- 广告点击数
- 用户看到广告卡片的时长
- 主动刷新推荐feed的次数
- 主动滚动到底部加载新内容的次数
- 点击不感兴趣的次数和原因

- cardShow
- cardClick
- adShow
- adClick


- pullToRefresh
- loadMore
- notInterested

2.2 属性拆解

属性拆解的原则:WWWHW(WHO WHEN WHERE HOW WHAT),某个用户在某时某地以某种方式完成了某个具体的行为。
其中WHO、WHEN、WHERE属于公共属性,HOW和WHAT属于专用属性,需要手动埋点。

  • 公共属性

定义:该文档内所有事件都会包含的属性。
说明:通常是公司数据组规定,所有业务线产品均需遵守的属性。
展示:为便于研发同学区分,通常将公共属性字段写在前面,且与各事件中的公共属性保持同一单元格背景色。

字段名称 类型 说明 上线版本 上线时间 当前状态 备注
distinct_id 字符串 用户ID 2.1.0 2018/9/12 上线
time 日期 时间,事件触发的时间 2.1.0 2018/9/12 上线
$app_version 字符串 应用的版本 2.1.0 2018/9/12 上线
$ip 字符串 IP,自动获取 2.1.0 2018/9/12 上线
$country 字符串 国家,通过IP解析 2.1.0 2018/9/12 上线
$province 字符串 省份,通过IP解析 2.1.0 2018/9/12 上线
$city 字符串 城市,通过IP解析 2.1.0 2018/9/12 上线
  • 事件(专用属性)

定义:需要手动埋点的具体事件,比如页面曝光量、广告点击量等等。
说明:确认需查看的数据需求后,由产品定义,跟随本期产品上线。

具体字段: (1)事件编号:不重要,就一序号,不过最好把同一页面上的事件放在一起,方便研发使用 (2)事件显示名:在数据平台查询时显示的名称(需要研发设置,默认显示英文变量名) (3)事件英文变量名:通常大公司数据组会根据各端业务情况,对部分事件进行抽象和固化,形成固定事件,各端统一使用这些固定事件。超出固定事件范围之外的事件,由我们自定义命名,不过一般会有一个统一的命名规则,方便沟通管理。 (4)属性显示名:同上 (5)属性英文变量名:同上(属性指的是这个事件的一些性质,比如一个广告点击事件,记录的是某个轮播广告位的点击量,那么可以加上“广告id”的属性,通过“广告id”字段,确认具体某个广告的点击量)

(6)属性值类型:数值、字符串等等

(7)属性值示例/说明:说明具体参数的对应内容,或是参数示例(比如还是那个广告点击事件,假如我加上“广告id”属性,对应的示例就是某串广告id,例如E23787094NME;假如我加上的是“广告位置”属性,对应的示例可能就是“1代表Banner1、2代表Banner2,以此类推,上限为10”)

(8)事件类别/上报时机:说明记录数据的时机,通常曝光量都是XX页面加载时上报,点击量都是XX(按钮、图片等等)点击时上报。

事件编号 事件变量 事件显示名 事件定义 属性变量 属性显示名 属性值类型
1 cardShow 卡片展示 contentId 内容ID 字符串
contentType 内容类型 字符串
position 列表位置 数值
recommandReason 推荐理由 字符串
channel 内容频道 字符串
withPicture 有无图片 布尔值
2 cardclick 卡片点击 contentId 内容ID 字符串
contentType 内容类型 字符串
position 列表位置 数值
recommandReason 推荐理由 字符串
channel 内容频道 字符串
withPicture 有无图片 布尔值
comments 评论数 数值
likes 点赞数 数值
3 adShow 广告展示 adId 广告ID 字符串
adType 广告类型 字符串
position 列表位置 数值
duration 停留时长 数值
4 adClick 广告点击 adId 广告ID 字符串
adType 广告类型 字符串
position 列表位置 数值
5 pullToRefresh 下拉刷新 times 单次访问刷新次数 数值
interval 刷新间隔时长 数值
6 loadMore 加载更多 depth 加载深度 数值
interval 加载间隔时长 数值
7 notInterested 不感兴趣 contentId 内容ID 字符串
reason 不感兴趣理由 字符串

2.3 触发时机

事件编号 事件变量 事件显示名 事件定义
1 cardShow 卡片展示 1.卡片在用户可见的屏幕范围内出现就算一次展示
2 cardclick 卡片点击 1.用户点击卡片可跳转的区域即算作点击一次
3 adShow 广告展示 1.广告卡片在用户可见的屏幕范围内出现就算一次展示
4 adClick 广告点击 1.用户点击广告卡片可跳转的区域即算作点击一次
5 pullToRefresh 下拉刷新 1.用户在顶部下拉,触发接口刷新后,新内容渲染出来算作一次行为
6 loadMore 加载更多 1.用户滚动到页面底部,触发了底部的加载接口,新内容渲染出来算作一次行为
7 notInterested 不感兴趣 1.用户点击X,并选择不感兴趣的理由后触发该行为
2.如果用户只点击X,而没选择理由视为没触发,避免误点

2.4 属性来源

事件编号 事件变量 事件显示名 事件定义 属性变量 属性显示名 属性值类型 属性定义
1 cardShow 卡片展示 1.卡片在用户可见的屏幕范围内出现就算一次展示 contentId 内容ID 字符串 从API返回的数据中提取
contentType 内容类型 字符串 从API返回的数据中提取
position 列表位置 数值 按照用户实际加载的列表顺序赋值
recommandReason 推荐理由 字符串 从API返回的数据中提取
channel 内容频道 字符串 从API返回的数据中提取
withPicture 有无图片 布尔值 从API返回的数据中提取
2 cardclick 卡片点击 1.用户点击卡片可跳转的区域即算作点击一次 contentId 内容ID 字符串 从API返回的数据中提取
contentType 内容类型 字符串 从API返回的数据中提取
position 列表位置 数值 按照用户实际加载的列表顺序赋值
recommandReason 推荐理由 字符串 从API返回的数据中提取
channel 内容频道 字符串 从API返回的数据中提取
withPicture 有无图片 布尔值 从API返回的数据中提取
comments 评论数 数值 从API返回的数据中提取
likes 点赞数 数值 从API返回的数据中提取
3 adShow 广告展示 1.广告卡片在用户可见的屏幕范围内出现就算一次展示 adId 广告ID 字符串 从API返回的数据中提取
adType 广告类型 字符串 从API返回的数据中提取
position 列表位置 数值 按照用户实际加载的列表顺序赋值
duration 停留时长 数值 从API返回的数据中提取
4 adClick 广告点击 1.用户点击广告卡片可跳转的区域即算作点击一次 adId 广告ID 字符串 从API返回的数据中提取
adType 广告类型 字符串 从API返回的数据中提取
position 列表位置 数值 按照用户实际加载的列表顺序赋值
5 pullToRefresh 下拉刷新 1.用户在顶部下拉,触发接口刷新后,新内容渲染出来算作一次行为 times 单次访问刷新次数 数值 从API返回的数据中提取
interval 刷新间隔时长 数值 从API返回的数据中提取
6 loadMore 加载更多 1.用户滚动到页面底部,触发了底部的加载接口,新内容渲染出来算作一次行为 depth 加载深度 数值 从API返回的数据中提取
interval 加载间隔时长 数值 从API返回的数据中提取
7 notInterested 不感兴趣 1.用户点击X,并选择不感兴趣的理由后触发该行为
2.如果用户只点击X,而没选择理由视为没触发,避免误点
contentId 内容ID 字符串 从API返回的数据中提取
reason 不感兴趣理由 字符串 从API返回的数据中提取

3、技术埋点(与RD沟通)

在屏幕里出现,怎样叫出现?出现多次怎么办?只出现了一半的高度怎么办?你这样把前端逻辑搞得很复杂,为什么非得做这个可见屏幕内的出现啊。就不能一次API拉回来的20条数据都算作展现了么? image.png
image.png 首先,我们这个推荐feed刚上线,需要大量的数据来调校,这依赖于对推荐出来的内容精准核算曝光和CTR。
- 如果API拉回本地就算展现,那第一屏往往就只能显示3、4条资讯,后面的十几条资讯从来没在用户这曝过光,算作已展现的话会大大影响我们CTR的计算。
- 因此还得麻烦你们来实现一下监测卡片出现的前端逻辑。
image.png 另外,我们其实是想统计精准的CTR,因此对于「出现」这个事件的定义还是希望更加严谨一些。
- 如果用户是在快速滚动feed过程中,那么其实是看不清卡片上的内容的,这样的也不要记录下来。
- 为了方便你们研发实施,这里我们就定一个数吧,只有在feed流处于静止状态超过0.5s后,才开始进行「展现」这个事件的触发。
- 另外就是这种展现为了统一统计口径,单一卡片在一次推荐列表刷新中,只计算一次「展现」,多次展现不累加。
image.png (此处省略一千字)我对事件的定义进行了完善。
image.png
那做呗 image.png

4、数据检验

4.1 数据检验

前端抓包或后端数据库

4.2 发现的坑

  • 「卡片展现」、「卡片点击」的位置属性( position )时常出现0
  • 「加载更多」的加载间隔时长有时候会出现极大的值(几万秒)

    4.3 版本信息更新

    | 事件编号 | 事件变量 | 事件显示名 | 事件定义 | 属性变量 | 属性显示名 | 属性值类型 | 属性定义 | 当前状态 | 埋点形式 | 上线版本 | 上线时间 | 备注 | | :—-: | :—-: | :—-: | :—-: | :—-: | :—-: | :—-: | :—-: | :—-: | :—-: | :—-: | :—-: | :—-: | | 1 | cardShow | 卡片展示 | 1.卡片在用户可见的屏幕范围内出现就算一次展示 | contentId | 内容ID | 字符串 | 从API返回的数据中提取 | 上线 | 前端 | 2.1.0 | 2018-9-12 | | | | | | | contentType | 内容类型 | 字符串 | 从API返回的数据中提取 | 上线 | | 2.1.0 | 2018-9-12 | | | | | | | position | 列表位置 | 数值 | 按照用户实际加载的列表顺序赋值 | 上线 | | 2.1.0 | 2018-9-12 | | | | | | | recommandReason | 推荐理由 | 字符串 | 从API返回的数据中提取 | 上线 | | 2.1.0 | 2018-9-12 | | | | | | | channel | 内容频道 | 字符串 | 从API返回的数据中提取 | 上线 | | 2.1.0 | 2018-9-12 | | | | | | | withPicture | 有无图片 | 布尔值 | 从API返回的数据中提取 | 上线 | | 2.1.0 | 2018-9-12 | | | 2 | cardclick | 卡片点击 | 1.用户点击卡片可跳转的区域即算作点击一次 | contentId | 内容ID | 字符串 | 从API返回的数据中提取 | 上线 | 前端 | 2.1.0 | 2018-9-12 | | | | | | | contentType | 内容类型 | 字符串 | 从API返回的数据中提取 | 上线 | | 2.1.0 | 2018-9-12 | | | | | | | position | 列表位置 | 数值 | 按照用户实际加载的列表顺序赋值 | 上线 | | 2.1.0 | 2018-9-12 | | | | | | | recommandReason | 推荐理由 | 字符串 | 从API返回的数据中提取 | 上线 | | 2.1.0 | 2018-9-12 | | | | | | | channel | 内容频道 | 字符串 | 从API返回的数据中提取 | 上线 | | 2.1.0 | 2018-9-12 | | | | | | | withPicture | 有无图片 | 布尔值 | 从API返回的数据中提取 | 上线 | | 2.1.0 | 2018-9-12 | | | | | | | comments | 评论数 | 数值 | 从API返回的数据中提取 | 上线 | | 2.1.0 | 2018-9-12 | | | | | | | likes | 点赞数 | 数值 | 从API返回的数据中提取 | 上线 | | 2.1.0 | 2018-9-12 | | | 3 | adShow | 广告展示 | 1.广告卡片在用户可见的屏幕范围内出现就算一次展示 | adId | 广告ID | 字符串 | 从API返回的数据中提取 | 上线 | 前端 | 2.1.0 | 2018-9-12 | | | | | | | adType | 广告类型 | 字符串 | 从API返回的数据中提取 | 上线 | | 2.1.0 | 2018-9-12 | | | | | | | position | 列表位置 | 数值 | 按照用户实际加载的列表顺序赋值 | 上线 | | 2.1.0 | 2018-9-12 | | | | | | | duration | 停留时长 | 数值 | 从API返回的数据中提取 | 上线 | | 2.1.0 | 2018-9-12 | | | 4 | adClick | 广告点击 | 1.用户点击广告卡片可跳转的区域即算作点击一次 | adId | 广告ID | 字符串 | 从API返回的数据中提取 | 上线 | 前端 | 2.1.0 | 2018-9-12 | | | | | | | adType | 广告类型 | 字符串 | 从API返回的数据中提取 | 上线 | | 2.1.0 | 2018-9-12 | | | | | | | position | 列表位置 | 数值 | 按照用户实际加载的列表顺序赋值 | 上线 | | 2.1.0 | 2018-9-12 | | | 5 | pullToRefresh | 下拉刷新 | 1.用户在顶部下拉,触发接口刷新后,新内容渲染出来算作一次行为 | times | 单次访问刷新次数 | 数值 | 从API返回的数据中提取 | 上线 | 前端 | 2.1.0 | 2018-9-12 | | | | | | | interval | 刷新间隔时长 | 数值 | 从API返回的数据中提取 | 上线 | | 2.1.0 | 2018-9-12 | | | 6 | loadMore | 加载更多 | 1.用户滚动到页面底部,触发了底部的加载接口,新内容渲染出来算作一次行为 | depth | 加载深度 | 数值 | 从API返回的数据中提取 | 上线 | 前端 | 2.1.0 | 2018-9-12 | | | | | | | interval | 加载间隔时长 | 数值 | 从API返回的数据中提取 | 上线 | | 2.1.0 | 2018-9-12 | | | 7 | notInterested | 不感兴趣 | 1.用户点击X,并选择不感兴趣的理由后触发该行为
    2.如果用户只点击X,而没选择理由视为没触发,避免误点 | contentId | 内容ID | 字符串 | 从API返回的数据中提取 | 上线 | 前端 | 2.1.0 | 2018-9-12 | | | | | | | reason | 不感兴趣理由 | 字符串 | 从API返回的数据中提取 | 上线 | | 2.1.0 | 2018-9-12 | |

5、新需求

一个多月过去了。推荐feed大受好评,人均阅读数和内容曝光量都大涨,相应的广告曝光及点击也随之增长。 看到如此正面的效果后,产品团队决定继续优化推荐功能。 【新功能】查看当前资讯,返回推荐feed时,在该卡片下方直接推荐和这个卡片相关联的3个卡片。

image.png 新推荐的三个卡片,都没有position
属性变量 属性显示名 属性值类型 属性定义 备注
contentId 内容ID 字符串 从API返回的数据中提取
contentType 内容类型 字符串 从API返回的数据中提取
position 列表位置 数值 按照用户实际加载的列表顺序赋值 从1开始
2018-10-23更新:因为加入了从文章页返回推荐feed自动在列表中插入相关推荐的功能,新插入的3条内容会打乱之前的列表排序值,因此每次插入都会重新计算整个列表各个卡片的排序值
recommandReason 推荐理由 字符串 从API返回的数据中提取
channel 内容频道 字符串 从API返回的数据中提取
withPicture 有无图片 布尔值 从API返回的数据中提取