帮你快速理解、总结文档立即下载

API 说明

最近更新时间:2026-09-30 17:29:02
我的收藏
本文详细介绍用户体验监控 Web SDK 的各功能接口,帮助您更灵活、深度地使用 SDK。

初始化

通过 new TDEM(config) 创建实例并自动开始采集。config 除必填的 id 外,还提供一系列可选参数,详见 SDK 初始化。

自定义事件

// 上报自定义事件
tdem.track('button_click', {
tags: { button_id: 'submit' },
properties: { page: '/checkout' },
});

自定义测速

// 直接上报耗时(毫秒)
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.setTags({ role: 'admin', team: 'dev' }); // 设置/追加标签
tdem.removeTags(['team']); // 移除指定标签
tdem.clearTags(); // 清空所有标签

用户标识管理

tdem.setUser('user-456'); // 设置用户
tdem.clearUser(); // 清除用户

页面管理

// 手动上报 PV
tdem.reportPageView('/checkout', { pageTitle: '结算页' });

// 虚拟页面(弹窗、Tab 等)
tdem.setPage('/modal/confirm', { pageTitle: '确认弹窗' });
// 弹窗关闭后恢复
tdem.leavePage();

挣扎事件上报

// 业务主动上报自定义挣扎事件(无需理解或填写 owner)
tdem.trackStruggle('payment_declined', {
severity: 'high', // 可选:low | medium | high,默认 medium;传其他值本次上报会被丢弃
tags: { channel: 'checkout' },
properties: {
reason: 'risk_rejected',
retry_count: 2,
},
});

表单提交结果上报

// 上报表单提交结果(需传 status)
tdem.reportFormSubmitResult({
status: 'success', // 必填:success | fail
eventName: 'form_submit', // 可选:事件名
formId: 'register-form', // 可选:表单标识
fieldId: 'email', // 可选:字段标识
validationCode: 'E001', // 可选:校验码
validationMessage: '邮箱格式错误', // 可选:校验信息(最长 256 字符)
tags: { channel: 'web' }, // 可选:标签
});

原始事件上报

// 直接上报 TDEMEvent 格式的事件(高级用法,SDK 会自动补齐 page_url、replay_id 与 tags)
tdem.reportTDEMEvent({
event_id: 'evt_xxx',
event_type: 'custom',
event_category: 'custom',
timestamp: Date.now(),
page_url: location.href,
data: {
event_name: 'my_event',
tags: { key: 'value' },
},
});

手动上报 Web Vitals

// 需配置 webVitals: { manualReport: true }
tdem.reportWebVitals(); // 使用 SDK 采集的数据
tdem.reportWebVitals({ LCP: 2500, FCP: 1800 }); // 使用自定义数据

扩展设备信息(Bean)

tdem.extendBean('customKey', 'customValue'); // 追加自定义键值到公共 Bean
const bean = tdem.getBean(); // 获取 Bean 查询串,如 id=xxx&uin=yyy&from=zzz

配置修改与销毁

tdem.setConfig({ userId: 'new-user', env: 'gray' }); // 动态修改配置
tdem.destroy(); // 销毁实例
setConfig 对象浅合并进当前配置,不会重新初始化插件。因此只有后续事件读取的字段才真正生效,例如 userId、defaultTags、env、version、pageUrl;插件级开关(如 sessionReplay、struggleMonitor 的 enabled)需在初始化时确定,运行期修改不会重新挂载对应插件。
与之相对,setUser / setTags 这类接口本身就是对上述字段的封装,可放心在运行期调用:
tdem.setUser('user-456'); // 等价于 setConfig({ userId: 'user-456' })
tdem.setTags({ role: 'admin' }); // 追加进 defaultTags,与事件级 tags 自动合并
destroy() 用于彻底结束实例:注销已挂载的插件、清空生命周期,并用空实现替换实例方法。默认保留对象外壳以规避外部持有的引用报错,传入 destroy(true) 会进一步清空对象属性并断开原型链。
以上接口均需在 SDK 初始化(创建实例)之后调用。

回调钩子

