4. 埋点属性设计规范:通用属性、业务属性、事件属性、用户属性的定义与约束

属性设计,说白了就是给每个埋点事件贴上「标签」。标签贴得乱,后面分析全抓瞎。我见过太多团队,埋点上了几百个,最后问「用户从哪个渠道来的?」——答不上来,因为渠道字段有的叫 channel,有的叫 utm_source,有的干脆没传。

这一章,咱们就把属性的四大家族理清楚:通用属性、业务属性、事件属性、用户属性。每个家族该管什么、不该管什么,边界在哪,约束条件是什么。嗯,这都是我踩过坑之后才总结出来的。

4.1 四类属性的核心定位

先看一张图,把四类属性的关系搞清楚。

埋点属性四大家族关系图 通用属性 设备ID、平台、App版本、网络类型 每条事件自动携带,全局统一 用户属性 用户ID、会员等级、注册渠道 用户维度画像,低频更新 事件属性 事件名称、触发时间、页面路径 描述事件本身,每条事件独有 业务属性 商品ID、订单金额、优惠券类型 业务域特有字段,按需扩展 自动注入 关联用户 承载 核心原则 1. 通用属性 + 用户属性 → 自动注入到每条事件 2. 事件属性 → 描述「谁在什么时候做了什么」 3. 业务属性 → 描述「具体业务对象的状态」 4. 四类属性互不重叠,各司其职

你看,通用属性和用户属性是「基础设施」,每条事件都自动带上。事件属性和业务属性是「业务表达」,按需设计。四者泾渭分明,不能混用。

4.2 通用属性:全局统一的「身份证」

通用属性是什么?就是不管什么事件,都必须携带的那几个字段。我习惯叫它「埋点身份证」。

通用属性清单(强制)

属性名类型示例值说明
device_idstringa1b2c3d4-...设备唯一标识,IDFA/IMEI/OAID
platformstringios / android / web操作系统或平台
app_versionstring3.2.1App 版本号,Web 可传空
network_typestringwifi / 4g / 5g网络环境
event_timelong1712563200000事件触发时间戳(毫秒)
session_idstringsess_abc123会话 ID,用于归因

这里有个坑。我遇到过团队把 app_version 写成 version,另一个团队写成 appVersion。最后做版本分析时,两个字段对不上,数据直接废了。所以通用属性必须统一命名,大小写、下划线、类型都得定死。

通用属性约束

  • 所有事件必须携带,缺失则丢弃该条事件
  • 字段名全局唯一,不允许重名
  • 类型固定,不允许同一字段在不同事件中类型不一致
  • 由 SDK 自动采集,业务方无需手动传入

4.3 业务属性:灵活扩展的「业务语言」

业务属性是最灵活、也最容易失控的部分。说白了,业务方想加什么就加什么,但加多了就变成垃圾场。

我举个例子。电商的「下单」事件,业务属性可能包括:

  • order_id — 订单号
  • total_amount — 订单总金额
  • coupon_id — 使用的优惠券 ID
  • sku_list — 商品 SKU 列表
  • pay_channel — 支付渠道

看起来没问题对吧?但实际项目中,我见过有人把 user_name 也塞进业务属性里。这就错了——用户信息应该走用户属性,不是业务属性。

我的经验法则

业务属性只放「这个事件特有的业务数据」。如果某个字段在多个事件中都出现,且描述的是同一个业务对象,那就应该抽成公共属性或者用户属性。

4.4 事件属性:描述「发生了什么」

事件属性是每个事件自带的元信息。它不关心业务细节,只关心事件本身。

标准的事件属性包括:

属性名类型说明
event_namestring事件名称,如 view_item、add_to_cart
page_urlstring当前页面 URL
page_titlestring页面标题
referrerstring来源页面
screen_widthint屏幕宽度
screen_heightint屏幕高度

你可能会问:page_url 和 referrer 算不算通用属性?我个人习惯把它们归到事件属性,因为不同事件可能在不同页面触发,page_url 是跟着事件走的。通用属性是「无论在哪都一样的」,事件属性是「跟着事件变的」。

4.5 用户属性:用户维度的「画像标签」

用户属性描述的是「这个用户是谁」。它不随事件变化,而是随用户状态变化。

常见的用户属性:

  • user_id — 登录用户 ID
  • user_level — 会员等级
  • register_channel — 注册渠道
  • register_time — 注册时间
  • last_login_time — 最后登录时间

用户属性更新规则

用户属性是「缓慢变化维度」。不要每条事件都去更新用户属性,那样会浪费大量存储和计算资源。我建议:

  • 用户属性只在登录、注册、信息修改时更新
  • 每次更新带上时间戳,方便回溯
  • 用户属性变更要记录变更日志,便于排查

4.6 属性命名与类型约束

这一节是硬规矩。命名不规范,后面全是坑。

命名规范

  • 全部小写 + 下划线:user_level,不是 userLevel 或 UserLevel
  • 不超过 64 个字符
  • 以字母开头,只包含字母、数字、下划线
  • 禁止使用保留关键字(如 event、user、time)

类型约束

类型示例约束
string"ios"长度不超过 1024 字符
int10032 位有符号整数
long171256320000064 位有符号整数,时间戳专用
float99.99保留 2 位小数
booleantrue不允许传 0/1
array["a","b"]元素类型必须一致

我曾经遇到一个项目,total_amount 在 iOS 端传的是 float,在 Android 端传的是 string。结果做聚合分析时,Android 的数据全被当成字符串拼接了。嗯,从那以后我强制要求类型校验必须在 SDK 层做掉。

4.7 属性治理的「三不」原则

最后,分享一个我总结的「三不」原则:

  1. 不重复:同一个业务含义,只用一个属性名。比如「商品价格」要么统一用 price,要么统一用 product_price,不能混用。
  2. 不滥用:不要把业务属性当通用属性用。比如 coupon_id 只在「领券」和「下单」事件中出现,就不要加到所有事件里。
  3. 不缺失:通用属性和事件属性必须非空。业务属性如果为空,要明确是「没有值」还是「值未知」,用 null 还是 "" 要提前约定好。

总结一下

属性设计是埋点治理的基石。通用属性管「全局统一」,业务属性管「业务表达」,事件属性管「事件描述」,用户属性管「用户画像」。四者各司其职,互不干扰。命名和类型约束是硬规矩,谁都不能破。做到这些,你的埋点数据至少能保证「可用」。