本文介绍接入用户体验监控 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/config | 远程配置预取。当前版本在初始化前先拉取该配置,只有返回 enabled 为真时才挂载各监控插件 |
POST {url}/api/v1/collect/events | 标准事件(错误 / 页面性能 / Web Vitals / 接口与资源测速 / 点击与行为 / 挣扎 / 自定义事件等) |
POST {url}/api/v1/collect/replay | 会话回放录屏数据,仅在开启 sessionReplay 后上报 |
{url} 为初始化时填写的上报域名,国内站为 https://dem.rumt-zh.com。其中「远程配置预取」是一道需要特别留意的闸门:若控制台侧未启用该项目,或预取请求失败且本地没有可用的 7 天缓存(
localStorage 键 TDEM_SAMPLE_CONFIG),SDK 会在控制台打印 [TDEM] SDK disabled by remote config, skip initialization,随后直接返回、不初始化任何插件,既不抛异常,也不额外告警。这是接入后「一条数据都没有」最常见的成因,排查时请先确认该配置请求的返回内容。除上述「是否初始化」的闸门外,采集管道入口还有一道事件级采样闸门,两者都通过才会有数据上报。远程配置中的
tdem_sample_rate(0 - 100,控制台配置)决定本次会话是否被采样:取值
0或缺失:即使 enabled=true、插件已正常挂载,所有事件仍会在管道入口被静默丢弃,控制台不会出现任何该项目的日志。取值
100:全部放行。其余取值:按比例随机判定,判定结果在同一会话内保持一致(Session 要么全部上报、要么全部不上报),会话续期时重新抽样。
判定完成前产生的事件会先进入内存队列暂存(上限1000条),判定完成后统一放行或丢弃,因此不存在「部分事件漏报」的情况。在排查「远程已启用但没有数据」时,请确认
/api/v1/config 返回体中的 enabled 与 tdem_sample_rate 两个字段,而不只是 enabled。步骤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 用于自定义业务返回码判定。页面性能与 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_sample_rate 覆盖(远程量纲为0 - 100) |
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。