SDK 提供一组回调钩子,用于接管上报链路上的关键判定。除 api.retCodeHandlerAsync 为异步形式外,其余回调都在 SDK 内部同步调用。
各回调对异常的处理并不统一:一部分在调用处带 try/catch,抛错会被吞掉并按原值继续(如 beforeReport、beforeRequest、api.retCodeHandler、api.isSlowApi);另一部分没有兜底,抛错会向上抛出(如 afterRequest、pagePerformance.urlHandler、api.resourceTypeHandler)。因此建议所有回调内部自行 try/catch,不要依赖 SDK 的兜底。
接口类回调(配置在 api 下):
配置项
说明
api.retCodeHandler
(responseBody, url, ctx, payload) => { code, isErr },自定义业务返回码解析。返回的 code 作为上报中的返回码,isErr 为 true 时按失败请求处理;未返回 code 或回调抛错时回落为 unknown。
api.retCodeHandlerAsync
(responseBody, url, ctx, callback) => void,异步版返回码解析。参数 callback 是回调函数,需在其内部调用 callback({ code, isErr }) 回填结果。该回调只在 XHR 链路上生效,fetch 请求不会读取它;在 XHR 链路上它优先于 retCodeHandler。
api.resourceTypeHandler
(url) => string,自定义资源类型判定,返回值作为上报的资源类型,未返回时回落为 static。
api.reqParamHandler
(body, url, ctx) => any,自定义请求参数处理,仅在 apiDetail 为 true 时生效;返回值会被序列化后截断至 10240 字符写入上报。
api.resBodyHandler
(response, url, ctx) => any,自定义响应体处理,仅在 apiDetail 为 true 时生效;返回值同样序列化后截断至 10240 字符。
api.isSlowApi
({ duration }) => boolean,自定义慢请求判定,返回 true 即按慢请求上报;抛错时回落为 false 并输出 [TDEM] isSlowApi function happen error 警告。
说明:
慢请求判定是一条短路链:配置了 api.isSlowApi 就只以它的返回值为准(不再看阈值);未配置时用 api.slowThreshold;两者都没有时用内置默认 1000ms。
生命周期回调(配置在顶层):
配置项
说明
beforeReport
(log) => boolean,单条事件上报前过滤,返回 false 丢弃该条。
beforeRequest
({ logs, logType }) => logs | false,请求发出前处理,可整体替换 logs,返回 false 丢弃。
afterRequest
(log) => boolean,请求发出后回调,返回 false 阻断上报。
beforeReportSpeed
(log) => boolean,测速事件上报前过滤。
插件回调:
配置项
说明
pagePerformance.urlHandler
() => string,自定义页面地址获取函数,返回值经 encodeURIComponent 后作为上报的 page_url。
blankScreen.customBlankScreenDector
() => boolean,自定义白屏检测,返回 true 判定为白屏;抛错时回落为 false,默认 null。
sessionReplay.beforeSend
(payload) => payload | null,回放数据上传前回调,返回 null 取消本次上传。
sessionReplay.onError
(error: Error) => void,回放数据上传失败回调。回放上传有独立于 reportRetry 的失败重试:最多重试 3 次,间隔按 1s / 2s / 4s 指数退避。此回调仅用于业务侧旁路记录,不影响上述重试行为。
struggleMonitor.custom.detector
({ event, tdem }) => ReportStruggleParams | ReportStruggleParams[] | null | void,自定义挣扎事件检测器,入参可拿到当前事件与 SDK 实例;返回空值表示本次不产生挣扎事件。
retCodeHandler 用于把业务自定义的返回码约定翻译成 SDK 可理解的成功/失败,适用于后端统一在响应体里返回 code 字段、HTTP 状态码恒为200的场景:
const tdem = new TDEM({
id: 'YOUR_APP_ID',
api: {
// 4 个参数:响应体、请求 URL、请求上下文、请求体
retCodeHandler(responseBody, url, ctx, payload) {
let data = responseBody;
if (typeof data === 'string') {
try { data = JSON.parse(data); } catch (_e) {}
}
const code = String(data?.body?.code ?? '');
// isErr 为 true 时按失败请求上报
return { code, isErr: code !== '0' && code !== '200' };
},
},
});
若返回码需要异步解析(例如要先解密或查缓存),改用 retCodeHandlerAsync。此时第4个参数是回调函数,必须在拿到结果后调用它:
const tdem = new TDEM({
id: 'YOUR_APP_ID',
api: {
// 第 4 个参数是回调函数,必须调用它回填结果
retCodeHandlerAsync(responseBody, url, ctx, callback) {
checkCode(responseBody).then(({ code, isErr }) => {
callback({ code: String(code), isErr });
});
},
},
});
同时在 XHR 链路配置两个回调时,只有 retCodeHandlerAsync 会执行;fetch 链路始终走 retCodeHandler,因为它不读取异步版。
isSlowApi 适合按业务语义判定慢请求,优先级高于 slowThreshold:
const tdem = new TDEM({
id: 'YOUR_APP_ID',
api: {
slowThreshold: 2000,
// 优先级高于 slowThreshold;返回 true 即按慢请求上报
isSlowApi({ duration }) {
return duration > 3000;
},
},
});
beforeReport 可在事件真正入队前做最后一道过滤,返回 false 的事件会被丢弃:
const tdem = new TDEM({
id: 'YOUR_APP_ID',
// 返回 false 丢弃该条事件
beforeReport(log) {
return !(log.url && log.url.includes('/health'));
},
});
struggleMonitor.custom.detector 用于把业务自己的「受挫信号」接入挣扎事件,返回的对象会被 SDK 自动补齐 type(默认 custom_struggle)、ownerType(默认 app)与 ownerKey(默认当前页面地址):
const tdem = new TDEM({
id: 'YOUR_APP_ID',
struggleMonitor: {
enabled: true,
custom: {
enabled: true,
// 返回空值表示本次不产生挣扎事件
detector({ event, tdem }) {
if (event.data?.event_name !== 'checkout_failed') return null;
return {
ownerKey: '/checkout',
payload: { reason: 'risk_rejected' },
};
},
},
},
});
reportRetry 的 retryInterval 同样支持传函数,按已重试次数动态计算下次重试间隔(毫秒),默认实现为 (retriedCount) => 1000 * (2 << retriedCount),即按2s / 4s / 8s 指数退避:
const tdem = new TDEM({
id: 'YOUR_APP_ID',
reportRetry: {
maxRetryCount: 10,
retryInterval: (retriedCount) => 1000 * Math.pow(2, retriedCount),
whenRetryEndStillFail: 'discard',
},
});
另有2个回调在运行时生效,但未出现在 .d.ts 类型声明中。接入方从类型提示看不到它们,属于「可用未公开」,使用前请以实际接入版本的运行结果为准:
onBeforeRequest:(requestOptions, tdem) => requestOptions | false,上报请求真正发出前的最后一站。可改写 requestOptions(含 url / method / data / sendBeacon 等)后返回;返回假值则丢弃本次请求并输出 Sending request blocked 警告;返回对象但缺少 url 时会输出参数提示警告。
modifyRequest:(requestOptions) => requestOptions,同为请求改写钩子,但只接受「返回带 url 的对象」这一种改写方式;抛错不会中断链路,仅输出 console.error。

