Web SDK
@evstats/web:网页里的页面浏览、全埋点、热力图坐标、A/B 分组,以及按需加载的会话回放和热力图叠加。核心没有运行时依赖,gzip 后小于 10KB。
安装
用 script 标签:
<script src="https://unpkg.com/@evstats/web/dist/evstats.min.js"></script>
<script>
evstats.init({
endpoint: "https://stats.example.com/sa",
key: "evs_wk_xxx"
})
</script>脚本地址要写到文件名。回放和热力图的分包按这个地址推算同目录的 evstats-replay.js、evstats-heatmap.js,自己托管时把 dist/ 整个目录放在一起。
用打包工具:
yarn add @evstats/webimport { init, track, identify } from "@evstats/web"
init({
endpoint: "https://stats.example.com/sa",
key: "evs_wk_xxx"
})
track("signup", { plan: "pro" })
identify("user_42")ESM 用法下两个分包通过动态 import() 加载,打包工具会把它们处理成懒加载的 chunk。
endpoint 必须是完整的采集地址,SDK 原样请求,不会再拼 /sa。
init 选项
| 选项 | 默认 | 说明 |
|---|---|---|
endpoint | 必填 | 完整采集地址(含路径) |
key | 必填 | 项目的写入密钥 |
pageview | true | 发 $pageview,并监听路由 |
autocapture | true | $WebClick、$WebStay。项目里关掉时以服务端为准 |
heatmap | true | 点击带 $page_x、$page_y 与视口宽高 |
record | 跟随服务端 | 设为 false 时从不录制;其它情况只有项目打开回放且本访客被抽中才录 |
replayEndpoint | 空 | 完整的回放上传地址。空则把 endpoint 的路径换成 /replay |
debug | false | 在控制台打印入队、上报、配置下发的日志 |
ignorePaths | [] | 命中则不自动发页面浏览,track 不受影响。字符串精确匹配路径,结尾 * 表示前缀("/admin/*"),也可以是正则 |
API
| 函数 | 作用 |
|---|---|
init(options): Promise<void> | 初始化。返回的 Promise 在项目配置返回(成功或失败)之后完成 |
track(event, properties?) | 记一个事件,type=track |
page(properties?) | 手动记一次页面浏览,事件名 $pageview |
identify(userId, traits?) | 登录之后调用。之后的新事件带 userId;带 traits 时另记一条用户属性 |
reset() | 退出登录时调用:忘掉 userId,换一个新的匿名 ID |
flush(): Promise<void> | 立即把本地队列全部发出 |
close(): Promise<void> | 停止监听与录制,发出队列和回放的最后一块 |
variant(experimentKey): string | null | 当前访客在某个 A/B 实验里分到的变体 key;没进入实验或配置还没返回时为 null |
version | SDK 版本号 |
属性值只能是字符串、数字、布尔,其它类型被丢弃。业务属性不要用 $ 开头。
行为
配置下发
初始化后请求 /sdk/config(由 endpoint 换路径),取项目的全埋点、热力图、回放、遮罩和实验配置,服务端缓存 5 分钟。请求失败时沿用 init 里的开关,5 分钟后再试。
页面浏览
监听 pushState、replaceState、popstate、hashchange,50ms 去抖,地址变了才发。初始加载只发一条;页面从浏览器的往返缓存恢复时再发一条。单页应用不用额外写代码。
utm_* 和 gclid、fbclid、ttclid、msclkid 从地址栏读取,同一个标签页的会话内沿用。
队列与重试
| 项 | 值 |
|---|---|
| 队列 | localStorage,最多 200 条,超出丢最旧;存储不可用时退到内存 |
| 发送 | 每 300ms 一批,单批最多 20 条 |
| 重试 | 网络失败、超时(10 秒)、429、5xx 按 200ms 起指数退避,最多 5 次;仍失败则留在队列,下次再发 |
| 不重试 | 400、401 等其它错误:丢弃这一批,在控制台告警 |
messageId | 入队时生成一次,重试沿用 |
| 多个标签页 | 同域共用一份队列,发送前先认领,不会重复发同一批 |
页面关闭
pagehide 时把当前批次(不超过 48KB)发出去,离开页面的 $WebStay 也在这一批里。同源时用 sendBeacon,跨源时先用 keepalive 的 fetch。sendBeacon 带不了 Authorization 头,所以这时写入密钥放在 JSON 的 writeKey 里。
跨源部署时,采集服务的跨域预检要允许 Authorization 与 Content-Type 请求头(evstats 按项目的 allow_origins 回答,默认允许)。
身份
| 存储 | 键 | 内容 |
|---|---|---|
localStorage | evstats_anonymous_id | 匿名 ID |
localStorage | evstats_user_id | identify 之后的用户 ID |
localStorage | evstats_queue | 待发送的队列 |
localStorage | evstats_first、evstats_latest | 首次和最近一次触点 |
sessionStorage | evstats_campaign | 本次会话的广告参数 |
sessionStorage | evstats_replay | 回放 ID 与块序号 |
SDK 不写 Cookie。identify 之后已经排队的事件不会被改写。
全埋点
- 点击发
$WebClick,带元素的 id、name、class、标签、选择器、链接地址,以及按钮和链接的可见文本(最多 100 字)。 - 绝不读取
input、textarea、密码框、[contenteditable]的值。命中遮罩选择器的元素、它的子元素、以及包含被遮罩元素的元素,都不采文本。 - 离开页面(
pagehide或单页应用切换路由)发$WebStay:停留秒数$event_duration、滚动位置$viewport_position。
遮罩选择器 = 内置的 input、textarea、[contenteditable]、[data-evstats-mask],加上项目设置里的选择器。
A/B
配置里只下发进行中的实验,分组在浏览器本地完成,和服务端同一个算法:
id = anonymousId || userId
bucket = fnv1a32(id + key) % 100 // bucket >= traffic 时不进入实验
pick = fnv1a32(key + id) % sum(weights) // 按顺序累加权重,取第一个累计值 > pick 的变体fnv1a32 按 UTF-8 字节计算,offset 2166136261、prime 16777619,结果是无符号 32 位整数。进入实验的访客每次页面加载发一次 $ABTestTrigger,属性 $abtest_experiment_id 是实验 key,$abtest_experiment_group_id 是变体 key。
await init({ endpoint, key })
if (variant("signup-button") === "new") renderNewButton()会话回放
项目打开回放,并且 fnv1a32("replay:" + anonymousId) % 100 小于抽样比例时,才加载 evstats-replay.js(内含 rrweb 录制)。所有输入框遮罩;事件按块上传,单块不超过 2MB;缓冲超过 512KB 或每 10 秒发一块,页面隐藏时发出当前块。同一个标签页 30 分钟内的多次页面加载算同一次回放。见 会话回放。
热力图叠加
地址栏带 evstats_heatmap=令牌 时:
- 用
history.replaceState从地址栏删掉这个参数。 - 本页停止一切上报:不发页面浏览、不采全埋点、不发送队列。
- 加载
evstats-heatmap.js,用令牌请求/sdk/heatmap,在页面最上层画一个不拦截点击的 Canvas。 - 右上角面板可以切换点击 / 停留、调透明度、关闭;令牌过期时提示回到后台重新打开。
见 全埋点与热力图。
产物
| 文件 | 内容 | 什么时候加载 |
|---|---|---|
dist/evstats.min.js | 核心,全局变量 evstats | 页面加载 |
dist/index.mjs | 核心的 ESM 入口,类型在 dist/types/ | 由打包工具引入 |
dist/evstats-replay.js / .mjs | rrweb 录制 | 项目打开回放且本访客被抽中 |
dist/evstats-heatmap.js / .mjs | 热力图叠加 | 地址栏带 evstats_heatmap |
浏览器
支持 ES2018 的浏览器:Chrome 64+、Firefox 78+、Safari 12+、Edge 79+。
版本
独立发布到 npm,标签 sdk-web/vX.Y.Z,更新日志在源码仓库的 evs-sdks/web/CHANGELOG.md。服务端升级不要求同时升级 SDK。