高级用法
自定义渠道
v0.1 内置 baidu(bd_vid)一个渠道。库内部用一个简单的检测器协议:
import type { ChannelDetector } from '@tripo3d/trace';
interface ChannelDetector {
name: ChannelName;
detect: (url: URL) => string | null;
}只要从 URL 中能拿到一个非空字符串,就视为命中(值会作为 click_id 用于业务分析)。
未来要加 google gclid 时只需在库里加:
// channels/google.ts
export const googleChannel: ChannelDetector = {
name: 'google',
detect: url => url.searchParams.get('gclid'),
};然后注册进 channels/index.ts 的 ALL_CHANNELS 列表即可。
自定义 fetch(Nuxt 用 $fetch)
fetch 入参用来注入业务侧已有的 HTTP 客户端:
const trace = new TripoTrace({
baseUrl: 'https://api-cn-test.tripo3d.com',
fetch: $fetch.raw, // Nuxt ofetch 实例
});这样上报请求会复用 Nuxt 的 baseURL、timeout、错误重试等配置。注意自定义 fetch 必须满足 Web Fetch API 签名(接收 url + init,返回 Response)。
为什么不强制注入 $fetch
库不感知 Nuxt,保留原生 fetch 兜底,让 React/Vite/普通 SPA 等场景也能直接用。
错误处理
const trace = new TripoTrace({
baseUrl: '...',
onError: (err, ctx) => {
if (ctx.phase === 'init') {
// device id 加载失败:可能是隐身模式 + Canvas/WebGL 被禁
console.warn('[trace] device id 加载失败', err);
} else if (ctx.phase === 'report') {
// 上报请求失败:网络问题、CORS、5xx
console.warn('[trace] landing 上报失败', ctx.channel, err);
}
},
});库内部不会重试任何失败请求,避免雪崩。失败的 landing 也不会写 dedupe 标记,下次访问同 URL 会重试。
上报成功钩子
const trace = new TripoTrace({
baseUrl: '...',
onReport: (payload, channel) => {
// 用于业务侧的链路监控(比如转发到 Sentry / 数据看板)
myMonitor.track('attribution_landing', { channel, ...payload });
},
});钩子在 dedupe 标记写入之后触发,保证幂等:同一日同一 URL 只会触发一次。
SPA 路由变化
库本身只在 initLanding() 调用时检查一次。SPA 用户从 /?bd_vid=A 跳到 /?bd_vid=B,业务侧需要主动再调一次:
// Vue Router
router.afterEach(() => {
void trace.initLanding();
});initLanding() 是幂等的:
| 场景 | 行为 |
|---|---|
| 第二次调用,URL 没变 | dedupe 命中 → 不发请求 |
| URL 变了但无渠道 | matchChannel 返回 undefined → 不发 |
| URL 变了且命中新 click_id 当日未报 | 正常上报 |
device id 已缓存在内存与 localStorage,第二次起几乎是零成本。
自管 device id(业务自有 ID 体系)
如果业务已经有自己的 visitor id(例如登录用户的 user_id 哈希),可以跳过指纹计算:
const userIdHash = await fetchUserIdFromBackend();
const trace = new TripoTrace({
baseUrl: '...',
deviceIdOverride: userIdHash,
});
await trace.initLanding(); // 直接用 userIdHash 当 device iddeviceIdOverride 也会被写入 localStorage,下次访问继续生效。
注意混用风险
deviceIdOverride 一旦写入 localStorage,再次访问时(即便不传 override)也会用缓存值。如果业务的 user id 体系会变(登出/换号),需要业务侧主动清理 localStorage['tripo:device_id']。
直接调用底层工具
库重导出了 fingerprint 的 hash 函数,便于业务做相关 key 计算:
import { murmurX64Hash128 } from '@tripo3d/trace';
const stableKey = murmurX64Hash128(`my-business-${userId}-${context}`);也直接导出 matchChannel 与 baiduChannel:
import { baiduChannel, matchChannel } from '@tripo3d/trace';
const url = new URL(window.location.href);
console.log(baiduChannel.detect(url)); // 'bd_vid 的值' 或 null
console.log(matchChannel(url)); // 命中的 ChannelDetector完整导出清单
// 主类
export { TripoTrace }
// 类型
export type {
ChannelName,
LandingPayload,
TraceErrorContext,
TripoTraceParams,
ChannelDetector,
}
// 渠道扩展
export { baiduChannel, matchChannel }
// 底层工具
export { murmurX64Hash128 } // re-exported from @tripo3d/fingerprint完整签名见 API Reference。