小程序埋点设计规范:如何设计可扩展的数据采集体系

0 阅读5分钟

埋点不是"想埋就埋"。

没有规范的埋点,3个月后你自己都不知道 btn_click 和 button_click 有什么区别。

这篇文章,我会给你一套可落地的埋点设计规范


一、为什么需要埋点规范?

没有规范的埋点会怎样?

问题后果
命名不统一click_btn vs btn_click vs button_click,数据无法聚合
参数不一致同一个事件,A传page,B传page_path,C传path
重复埋点同一个按钮埋了3次,PV虚高3倍
遗漏埋点核心功能没有埋点,关键数据缺失
无法下线不知道哪些事件还在用,不敢删除

一句话:没有规范的埋点,数据就是垃圾。


二、埋点命名规范

2.1 事件命名规范

格式:对象_动作

code复制

{object}_{action}

对象命名规则:

对象类型前缀示例
页面pagepage_viewpage_stay
按钮btnbtn_clickbtn_longpress
列表listlist_scrolllist_loadmore
表单formform_submitform_reset
弹窗modalmodal_showmodal_close
分享shareshare_clickshare_success
支付paypay_clickpay_successpay_fail
搜索searchsearch_submitsearch_result_click

动作命名规则:

动作说明示例
view查看page_view
click点击btn_click
show展示modal_show
close关闭modal_close
submit提交form_submit
success成功pay_success
fail失败pay_fail
scroll滚动list_scroll
loadmore加载更多list_loadmore

2.2 参数命名规范

格式:小写 + 下划线

code复制

{category}_{name}
参数分类前缀示例
页面相关page_page_pathpage_titlepage_from
按钮相关btn_btn_idbtn_textbtn_position
列表相关list_list_idlist_indexlist_total
搜索相关search_search_keywordsearch_result_count
用户相关user_user_iduser_leveluser_type
商品相关item_item_iditem_nameitem_price
订单相关order_order_idorder_amountorder_status

2.3 参数值规范

参数类型格式示例
字符串小写 + 下划线page_path: "/pages/index/index"
数字纯数字item_price: 99.9
布尔true/falseis_new_user: true
枚举预定义枚举值pay_method: "wechat"
数组JSON数组item_ids: ["id1", "id2"]

禁止的参数值:

禁止原因
中文编码问题,查询困难
大写字母不统一,容易混淆
空格查询困难
特殊字符编码问题

三、埋点分类规范

3.1 三类埋点

类型说明示例
页面级埋点自动采集,无需手动埋点page_view, page_stay
操作级埋点用户交互,需要手动埋点btn_click, form_submit
业务级埋点业务事件,需要手动埋点pay_success, share_complete

3.2 页面级埋点(自动采集)

javascript复制

// 页面级自动埋点
function setupAutoTrack() {
  const originalPage = Page;
  Page = function(config) {
    const originalOnShow = config.onShow;
    const originalOnHide = config.onHide;

    config.onShow = function() {
      tracker.track('page_view', {
        page_path: this.route,
        page_title: this.data.pageTitle || '',
      });
      if (originalOnShow) originalOnShow.call(this);
    };

    config.onHide = function() {
      tracker.track('page_stay', {
        page_path: this.route,
        stay_duration: Date.now() - this._showTime,
      });
      if (originalOnHide) originalOnHide.call(this);
    };

    originalPage(config);
  };
}

3.3 操作级埋点(手动埋点)

javascript复制

// 按钮点击
tracker.track('btn_click', {
  btn_id: 'submit_order',
  btn_text: '提交订单',
  page_path: '/pages/order/order',
  btn_position: 'bottom',
});

// 表单提交
tracker.track('form_submit', {
  form_id: 'login_form',
  form_fields: Object.keys(formData).join(','),
  form_result: 'success',
  page_path: '/pages/login/login',
});

3.4 业务级埋点(手动埋点)

javascript复制

// 支付流程
tracker.track('pay_click', {
  order_id: this.data.orderId,
  order_amount: this.data.orderAmount,
  pay_method: 'wechat',
  page_path: '/pages/order/order',
});

// 支付成功
tracker.track('pay_success', {
  order_id: this.data.orderId,
  order_amount: this.data.orderAmount,
  pay_method: 'wechat',
});

// 支付失败
tracker.track('pay_fail', {
  order_id: this.data.orderId,
  order_amount: this.data.orderAmount,
  pay_method: 'wechat',
  fail_reason: err.errMsg,
});

四、埋点注册管理

4.1 埋点注册表

javascript复制

const EVENT_REGISTRY = {
  'page_view': {
    description: '页面浏览',
    category: 'page',
    auto: true,
    properties: {
      page_path:   { type: 'string', required: true,  description: '页面路径' },
      page_title:  { type: 'string', required: false, description: '页面标题' },
      page_from:   { type: 'string', required: false, description: '来源页面' },
    }
  },
  'page_stay': {
    description: '页面停留',
    category: 'page',
    auto: true,
    properties: {
      page_path:       { type: 'string', required: true,  description: '页面路径' },
      stay_duration:   { type: 'number',  required: true,  description: '停留时长(ms)' },
    }
  },
  'btn_click': {
    description: '按钮点击',
    category: 'interaction',
    auto: false,
    properties: {
      btn_id:       { type: 'string', required: true,  description: '按钮ID' },
      btn_text:     { type: 'string', required: false, description: '按钮文案' },
      page_path:    { type: 'string', required: true,  description: '页面路径' },
      btn_position: { type: 'string', required: false, description: '按钮位置' },
    }
  },
  'pay_click': {
    description: '支付点击',
    category: 'business',
    auto: false,
    properties: {
      order_id:      { type: 'string', required: true,  description: '订单ID' },
      order_amount:  { type: 'number',  required: true,  description: '订单金额' },
      pay_method:    { type: 'string', required: true,  description: '支付方式' },
      page_path:     { type: 'string', required: true,  description: '页面路径' },
    }
  },
};

