news 2026/9/12 11:32:54

在 Supabase Auth 回调中接入 Dub Lead 转化跟踪:从 `dub_id` Cookie 归因到 Sign Up 事件上报

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
在 Supabase Auth 回调中接入 Dub Lead 转化跟踪:从 `dub_id` Cookie 归因到 Sign Up 事件上报

在 Supabase Auth 回调中接入 Dub Lead 转化跟踪:从dub_idCookie 归因到 Sign Up 事件上报

【免费下载链接】dubThe modern link attribution platform. Loved by world-class marketing teams like Framer, Perplexity, Superhuman, Twilio, Buffer and more.项目地址: https://gitcode.com/GitHub_Trending/du/dub

本文基于 Dub 开源仓库中的官方集成指南,完整讲解如何在基于 Supabase 的 Next.js 应用里,通过在/api/auth/callback回调路由中上报 Lead 转化事件,把"点击 Dub 短链 → 注册成为新用户"这一链路以可归因的方式接入 Dub 的分析与归因体系。读完本文,你将掌握dub.track.lead的完整调用方式、dub_idCookie 的来源与生命周期,以及如何用 10 分钟新用户窗口精确区分"新注册"与"老用户登录",避免重复上报与归因污染。

一、背景:Dub 的转化归因模型为什么依赖dub_id

Dub 的转化归因(Lead / Sale 归因)核心思路是:一次点击对应一个全局唯一的点击 ID(clickId),后续发生的转化事件必须携带该 ID 才能回溯到来源链接

在 Dub 的短链跳转链路中,当用户点击一个启用了转化跟踪(trackConversion)的短链时,服务端会为该次点击生成一个 16 位随机 ID(nanoid(16)),并以 Cookie 形式种在浏览器里。从仓库源码 lib/middleware/link.ts 可以看到这一机制的实现细节:

  • Cookie 的命名格式为dub_id_{domain}_{key},例如访问dub.sh/launch后浏览器会持有名为dub_id_dub.sh_launch的 Cookie;
  • 只有当链接满足"启用转化跟踪 / 合作伙伴链接 / Singular、AppsFlyer 跟踪 URL"等条件时,点击 ID 才会被缓存(shouldCacheClickId),从而支撑后续的/track/lead请求归因;
  • 若命中 Redis 中缓存的点击记录,会复用原 clickId,否则新生成一个。

而 Dub 的客户端分析脚本(gtm-client-sdk.md 中提到的dubcdn.com/analytics/script.js)与各类 SDK 在对外接口上统一将归因标识暴露为dub_idCookie。因此,在应用服务端读取dub_idCookie,就等价于拿到"用户是经由哪一次 Dub 点击进入本站"这一归因信息。

二、集成前提:准备好 Supabase 客户端与 Dub SDK

在编写回调路由之前,你的应用需要具备以下基础能力:

  1. Supabase 服务端客户端:用于在回调中通过exchangeCodeForSession完成 OAuth Code 换取会话。指南中的示例引用了@/lib/supabase/server,即应用内对 Supabase SSR 客户端的封装,通常基于@supabase/ssrcreateServerClient实现,并接收cookies()作为存储。
  2. Dub SDK 客户端:指南中的import { dub } from "@/lib/dub"对应应用内对 Dub TypeScript SDK 的实例化。仓库自身就是这么做的,见 apps/web/lib/dub.ts:
import { Dub } from "dub"; export const dub = new Dub();

new Dub()默认读取DUB_API_KEY环境变量作为鉴权凭据。因此请确保在部署环境中配置了DUB_API_KEY(可在 Dub 后台的 Tokens 页面生成),否则dub.track.lead会因缺少凭证而失败。

三、核心工作流:三步完成 Lead 事件上报

指南给出的整体思路可以浓缩为以下三步:

  1. 检查dub_idCookie 是否存在:存在说明该用户确实是通过 Dub 短链点击进入的,具有归因价值;
  2. 判断是否为"新注册用户":通过user.created_at是否落在最近 10 分钟窗口内来判定,避免老用户每次登录都重复上报;
  3. 上报 Lead 事件并清理 Cookie:调用dub.track.lead把点击 ID 与用户身份绑定,随后删除dub_idCookie。

三步全部发生在 Supabase 的 Auth 回调中,因为这是服务端唯一能同时拿到"OAuth 用户信息 + 请求 Cookie"的位置。

四、完整实现:在/api/auth/callback中上报 Lead

以下为指南提供的完整代码,并补充了关键注释说明:

// app/api/auth/callback/route.ts import { dub } from "@/lib/dub"; import { createClient } from "@/lib/supabase/server"; import { waitUntil } from "@vercel/functions"; import { cookies } from "next/headers"; import { NextResponse } from "next/server"; export async function GET(request: Request) { const { searchParams, origin } = new URL(request.url); const code = searchParams.get("code"); // if "next" is in param, use it as the redirect URL const next = searchParams.get("next") ?? "/"; if (code) { const supabase = createClient(cookies()); const { data, error } = await supabase.auth.exchangeCodeForSession(code); if (!error) { const { user } = data; const dub_id = cookies().get("dub_id")?.value; // if the user is created in the last 10 minutes, consider them new const isNewUser = new Date(user.created_at) > new Date(Date.now() - 10 * 60 * 1000); // if the user is new and has a dub_id cookie, track the lead if (dub_id && isNewUser) { waitUntil( dub.track.lead({ clickId: dub_id, eventName: "Sign Up", customerExternalId: user.id, customerName: user.user_metadata.name, customerEmail: user.email, customerAvatar: user.user_metadata.avatar_url, }), ); // delete the clickId cookie cookies().delete("dub_id"); } return NextResponse.redirect(`${origin}${next}`); } } // return the user to an error page with instructions return NextResponse.redirect(`${origin}/auth/auth-code-error`); }

实现要点逐条拆解:

  • exchangeCodeForSession(code):Supabase Auth 的标准授权码交换流程。这里必须先于 Lead 上报完成,因为只有拿到data.user才能获得created_atuser_metadata等判断与上报所需的用户信息。
  • dub_id的读取时机:务必在next/headerscookies()上下文中读取,且 Cookie 名保持与 Dub 客户端脚本写入的一致。
  • isNewUser的 10 分钟窗口Date.now() - 10 * 60 * 1000是一个经验阈值,用于容忍注册流程中可能存在的网络延迟与重定向耗时;超过该窗口的用户会被视为老用户,不会重复上报。
  • waitUntil包裹上报:来自@vercel/functions,它允许异步任务在响应返回后继续执行,从而不阻塞注册回调的重定向,把dub.track.lead变成"发后即忘"的后台任务。这与 Dub 的异步跟踪模式一脉相承(见下文mode: "async")。
  • customerExternalId: user.id:以 Supabase 用户 ID 作为客户外部标识,此后该用户的所有后续事件(Sale 等)都会以这个 ID 为准进行归因聚合。
  • 删除 Cookie 的时机:在成功上报后立即删除,保证同一个浏览器后续登录时不会再触发重复上报。

五、dub.track.lead参数详解与可选字段

指南示例使用了 6 个参数,但 Dub 的 Lead 跟踪接口还支持更多可选字段。仓库的请求校验 Schema 定义在 apps/web/lib/zod/schemas/leads.ts,各参数说明如下:

参数类型必填说明
clickIdstring点击的唯一 ID,即从dub_idCookie 读取的值,用于将 Lead 归因到具体点击
eventNamestringLead 事件名称,最长 255 字符,同时可作为后续 Sale 事件关联的标识(通过/track/saleleadEventName属性)
customerExternalIdstring你系统中客户的唯一 ID(此处为 Supabaseuser.id),最长 100 字符,将作为该客户所有后续事件的归因主键
customerNamestring客户姓名,最长 100 字符;不传时 Dub 会生成随机名称(如 "Big Red Caribou")
customerEmailstring客户邮箱,需符合 email 格式,最长 100 字符
customerAvatarstring客户头像 URL
modeenum(async/wait/deferred)默认async:不阻塞当前请求;wait:阻塞直到 Lead 完全落库;deferred:延后到后续请求再创建
eventQuantitynumber事件数值(如免费试用开通的席位数量),设为 N 则该 Lead 会被记录 N 次,范围 1-100
metadataobject附加元数据,总长不超过 10,000 字符

两个值得留意的细节:

  • clickId也支持延迟归因:Schema 注释指出,如果传入空字符串,Dub 会尝试按customerExternalId查找已存在的客户并复用其clickId。这为"回调中拿不到 Cookie"的边缘场景提供了兜底方案。
  • mode默认值是async:这意味着即使不手动包一层waitUntildub.track.lead本身也设计为不阻塞调用方;waitUntil的作用是让任务在响应返回后继续存活,两者配合效果最佳。

六、防重复上报的两种手段:新用户窗口 + Cookie 删除

这套方案的健壮性建立在两道保险之上:

  1. 时间窗口过滤:只对created_at在最近 10 分钟内的用户上报。即便回调被重放、或用户刷新页面,只要不是"新注册",就不会再次上报。
  2. 一次性 Cookie:上报成功后立即cookies().delete("dub_id")。Cookie 被消费后即失效,从根源上杜绝同一次点击产生多条 Lead 的可能。

