目录

前端视角下的 A/B Test:埋点、分流与验证

「做个 A/B 实验看看」这句话听起来很轻松,真正落地时会发现:

  • 指标怎么算?
  • 实验人群怎么分?
  • 前端要怎么接入实验配置?
  • 实验结束之后,代码怎么收口?

这篇文章从前端的角度,讲一次相对完整的 A/B 实验闭环。


1. 先确定:为什么要做这个实验?

我们当时的实验目标是:提高某投资流程的转化率

假设是:

把原本一个超长的单页表单拆成多步引导,是否能提高「填写完成率」。

因此:

  • 实验对象:访问该流程的真实用户;
  • 对照组:看到旧版「单页表单」;
  • 实验组:看到新版「多步引导」;
  • 观测指标:完成率、平均耗时、中途流失位置等。

只有先把这些定义清楚,后续埋点和分流才有方向。


2. 埋点设计:先有指标,再谈实现

这次我们重点关心几个指标:

  1. flow_enter:进入流程的人数;
  2. flow_complete:完成流程的人数;
  3. step_view:在多步表单中,每一步的曝光;
  4. step_error:每一步表单提交失败次数。

在前端埋点上做了几件事:

  • 所有埋点带上 experiment_idvariant(A / B);
  • 关键事件使用统一的 event_name + event_params 格式;
  • 尽量避免把业务逻辑硬编码到埋点名里。

示例:

track('flow_enter', {
  experimentId: 'exp_split_form_v1',
  variant: currentVariant, // 'A' 或 'B'
});

track('step_view', {
  experimentId: 'exp_split_form_v1',
  variant: currentVariant,
  step: 1,
});

track('flow_complete', {
  experimentId: 'exp_split_form_v1',
  variant: currentVariant,
});

3. 分流:让实验「公平」且可控

3.1 基本原则

  1. 同一用户体验稳定

    • 被分到 A 组,就一直看 A;
    • 避免一次访问是 A,刷新变 B。
  2. 分配近似均匀

    • 比如 50% / 50%,可配置。
  3. 可按维度分层(可选)

    • 某些实验只针对特定渠道/地区/设备;
    • 可以把这些条件交给实验平台控制。

3.2 简单的前端分流逻辑(示意)

真实环境建议统一由实验平台服务端下发
这里用一个简化版说明思路:

function assignVariant(userId: string) {
  // 简单哈希,保证同一用户稳定
  const hash = hashString(userId);
  return hash % 100 < 50 ? 'A' : 'B';
}

实际项目中:

  • 更推荐由 实验平台在服务端完成分流,前端只负责读取「当前用户在哪个 variant」;
  • 或者前端从配置接口拿到 variant,不自己算。

前端只要:

const { variant, experimentId } = await fetchExperimentConfig('exp_split_form_v1');
renderByVariant(variant);

4. 前端实现:一套代码里兼容 A/B 两种体验

实验时间有限,没必要搞两个完全独立项目,我们选择:同一代码库内分支渲染

示意:

<template>
  <div>
    <OldSingleForm v-if="variant === 'A'" />
    <StepForm v-else />
  </div>
</template>

注意两点:

  1. 埋点要分别在两个版本里打好;
  2. 实验结束后,记得删掉失败版本的代码,而不是永远留个 if

为了减少「代码污染」,我们一般会:

  • 把新旧版本封装成两个独立组件;
  • 把实验 if 判断集中放在一层。

5. 实验过程中的监控与灰度

上线时我们采用的是:

  1. 先把实验比例设得很小(比如 5% 的 B 组);
  2. 观察 1–2 天,确认没有严重 bug;
  3. 再逐步放大到目标比例(例如 50%)。

期间前端要关注:

  • 是否出现某个版本异常 JS 错误;
  • 是否出现某个版本性能指标明显变差;
  • 是否有用户反馈「流程异常」。

这些都要在实验看效果之前先保证「能用」


6. 结果验证:从数据到决策

实验跑了几周之后,数据团队给出的结果大概是:

  • B 组(多步表单)完成率相比 A 组提升了 7–10%(统计显著);
  • 平均填写耗时略有上升,但仍在可接受范围;
  • 流失主要集中在第 2 步(补充信息),为后续优化提供了方向。

从前端视角看,更关心的是:

  • 是否存在异常埋点(比如某些事件 A/B 数据差异异常大);
  • 页面报错/性能是否在两组之间差异显著。

最终结论是:

  • 该实验可以「放量上线」,即 B 组变成新默认;
  • 旧版单页表单支撑一段时间后下线。

7. 实验结束:代码与配置的「收口」

很多团队会忽略一个步骤——清理实验遗留

我们做了三件事:

  1. 删除旧版本组件和相关样式;
  2. 删除实验 ID / 分流逻辑,只保留新的实现;
  3. 保留埋点,但去掉 variant 区分,改为新方案作为常规指标。

这样可以避免代码里残留一堆:

if (experimentId === 'xxx' && variant === 'B') {
  // ...
}

长期下来会变成「实验墓地」。


8. 小结:前端在 A/B 实验中的角色

从这次实践来看,前端在 A/B 流程里的角色大概是:

  1. 在实验设计阶段,一起讨论可观测指标和埋点方案
  2. 实现支持多版本渲染的前端逻辑;
  3. 接入实验平台,正确获取用户实验分组;
  4. 在实验过程中配合观察错误/性能;
  5. 实验结束后,做好代码和配置的收口。

A/B Test 的核心不在于「用了哪个实验平台」,而在于:

是否有一条「从假设 → 实验 → 数据 → 决策 → 收口」的闭环。

从前端把每一步做好,是让实验真正落地的关键。