4.2 埋点校验

javascript复制

class EventValidator {
  constructor(registry) { this.registry = registry; }

  validate(eventName, properties) {
    const errors = [];
    const schema = this.registry[eventName];
    if (!schema) {
      errors.push(`未注册的事件: ${eventName}`);
      return errors;
    }

    for (const [name, prop] of Object.entries(schema.properties)) {
      if (prop.required && !properties[name]) {
        errors.push(`缺少必填参数: ${name}`);
      }
    }

    for (const [name, value] of Object.entries(properties)) {
      const prop = schema.properties[name];
      if (prop && value !== undefined && typeof value !== prop.type) {
        errors.push(`参数类型错误: ${name} 期望 ${prop.type},实际 ${typeof value}`);
      }
    }

    return errors;
  }
}

五、埋点文档管理

5.1 埋点文档模板

markdown复制

## 事件名:btn_click

| 字段 | 内容 |
|------|------|
| **事件名** | btn_click |
| **事件描述** | 用户点击按钮 |
| **事件分类** | 操作级 |
| **触发时机** | 用户点击任何按钮时 |
| **是否自动采集** | 否 |
| **负责人** | 张三 |
| **创建时间** | 2026-06-17 |

### 参数列表

| 参数名 | 类型 | 必填 | 描述 | 示例值 |
|--------|------|------|------|--------|
| btn_id | string | 是 | 按钮唯一标识 | submit_order |
| btn_text | string | 否 | 按钮文案 | 提交订单 |
| page_path | string | 是 | 页面路径 | /pages/order/order |
| btn_position | string | 否 | 按钮位置 | bottom |

5.2 埋点变更流程

code复制

提出变更 → 评审 → 开发 → 测试 → 上线 → 文档更新
步骤说明负责人
提出变更提交埋点变更申请产品/运营
评审评估埋点合理性数据分析师
开发按规范实现埋点代码开发
测试验证埋点数据是否正确测试
上线发布埋点代码开发
文档更新更新埋点文档数据分析师

六、埋点质量控制

6.1 埋点监控规则

javascript复制

const monitorRules = [
  // 未注册事件
  (event) => {
    if (!EVENT_REGISTRY[event.event_name]) {
      return `未注册事件: ${event.event_name}`;
    }
  },
  // 缺少必填参数
  (event) => {
    const schema = EVENT_REGISTRY[event.event_name];
    if (!schema) return null;
    const missing = [];
    for (const [name, prop] of Object.entries(schema.properties)) {
      if (prop.required && !event.properties[name]) missing.push(name);
    }
    if (missing.length > 0) return `${event.event_name} 缺少必填参数: ${missing.join(', ')}`;
  },
  // 事件时间是未来
  (event) => {
    if (event.event_time > Date.now() + 60000) {
      return `${event.event_name} 事件时间是未来: ${event.event_time}`;
    }
  },
  // 参数值超过255字符
  (event) => {
    for (const [name, value] of Object.entries(event.properties || {})) {
      if (typeof value === 'string' && value.length > 255) {
        return `${event.event_name} 参数 ${name} 超过255字符`;
      }
    }
  },
];

七、埋点扩展性设计

7.1 插件化架构

javascript复制

class PluginTracker extends Tracker {
  constructor(options) {
    super(options);
    this.plugins = [];
  }

  use(plugin) {
    this.plugins.push(plugin);
    if (plugin.install) plugin.install(this);
    return this;
  }

  track(eventName, properties = {}) {
    let enhancedProps = { ...properties };

    for (const plugin of this.plugins) {
      if (plugin.beforeTrack) {
        enhancedProps = plugin.beforeTrack(eventName, enhancedProps) || enhancedProps;
      }
    }

    super.track(eventName, enhancedProps);

    for (const plugin of this.plugins) {
      if (plugin.afterTrack) plugin.afterTrack(eventName, enhancedProps);
    }
  }
}

7.2 常用插件

性能监控插件: 自动注入内存、页面加载时间等性能数据。

用户属性插件: 自动注入用户等级、类型等属性数据。

AB实验插件: 自动注入实验分组数据。


八、埋点规范总结

8.1 命名规范

规则格式示例
事件名对象_动作btn_click
参数名分类_名称page_path
参数值小写+下划线submit_order

8.2 埋点分类

类型采集方式示例
页面级自动page_view, page_stay
操作级手动btn_click, form_submit
业务级手动pay_success, share_complete

8.3 管理规范

规范说明
注册制度每个埋点必须在注册表中登记
文档制度每个埋点必须有文档
变更流程提出→评审→开发→测试→上线→文档更新
校验机制开发环境自动校验
监控机制线上自动监控异常数据
扩展性插件化架构,方便扩展

写在最后

埋点规范,不是"增加工作量",而是"减少返工"。

没有规范的埋点,3个月后:

  • 你不知道 btn_click 和 button_click 有什么区别
  • 你不知道 page 是页面路径还是页面名称
  • 你不知道哪些埋点还在用,哪些可以删除

有了规范的埋点:

  • 任何人看到 btn_click,就知道是"按钮点击"事件
  • 任何人看到 page_path,就知道是"页面路径"参数
  • 你可以放心删除不再使用的埋点,因为文档记录了一切

埋点规范,是数据质量的基础。