仓库自身的认证链路采用了同样的"读 Cookie → 上报 → 删除"模式作为佐证。在 apps/web/lib/auth/track-dub-lead.ts 中,Dub 的 NextAuth 集成同样先读取dub_id,调用dub.track.lead(事件名同样为"Sign Up"),然后删除dub_iddub_partner_data两个 Cookie。这说明"上报即删除"是 Dub 官方集成的标准做法,且合作伙伴归因数据(dub_partner_data)也会在同一步骤被清理,避免敏感归因信息长期驻留浏览器。

七、方案对比:Supabase 与 NextAuth / Auth0 / Clerk 集成方式的异同

本指南属于 Dub 认证集成系列中的一篇,同一套"dub_idCookie 归因"心智模型在其他认证方案中均有对应实现,可互相参照:

  • NextAuth:在signIn事件回调中通过message.isNewUser判断新用户,逻辑与本文的isNewUser等价,但判断责任由 NextAuth 承担;
  • Auth0:在afterCallback中通过"数据库中是否已存在该邮箱用户"来判断新旧,同样读取dub_id、上报、删 Cookie;
  • Clerk:走客户端 Server Action / API 路由路线,用user.publicMetadata.dubClickId标记"该用户是否已上报",实现幂等。

可以看到,不同认证体系只是"新用户判定"与"上报触发点"不同,核心的dub.track.lead({ clickId, eventName, customerExternalId, ... })调用与dub_idCookie 读取逻辑完全一致。这意味着你可以在多认证方案共存的架构中复用同一套归因上报封装。

八、验证与排错建议

完成接入后,建议按以下顺序验证链路是否打通:

  1. 确认 Cookie 已种下:先访问一条启用了转化跟踪的 Dub 短链,在浏览器 DevTools 的 Application → Cookies 中确认dub_id(或dub_id_{domain}_{key})已写入;
  2. 触发一次真实注册:带着该 Cookie 完成 Supabase Auth 注册流程,观察回调路由是否命中dub_id && isNewUser分支;
  3. 检查请求与后台:在 Network 面板确认存在发往 Dub 跟踪端点的请求,并在 Dub 控制台的 Lead 事件分析中看到对应记录;
  4. 验证幂等性:注册完成后再次登录同一账号,确认没有产生第二条 Lead 记录——这同时验证了 10 分钟窗口与 Cookie 删除两道保险。

若事件未上报,优先排查:DUB_API_KEY是否配置、dub_idCookie 是否在请求作用域内可读、user.created_at是否真的落在 10 分钟窗口内,以及@vercel/functionswaitUntil是否被正确引入。

相关文档

  • Dub 官方指南:NextAuth 集成
  • Dub 官方指南:Auth0 集成
  • Dub 官方指南:Clerk 集成
  • Dub 官方指南:GTM 埋点跟踪
  • Dub 官方指南:手动调用 SDK / REST API 跟踪
  • 仓库内 Dub SDK 客户端实例
  • 仓库内 Lead 请求参数 Schema(含全部字段约束)
  • 仓库内短链中间件对dub_id_{domain}_{key}Cookie 的写入逻辑

【免费下载链接】dubThe modern link attribution platform. Loved by world-class marketing teams like Framer, Perplexity, Superhuman, Twilio, Buffer and more.项目地址: https://gitcode.com/GitHub_Trending/du/dub

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/12 11:30:37

Django框架在农家乐预约系统开发中的实践与优化

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/12 11:30:29

OpenClaw三大落地路径:PolarDB Agent Express、ArkClaw与DatabaseClaw选型指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/12 11:30:15

AI论文写作工具测评:提升本科生论文效率的10款神器

1. 本科生论文写作痛点与工具需求分析 写毕业论文是每个本科生都要经历的"成人礼",但现实中90%的学生都会遇到相似的困境:开题没方向、文献找不到、格式总出错、查重过不了。去年指导学弟学妹时,我发现他们平均要花200小时在论文格…

作者头像 李华
网站建设 2026/9/12 11:28:20

AIGC检测与降AI率工具全面测评与实战指南

1. 项目概述:为什么我们需要关注AIGC检测与降AI率? 在内容创作领域,AIGC(AI生成内容)的普及率正以惊人速度增长。根据最新行业调研,超过78%的图文创作者每周至少使用一次AI辅助工具,而学术领域A…

作者头像 李华
网站建设 2026/9/12 11:26:56

Qiskit与Cirq量子编程框架核心语法对比与应用指南

1. 量子编程语言概述量子计算正在从实验室走向实际应用,而量子编程语言作为连接人类思维与量子硬件的桥梁,其重要性日益凸显。目前主流的量子编程框架中,IBM的Qiskit和Google的Cirq凭借其完整性和易用性脱颖而出。这两个框架都采用Python作为…

作者头像 李华