其余回调的配置示例

api.resourceTypeHandler:自定义资源类型,返回值写进上报的 type 字段,未返回时回落 static:
const tdem = new TDEM({
id: 'YOUR_APP_ID',
api: {
// 入参是资源 URL,返回自定义类型字符串
resourceTypeHandler(url) {
if (/\\.(png|jpg|jpeg|webp|gif)$/i.test(url)) return 'image';
if (/\\.(js|css)$/i.test(url)) return 'static';
return 'static';
},
},
});
api.reqParamHandler / api.resBodyHandler: 仅在 apiDetail 为 true 时生效,用于把请求体 / 响应体里的业务字段带进上报。注意是位置参数,ctx 在 fetch 链路下为 undefined:
const tdem = new TDEM({
id: 'YOUR_APP_ID',
api: {
apiDetail: true,
// (请求体, 请求 URL, 上下文)
reqParamHandler(body, url, ctx) {
return typeof body === 'string' ? body.slice(0, 500) : JSON.stringify(body);
},
// (响应体, 请求 URL, 上下文)
resBodyHandler(response, url, ctx) {
const text = typeof response === 'string' ? response : JSON.stringify(response);
return text.slice(0, 500);
},
},
});
beforeRequest:请求发出前可整体替换或丢弃:
const tdem = new TDEM({
id: 'YOUR_APP_ID',
beforeRequest({ logs, logType }) {
// 返回 false 丢弃;返回 { logs, logType } 可整体替换
if (logType === 'speed') return false;
return { logs, logType };
},
});
afterRequest:请求发出后的最后一道闸门,返回 false 阻断上报:
const tdem = new TDEM({
id: 'YOUR_APP_ID',
// 返回 false 阻断上报;此处屏蔽自身采集接口,避免自采集
afterRequest(log) {
return !String(log.url || '').includes('/api/v1/collect');
},
});
beforeReportSpeed:测速事件上报前过滤,返回 false 丢弃:
const tdem = new TDEM({
id: 'YOUR_APP_ID',
beforeReportSpeed(log) {
return !String(log.url || '').includes('favicon');
},
});
pagePerformance.urlHandler:自定义页面地址来源,SDK 会在返回值外层再套一次 encodeURIComponent:
const tdem = new TDEM({
id: 'YOUR_APP_ID',
pagePerformance: {
urlHandler() {
return location.pathname + location.search;
},
},
});
blankScreen.customBlankScreenDector:必须严格返回 true 才判定白屏;返回其他值或抛错都视为非白屏:
const tdem = new TDEM({
id: 'YOUR_APP_ID',
blankScreen: {
enabled: true,
customBlankScreenDector() {
const root = document.getElementById('app');
return !!root && root.children.length === 0;
},
},
});
sessionReplay.beforeSend / sessionReplay.onError:回放上传前的改写与失败旁路:
const tdem = new TDEM({
id: 'YOUR_APP_ID',
sessionReplay: {
enabled: true,
// 返回假值(如 null)取消本次回放上传
beforeSend(payload) {
if (payload.events && payload.events.length > 5000) return null;
return payload;
},
// 上传失败时回调;SDK 自身仍会按 3 次指数退避重试
onError(error) {
console.warn('[replay] upload failed', error);
},
},
});
onBeforeRequest / modifyRequest:请求发出前的改写钩子(未在类型声明中暴露):
const tdem = new TDEM({
id: 'YOUR_APP_ID',
// 返回假值则丢弃本次上报请求
onBeforeRequest(options, tdem) {
return options;
},
// 只接受「返回带 url 的对象」这一种改写方式
modifyRequest(options) {
return options;
},
});

