Skip to content

快速上手

@tripo3d/trace 的核心 API 只有两步:new TripoTrace(params) 创建实例,await trace.initLanding() 完成 device id 加载与渠道归因。

完整流程

ts
import { TripoTrace } from '@tripo3d/trace';

const trace = new TripoTrace({
  baseUrl: 'https://api-cn-test.tripo3d.com',
  onError: (err, ctx) => console.warn('[trace]', ctx, err),
});

// 一次性完成:
// 1. 加载 device id(首次:从 fingerprint 现算并写 localStorage;后续:直接读缓存)
// 2. 检测当前 URL 渠道(v0.1 仅 bd_vid)
// 3. 命中且当日未报 → POST {baseUrl}/v2/attribution/landing
await trace.initLanding();

为什么 initLanding 是异步的

device id 来自 FP.load() —— 内部用 requestIdleCallback 等一帧空闲,保证 Canvas/WebGL 等特征渲染稳定。这一步只在首次访问时跑一次,之后命中 localStorage 缓存。

TripoTraceParams

字段类型 / 默认说明
baseUrlstring(必填)归因服务 base URL,例如 https://api-cn-test.tripo3d.com
channelsChannelName[] / 全部已注册启用的渠道白名单。v0.1 只有 baidu 一个
deviceIdOverridestring业务自管 device id 时显式传入,跳过指纹计算
fetchtypeof fetch / globalThis.fetch注入自定义 fetch,Nuxt 项目可传 $fetch
onError(err, ctx) => void错误回调;ctx.phase 是 init 或 report,便于定位
onReport(payload, channel) => void上报成功钩子,便于业务做埋点链路监控

实例属性 / 方法

名称签名说明
trace.deviceIdstring当前 device id;未 init 或 SSR 下为 ''
trace.headersRecord<string, string>{ 'x-tripo-device-id': string };无 id 时为 {},安全合并
trace.initLanding()() => Promise<void>加载 device id + 渠道检测 + 命中上报。幂等,可重复调用

没有公开的 reportLanding

归因上报是 SDK 内部行为,不暴露给调用方。业务方需要做的只有 new + await initLanding() 两步。

Nuxt 接入

步骤 1:runtimeConfig

ts
// nuxt.config.ts
export default defineNuxtConfig({
  runtimeConfig: {
    public: {
      attributionBaseUrl: 'https://api-cn-test.tripo3d.com',
    },
  },
});

步骤 2:客户端 plugin

app/plugins/05.trace.client.ts.client 后缀让 Nuxt 仅在客户端执行,避免 SSR 阶段执行 fingerprint):

ts
import { TripoTrace } from '@tripo3d/trace';

export default defineNuxtPlugin(async (nuxtApp) => {
  const config = useRuntimeConfig();

  const trace = new TripoTrace({
    baseUrl: config.public.attributionBaseUrl as string,
    onError: (err, ctx) => console.warn('[trace]', ctx, err),
  });

  // 加载 device id + 渠道检测 + 命中则自动上报 landing
  await trace.initLanding();

  // SPA 路由变化时再触发一次(已有当日去重保护,无副作用)
  const router = useRouter();
  router.afterEach(() => {
    void trace.initLanding();
  });

  return {
    provide: { trace },
  };
});

步骤 3:业务请求拦截器

ts
// composables/useApi.ts 或 plugins/api.ts
export const apiFetch = $fetch.create({
  baseURL: useRuntimeConfig().public.apiBase,
  onRequest({ options }) {
    if (import.meta.client) {
      const { $trace } = useNuxtApp();
      Object.assign(options.headers ||= {}, $trace.headers);
    }
  },
});

后续所有用 apiFetch(...) 发出的请求都会自动带上 x-tripo-device-id

SSR 行为

ts
// SSR 阶段
const trace = new TripoTrace({ baseUrl: '...' }); // ✅ 构造器不读 window,安全
await trace.initLanding();                         // ✅ 立即 resolve(no-op)
trace.deviceId                                     // === ''
trace.headers                                      // === {}

业务侧用 .client.ts plugin 后缀就能保证只在客户端执行;即便忘加,库也不会爆错。

下一步

基于 MIT 协议发布(内部使用)