事件采集基础:用户事件、埋点方案与事件模型设计

好,咱们正式开始聊事件采集。说实话,很多刚入行的同学会把「埋点」想得很简单——不就是往页面上插几段代码吗?但真正做过几个项目之后你就会发现,埋点这件事,从定义到落地,每一步都有坑。今天这一章,我就带你把这些基础概念彻底捋清楚。

什么是用户事件?

先问一个问题:用户在你的产品里干了什么?

他点了某个按钮、滑动了一个页面、提交了一个表单、播放了一段视频……这些行为,在数据采集的语境下,统称为用户事件。每个事件都代表一次用户与产品的交互。

但注意,不是所有行为都值得采集。我见过有的团队恨不得把鼠标移动的每个像素都记录下来,结果数据量爆炸,真正有用的指标反而被淹没了。所以,定义事件之前,先想清楚:这个行为能帮我回答什么业务问题?

用户事件的三要素:

  • 谁(Who)—— 用户的唯一标识,比如 user_id、device_id
  • 什么时候(When)—— 事件发生的时间戳,精确到毫秒
  • 做了什么(What)—— 事件名称 + 附带属性

举个例子:用户「张三」在「2025-03-20 14:30:00.123」点击了「立即购买」按钮,商品 ID 是 10086,价格 299 元。这就是一个完整的事件。

三种埋点方案,我该怎么选?

埋点方案之争,说白了就是「采集的灵活度」和「接入的成本」之间的博弈。目前主流的有三种:代码埋点、全埋点、可视化埋点。我一个个说。

1. 代码埋点(手动埋点)

这是最传统的方式。开发人员在需要采集的位置,手动调用 SDK 的 API 来上报事件。

// 示例:代码埋点
button.addEventListener('click', function() {
  track('product_buy', {
    product_id: '10086',
    price: 299,
    source: 'homepage'
  });
});

优点:灵活、精确。你想采集什么就采集什么,属性可以自定义。

缺点:成本高。每次新增或修改事件,都需要发版。我曾经在一个电商项目里,光埋点代码就写了三千多行,后期维护简直是噩梦。

我的经验:代码埋点适合核心业务事件,比如下单、支付、注册。这些事件对准确性要求极高,手动控制最放心。

2. 全埋点(无埋点)

全埋点的思路是:我不管你点哪里,反正所有交互我都记录下来。SDK 会自动监听页面上的点击、滚动、页面切换等行为,然后一股脑上报。

听起来很省事对吧?但这里有个大坑。

我曾经踩过的坑:全埋点采集的数据量是代码埋点的 10 倍以上。有一次我们没做限流,结果 Kafka 集群直接被冲垮,影响了线上业务。全埋点一定要配合采样率和流量控制,否则就是灾难。

优点:接入快,不需要开发人员写代码,适合快速验证。

缺点:数据噪音大,后期清洗成本高。而且你无法采集「语义化」的属性,比如用户点击了哪个商品、价格是多少,这些全埋点拿不到。

3. 可视化埋点

这个方案介于前两者之间。运营或产品同学可以在后台界面上,直接圈选页面上的元素,然后配置事件名称和属性。SDK 会自动识别这些元素并上报。

说白了,就是「圈一圈,配一配,埋点就完成了」。

优点:非技术人员也能操作,迭代快。

缺点:依赖页面结构。如果前端改了 DOM 结构,埋点可能就失效了。我见过一个团队,改版后一半的可视化埋点都断了,数据直接断档三天。

三种方案对比

维度 代码埋点 全埋点 可视化埋点
接入成本 高(需开发) 低(接入 SDK) 中(需配置)
灵活性 最高 低 中
数据准确性 高 中(有噪音) 中(依赖页面结构)
维护成本 高 低 中
适用场景 核心业务事件 页面浏览、基础点击 运营活动、快速迭代

我个人习惯是混合使用:核心事件用代码埋点,页面浏览用全埋点,运营活动用可视化埋点。没有银弹,只有最适合你当前阶段的方案。

事件模型设计

好,方案选完了,接下来就是设计事件模型。这一步做不好,后面数据治理就是一团乱麻。

事件模型的核心就一句话:一个事件 = 事件名 + 事件属性。但怎么命名、怎么定义属性,这里头有讲究。

事件命名规范

我建议用「对象_动作」的格式,全小写,下划线分隔。比如:

  • product_view —— 浏览商品
  • product_buy —— 购买商品
  • cart_add —— 加入购物车
  • order_submit —— 提交订单

为什么不用驼峰?因为不同团队、不同语言之间,下划线格式最通用,解析起来也最不容易出错。

避坑指南:事件名不要带版本号,比如 product_buy_v2。版本变化应该通过属性来区分,而不是改事件名。否则你后面做漏斗分析时,要把 v1、v2、v3 合并,那叫一个痛苦。

事件属性的分层设计

属性分为三类:

  1. 公共属性:每个事件都带,比如 app_version、platform、user_id、timestamp
  2. 事件特有属性:只属于这个事件,比如 product_buy 的 price、quantity
  3. 上下文属性:当前页面或环境信息,比如 page_url、referrer、network_type

我建议把公共属性放在事件结构的最外层,这样解析时可以直接提取,不用层层嵌套。

{
  "event": "product_buy",
  "user_id": "u_12345",
  "timestamp": 1710923400123,
  "app_version": "3.2.1",
  "platform": "iOS",
  "properties": {
    "product_id": "10086",
    "price": 299.00,
    "quantity": 1,
    "source": "homepage"
  },
  "context": {
    "page_url": "/product/10086",
    "network_type": "wifi"
  }
}

你看,这样结构清晰,解析也方便。我在项目中一直用这个结构,后来接入 Kafka 做流处理时,解析逻辑几乎没改过。

事件模型设计的核心原则

  • 原子性:一个事件只描述一个行为。不要把「点击购买」和「支付成功」混在一个事件里。
  • 可枚举:事件名和属性值尽量用枚举,不要用自由文本。比如 platform 用 "iOS"、"Android",而不是用户随便填。
  • 向前兼容:新增属性时,不要删除或修改已有属性的含义。否则历史数据就废了。

我的习惯:每次新增事件或属性,先在文档里写清楚定义,然后评审。不要边写代码边想,后面一定会乱。

本章知识体系总览

下面这张图,把事件采集的核心脉络串起来了。你可以看到,从「用户行为」到「事件模型」,中间经过了「埋点方案」的选择,最终落地到「数据上报」。每一步都有对应的决策点。

事件采集知识体系图 事件采集知识体系 用户行为 代码埋点 全埋点 可视化埋点 事件模型设计 事件名 + 公共属性 + 特有属性 + 上下文属性 原子性 · 可枚举 · 向前兼容 数据上报(Kafka) 核心:选方案 → 建模型 → 上报

嗯,这一章的内容就到这里。事件采集的「地基」算是打好了。从用户行为的定义,到三种埋点方案的优劣对比,再到事件模型的设计原则,每一步都直接影响后续的数据质量和处理效率。你想想看,如果事件名乱起、属性结构混乱,后面做实时计算、做漏斗分析,那简直就是给自己挖坑。