上报就绪与延迟上报

SDK 默认在采集后立即上报(reportImmediately 默认 true)。若将其设为 false,事件不会立刻发出,而是先进入等待队列:
const tdem = new TDEM({
id: '<project-key>',
url: 'https://dem.rumt-zh.com',
reportImmediately: false, // 采集后不立即上报,先入队等待
});

// 业务关键节点就绪后放行队列
tdem.ready();
ready() 会逐个消费等待队列并开始上报;重复调用同样安全,队列为空时不做任何事。
未调用 ready() 时队列会持续积压,控制台看不到任何上报请求:排查「配置了 reportImmediately: false 后没有数据」时,先确认是否遗漏了这一调用。

版本与环境

TDEM.version; // SDK 版本号(静态属性)
tdem.sdkVersion; // 当前实例的 SDK 版本号
TDEM.environment; // 环境枚举,同时兼容其他端 SDK 的环境名
tdem.config.env; // 当前实例实际生效的环境值
TDEM.version 与 tdem.sdkVersion 取值一致,均来自构建期注入的 SDK 版本。
env 传给 SDK 后若不属于环境枚举,会被归一为 others。

回放脱敏标记

会话回放会录制页面 DOM 与文本,SDK 默认开启高强度脱敏。除配置式开关外,还支持在 HTML 上直接标注,按元素粒度控制录制内容。
在元素上加下列属性即可(对子元素就近生效,即父容器标注会覆盖其后代):
HTML 属性
效果
data-tdem-mask
该元素文本被遮罩,等价于默认遮罩类名 tdem-mask
data-tdem-block
该元素整体不录制,回放中呈现为空占位
data-tdem-ignore
该元素及其子树完全忽略,不产生任何录制数据
<div data-tdem-mask>这段文本在回放中会被遮罩</div>
<div data-tdem-block>这块区域整体不录制</div>
<div data-tdem-ignore>整个子树都会被忽略</div>
SDK 同时内置一批默认选择器,语义与上表相互对应:
类别
默认选择器
遮罩
.tdem-mask、[data-tdem-mask]、[data-sensitive]、.sensitive、.private
阻止录制
.tdem-block、[data-tdem-block]、.secret、[data-secret]、iframe[srcdoc]:not([src])、.replayer-wrapper
忽略录制
.tdem-ignore、[data-tdem-ignore]、input[type="file"]、input[type="password"]
自定义选择器与默认选择器是累加关系,不会覆盖掉内置的默认值。也可通过 sessionReplay.privacy 统一声明:
const tdem = new TDEM({
id: '<project-key>',
url: 'https://dem.rumt-zh.com',
sessionReplay: {
enabled: true,
privacy: {
mask: ['.my-mask'], // 追加遮罩选择器
block: ['.my-block'], // 追加阻止录制选择器
ignore: ['.my-ignore'], // 追加忽略录制选择器
},
},
});
默认遮罩策略为全量遮罩:所有文本与所有输入框均被遮罩,媒体元素整体阻止录制。
maskAllText 不是独立旋钮,它随 maskAllInputs 联动。maskAllInputs 为 false 时它才为 false,该字段的独立配置不生效。
此外 SDK 默认开启敏感数据自动检测,会在文本被记录前做脱敏,覆盖手机号、身份证号、邮箱、银行卡号四类。如需完全接管脱敏,可将 privacy.autoDetectSensitiveData 设为 false,并通过 privacy.maskTextFn 提供自定义脱敏函数:
sessionReplay: {
enabled: true,
privacy: {
autoDetectSensitiveData: false,
maskTextFn: (text) => text.replace(/机密/g, '[已脱敏]'),
},
}
纳入自动检测的四类内容与脱敏后的形态:
类型
脱敏后形态
手机号
保留前3位与后4位,中间替换为 ****
身份证号
保留前6位与后4位,中间替换为 ********
邮箱
用户名保留首尾字符,中间替换为 ***,域名不变
银行卡号
保留前4位与后4位,中间替换为 **** ****
注意:
SDK 侧脱敏只作用于录制数据,不能替代服务端自身的隐私处理流程。

