本文介绍接入用户体验监控 Web SDK 后,如何验证各监控能力的数据上报是否成功。
前提条件
错误监控(
onError)、页面性能(pagePerformance)、Web Vitals(webVitals)、卡顿(lagMonitor)、白屏(blankScreen)、内存监控(memoryMonitor)默认开启。接口测速(
api)、静态资源测速(assets)、点击行为(click)、Console 采集(console)、会话回放(sessionReplay)、挣扎事件监测(struggleMonitor)、WebSocket 错误监控(websocket)、JSBridge 监控(bridge)、上报重试(reportRetry)默认关闭,需显式开启。验证期间建议开启
debug: true,方便观察上报请求与运行日志。单页应用(React / Vue 等)建议显式开启
spa: true,SDK 才会监听路由变化并上报页面浏览事件;该事件同时是挣扎检测中 back_forward 子规则的触发来源。卡顿与内存监控虽默认开启,但存在浏览器前提:卡顿依赖
PerformanceObserver 支持 long-animation-frame,内存监控依赖 window.performance.memory(仅 Chromium 内核)。不满足前提时,这两项会被跳过采集器注册:插件实例仍处于挂载状态,但内部不会创建 PerformanceObserver 或内存采样定时器,因此既不产生任何数据,debug: true 下也不会输出对应告警。排查时不要以「插件已挂载」为依据推断「一定能采到数据」。步骤1:检查上报请求
初始化后,SDK 会发出下列请求(会话回放默认关闭,开启后才有回放上报)。HTTP 2xx 均视为成功:
端点 | 内容 |
POST {url}/api/v1/sample-config | 采样配置预取。该采样配置不决定插件是否挂载——插件都会正常挂载;它只决定每个事件是否上报 |
POST {url}/api/v1/collect/events | 标准事件(错误 / 页面性能 / Web Vitals / 接口与资源测速 / 点击与行为 / 挣扎 / 自定义事件等) |
POST {url}/api/v1/collect/replay | 会话回放录屏数据,仅在开启 sessionReplay 后上报 |
{url} 为初始化时填写的上报域名,国内站为 https://dem.rumt-zh.com。其中「采样配置预取」不是初始化闸门:请求结束后插件照常挂载。未获取到有效配置时,采样行为按以下顺序回落:
①
localStorage 键 TDEM_SAMPLE_CONFIG 中的缓存(仅对同一 project_key 有效,7天内有效);② 初始化配置中的
sampleConfig(若传入);③ 内置默认。若
sampleConfigPreference 配为 local-first,① 与 ② 互换。内置默认下事件全部上报,但 replay.enabled 为 false 且与本地 sessionReplay.enabled 取与,因此未成功获取远程配置时会话回放不会生效。采集管道入口有一道事件级采样闸门,远程下发的采样配置中
event 部分决定各事件是否被放行:event.enabled 为 false:所有事件在管道入口被静默丢弃,控制台不会出现任何该项目的日志。该开关默认为 true。event.types[事件类型].sample_rate 取值100:该类型事件全部放行。其余取值:按比例逐个事件独立随机判定,取值
0则全部丢弃;未在 types 中显式配置的事件类型默认按 100 处理。与旧版本不同,Web 端的采样是按事件独立抽签的,不再对整个会话「要么全报、要么全不报」。判定完成前产生的事件会先进入内存队列暂存(上限1000条),判定完成后统一放行或丢弃。在排查「没有数据」时,请确认
/api/v1/sample-config 返回体中 event.enabled 与对应事件类型的 sample_rate 两个字段。步骤2:验证各监控能力
错误监控
初始化后,可在页面中主动触发 JS 错误来验证:
// 触发未捕获的 JS 异常setTimeout(() => { throw new Error('tdem verify error'); }, 0);// 触发 Promise 未捕获异常Promise.reject(new Error('tdem verify promise error'));
接口测速
开启
api: true 后,SDK 会自动监听 XMLHttpRequest / fetch 请求并上报耗时与错误:const tdem = new TDEM({id: '<project-key>',url: 'https://dem.rumt-zh.com',api: true,});
api 传对象时还可精细控制采集内容:apiDetail 为 true 时一并采集请求体与响应体,reqHeaders / resHeaders 指定需要附带采集的请求头 / 响应头,reportRequest 控制普通请求是否上报,retCodeHandler 用于自定义业务返回码判定。api 开启后,SSE(Content-Type: text/event-stream)连接也会被一并采集,无需额外配置,也没有独立开关。可在控制台的接口分析中按事件类型 sse_call 查看:正常结束的连接
outcome 为 success;连接中途断开为
transport_error;响应码 ≥ 400为
http_error;超过
api.sseStallThresholdMs(默认60000ms)未收到新消息则记为 stalled。若希望更快发现卡流,可调小该阈值,例如:
const tdem = new TDEM({id: '<project-key>',url: 'https://dem.rumt-zh.com',api: { sseStallThresholdMs: 15000 },});
大模型 SSE 体验监控
大模型应用普遍用 SSE(Server-Sent Events)流式返回内容,普通 HTTP 请求指标看不出「首字慢」、「长时间不吐字」、「流中断」这类问题。Web SDK 在接口测速之上对 SSE 流单独采集,上报
sse_call 事件(event_category 为 network),控制台可据此分析首次消息时延、卡死率与流畅度。接入前提:业务侧使用 XMLHttpRequest、fetch 或 EventSource 发起请求,且响应头
Content-Type 为 text/event-stream。XHR 与 fetch 按该响应头识别;EventSource 实例本身即为 SSE,SDK 直接接管其 message 与 error 事件计数,不再判断响应头。自行拼连接、手工解析流式文本的写法不采集。开关:跟随
api 开关,没有独立的 SSE 开关。api 关闭时,SSE 与普通接口一并停止采集。停滞阈值:
api.sseStallThresholdMs(默认60000ms),取值与示例见上一节。某条连接一旦被判定为 stalled 并上报,该连接不再重复上报。resource_type 为 sse 的 sse_call 事件,字段分三组:连接:
http_method、outcome(success / http_error / transport_error / cancelled / stalled)、http_status(拿到响应码时才有)、original_url(请求发生重定向时才有)时长与归属:
duration(连接总时长)、redirect_count(是否重定向,取值 0 或 1)、stall_threshold_ms(本次生效的停滞阈值,每条必带)、url、replay_id流式特征:
message_count(收到的 SSE 消息条数)、time_to_first_message(首条消息相对请求发起的耗时,收到过消息才有)、last_message_offset(最后一条消息的时间偏移,收到过消息才有)、max_message_gap(最大消息间隔,消息数不少于2时才有),以及6档间隔计数 gap_lt_500_count / gap_500_999_count / gap_1000_2999_count / gap_3000_9999_count / gap_10000_59999_count / gap_ge_60000_count验证方式:在控制台 大模型体验 查看首次消息时延、卡死率与流畅度,或在接口分析中按事件类型
sse_call 确认连接明细;也可在浏览器 Network 面板确认目标请求已产生 sse_call 上报。控制台按 token 计算的吞吐率依赖 token 计数,Web 端 SDK 采集的是消息条数而非 token 数,也不提供模型版本标识,因此「模型版本」维度与 token 吞吐率不适用于 Web 数据。页面性能与 Web Vitals
pagePerformance 与 webVitals 默认开启,无需额外配置。页面加载完成后,SDK 会自动上报首屏耗时及 FCP / LCP / CLS 等指标。卡顿、白屏与内存监控
lagMonitor、blankScreen、memoryMonitor 默认开启:卡顿:主线程出现长任务(long-animation-frame)时自动上报。该监控有两个阈值:
threshold(默认2000ms,长任务上报门槛)与 noResponseThreshold(默认5000ms,超过即记为无响应事件)。两者存在联动约束,当配置的 noResponseThreshold <= threshold 时,SDK 会将其静默抬升为 max(5000, threshold + 1) 并输出 relation_conflict 告警。例如把 threshold 调到6000,noResponseThreshold 会被改成 6001,而不是您配置的值。白屏:页面采样点空白占比超过阈值(默认70%)时自动上报白屏事件。
内存:定时上报 JS 堆内存占用,超过
oomThreshold 时上报 OOM 事件。WebSocket 错误监控
开启
websocket: true 后,SDK 会拦截 WebSocket 连接错误并上报:const tdem = new TDEM({id: '<project-key>',url: 'https://dem.rumt-zh.com',websocket: true,});
需要说明的是,WebSocket 采集并非独立插件,而是错误监控(
onError)内部的一段逻辑:websocket 只是它的子开关,命中后上报的仍是一条 js_error 族事件(mechanism_type 为 websocket,连接地址记在标签 websocket_url 中)。该能力随错误监控一同挂载,关闭 onError 会一并关闭 WebSocket 采集;websocket 也可写成对象形式 { enabled: true }。JSBridge 监控
开启
bridge 并指定目标与方法白名单后,SDK 会覆写对应 JSBridge 方法并上报耗时:const tdem = new TDEM({id: '<project-key>',url: 'https://dem.rumt-zh.com',bridge: {target: window.JSBridge,methods: ['callNative'],},});
会话回放
会话回放默认关闭,需要显式开启:
const tdem = new TDEM({id: '<project-key>',url: 'https://dem.rumt-zh.com',sessionReplay: {enabled: true,sessionSampleRate: 0.1, // 体验流采样率(0-1)errorTraceback: true, // 错误回溯开关errorSampleRate: 1.0, // 错误命中率(0-1)},});
四个旋钮的语义如下:
配置 | 默认值 | 说明 |
enabled | false | 是否启用。与远程下发的 enabled 取与,两者都为真才生效 |
sessionSampleRate | 0.1 | 体验流采样率,按会话随机抽取。可被采样配置中 replay.experience_sample_rate 覆盖(该字段量纲为 0 - 100,超出按边界截断);服务端若只给旧名 replay.replay_sample_rate,SDK 也会兼容读取。 |
errorTraceback | true | 错误回溯开关:未抽中体验流的会话若发生错误,也补报该段回放 |
errorSampleRate | 1.0 | 错误命中率,仅在 errorTraceback 为真时生效 |
由此产生三种常见组合:
组合 | 配置 | 会上报回放的会话 |
纯错误回溯 | sessionSampleRate: 0 + errorTraceback: true | 仅含错误的会话 |
体验流并集错误回溯 | sessionSampleRate > 0 + errorTraceback: true | 抽中的体验流会话,并含错误的会话 |
只看体验流 | errorTraceback: false | 仅按 sessionSampleRate 抽取,错误不再补报 |
验证前需知:未命中体验流且开启了错误回溯时,SDK 在内存缓冲区中持续攒数据,若始终没有错误发生,不会因为页面关闭等生命周期事件而 flush。因此在无错误场景下「开了回放却看不到数据」属正常现象。要快速验证,可把
sessionSampleRate 设为 1,或临时改为纯错误回溯并主动触发一次错误。挣扎检测
挣扎检测默认关闭,需显式开启
struggleMonitor: true。它消费 SDK 其他模块产出的事件并按内置规则判定,产出下列子事件(规则版本 1.0.0,阈值内部写死、接入方不可修改):子事件 | 判定规则 |
rage_click | 同一元素1秒内连续点击达5次 |
dead_click | 点击后3秒内未产生任何有效动作(页面跳转 / 接口成功 / 表单操作 / DOM 变更 / 打开新页等) |
error_click | 点击后3秒内出现接口错误或 JS / Promise / 资源错误 |
long_focus_time | 表单控件持续聚焦超过20秒 |
form_zigzag | 表单焦点的最近4次切换呈 a → b → a → b 往复,且已修改字段不少于2个,累计2次后上报 |
uncompleted_form | 页面退出时表单已改动字段占必填项(无必填项时取已触碰字段)的比例达到阈值(默认30%),且期间没有成功提交 |
form_validation_error | 表单提交结果的状态为失败 |
slow_page | 页面 LCP 超过4000ms 或 INP 超过500ms |
back_forward | 页面浏览事件中的导航类型为后退或前进 |
各子事件的事件来源不同,并非全部开箱可用:
rage_click、dead_click、long_focus_time 与三个表单类规则:挣扎检测模块内部自行监听 DOM 点击与表单输入事件,无需其他插件配合,开启后即可生效。error_click:需要点击事件的关联记录,而点击事件由点击行为插件(click,默认关闭)产出,需同时开启 click: true。slow_page:消费页面性能与 Web Vitals 事件,两者默认开启,通常无需额外配置。back_forward:消费页面浏览事件中的导航类型字段,该字段由单页应用能力产出,因此需同时开启 spa: true。自定义挣扎事件:通过
trackStruggle() 主动上报,详见 主动上报。配置为对象时还可按规则分组关闭:
click.enabled / form.enabled / performance.enabled / navigation.enabled 分别对应点击类、表单类、慢页面类与返回类规则。设备信息
设备信息采集由
device 插件负责,始终挂载、没有开关,SDK 会在每次上报的上下文中附带 session_id / platform / user_agent / screen_resolution / language 字段。其中
user_agent / language / screen_resolution 由浏览器环境读取;调用 setUser 后,上下文中还会带上 user_id。另有一组随请求地址参数上报的运行时字段:platform / netType / netStatus / vp(视口尺寸)/ sr(屏幕分辨率),其中:netStatus 依赖宿主注入 getNetworkStatus,浏览器环境下无内置兜底,默认不采集;netType 则优先调用宿主注入的 getNetworkType,未注入时由 SDK 内置实现自行探测(先取 UA 中的 NetType/,再读 navigator.connection.effectiveType),通常仍会带值,探测不到才回落为 unknown。说明:
设备标识由 SDK 自动生成并持久化在
localStorage 键 TDEM_ID 中(配置项 aid 可传自定义字符串覆盖),接入方无需额外维护。验证方式:在控制台打开任一事件的详情,确认事件上下文中的上述字段已填充。
步骤3:主动上报(可选)
除自动采集外,SDK 提供下列主动上报接口。
const tdem = new TDEM({ id: '<project-key>', url: 'https://dem.rumt-zh.com' });// 自定义事件tdem.track('order_submit', {tags: { channel: 'web' },properties: { amount: 99 },});// 自定义测速:可直接传耗时,或 start / end 成对使用tdem.measure('api_latency', 320, { tags: { api: '/user/info' } });tdem.startMeasure('render');// ... 执行操作 ...tdem.endMeasure('render');// 日志与异常:用于上报业务已捕获、未导致页面崩溃的异常tdem.captureMessage('用户完成注册', { level: 'info', tags: { step: 'register' } });try {riskyOperation();} catch (e) {tdem.captureException(e, { tags: { module: 'payment' } });}// 自定义挣扎事件tdem.trackStruggle('submit_blocked', { severity: 'high', tags: { form: 'checkout' } });
用户标识与全局标签:
tdem.setUser('user-456'); // 设置用户标识,用于用户维度聚合tdem.clearUser(); // 清除用户标识tdem.setTags({ role: 'admin', team: 'dev' }); // 设置 / 追加全局标签tdem.removeTags(['team']); // 移除指定标签tdem.clearTags(); // 清空所有标签
页面浏览事件:
tdem.reportPageView('/checkout', { pageTitle: '结算页' }); // 主动上报一次页面浏览tdem.setPage('/checkout'); // 设置当前逻辑页面,后续事件以此为准tdem.leavePage(); // 离开当前逻辑页面
Web Vitals 主动上报:
reportWebVitals 仅在 webVitals 配置为对象且 manualReport: true 时生效,调用后以传入数据覆盖 SDK 采集值后上报:const tdem = new TDEM({id: '<project-key>',url: 'https://dem.rumt-zh.com',webVitals: { manualReport: true },});tdem.reportWebVitals({ LCP: 2500, FCP: 1800 }); // 部分字段自定义,其余沿用 SDK 采集值
步骤4:检查数据上报
在浏览器开发者工具 Network 面板中,观察 SDK 发往采集服务的事件上报请求(默认 POST 到
{url}/api/v1/collect/events),或在控制台查看对应监控能力的数据。其中 {url} 为初始化时填写的上报域名,国内站为 https://dem.rumt-zh.com。