行为属性标记

除主动上报接口外,SDK 支持用 HTML 属性向挣扎检测声明业务语义,用于避免误判。两者都支持就近祖先匹配:
HTML 属性
效果
data-tdem-ignore-dead-click
命中时不为该元素安排死点击判定
data-tdem-effective-action
命中时将该元素视为有效操作,消解同期待判定的死点击
<!-- 明确不需要判定的装饰性入口 -->
<button data-tdem-ignore-dead-click>查看更多</button>

<!-- 点击后由业务自行处理跳转,SDK 不应判为死点击 -->
<div data-tdem-effective-action>提交订单</div>
这两项标记仅在开启 struggleMonitor 后生效(该插件默认关闭)。等价能力也可通过配置声明选择器:
struggleMonitor: {
enabled: true,
click: {
ignoreDeadClickSelectors: ['.js-no-dead-click'],
effectiveActionSelectors: ['.js-effective-action'],
},
}

环境枚举

TDEM.environment.production // 生产环境
TDEM.environment.development // 开发环境
TDEM.environment.gray // 灰度环境
TDEM.environment.pre // 预发布环境
TDEM.environment.daily // 日发布环境
TDEM.environment.local // 本地环境
TDEM.environment.test // 测试环境
TDEM.environment.others // 其他环境