@dub/analytics) detects the dub_id query parameter and stores it as a first-party cookie. This cookie is what allows Dub to attribute conversion events back to the original link click.1npm install @dub/analytics
<Analytics /> component to your root layout:12345678910import { Analytics as DubAnalytics } from "@dub/analytics/react"; export default function RootLayout({ children }) { return ( <html lang="en"> <body>{children}</body> <DubAnalytics apiHost="https://dub.strinkl.com/api" /> </html> ); }
1234<script src="https://www.dubcdn.com/analytics/script.js" defer ></script>
| Prop | Type | Default | Description |
apiHost | string | https://api.dub.co | Base URL for the Dub API. Use your self-hosted instance if applicable. |
attributionModel | "first-click" | "last-click" | "last-click" | Which touchpoint gets credit for the conversion. |
publishableKey | string | — | Required for client-side conversion tracking. |
cookieOptions.expiresInDays | number | 90 | Attribution window in days. |
cookieOptions.domain | string | — | Set for cross-subdomain tracking (e.g. .example.com). |
domainsConfig.refer | string | — | Custom domain for client-side click tracking. |
domainsConfig.outbound | string | string[] | — | Domains for cross-domain tracking. |
_dubAnalytics — you should see the analytics object?dub_id=test to your URL and check that the dub_id cookie is set/track/click requests1234await dub.links.create({ url: "https://yoursite.com", trackConversion: true, });
example.com — tracks traffic only from example.com*.example.com — tracks traffic from all subdomains, but not the apex domainlocalhost for local development. Remove it before going live.1234<DubAnalytics publishableKey="dub_pk_xxxxxxxx" apiHost="https://dub.strinkl.com/api" />
123456789101112131415161718192021import { useAnalytics } from "@dub/analytics/react"; import { useEffect } from "react"; export function ThankYouPage() { const { trackLead } = useAnalytics(); useEffect(() => { const params = new URLSearchParams(window.location.search); const email = params.get("email"); if (email) { trackLead({ eventName: "Sign Up", customerExternalId: email, customerEmail: email, }); } }, [trackLead]); return <div>Thank you for signing up!</div>; }
1234567891011121314151617import { useAnalytics } from "@dub/analytics/react"; export function SignUpForm() { const { trackLead } = useAnalytics(); const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); trackLead({ eventName: "Sign Up", customerExternalId: email, customerName: name, customerEmail: email, }); }; return <form onSubmit={handleSubmit}>...</form>; }
1234567891011import { Dub } from "dub"; const dub = new Dub({ token: process.env.DUB_API_KEY }); await dub.track.lead({ clickId: cookies.get("dub_id"), eventName: "Sign Up", customerExternalId: user.id, customerEmail: user.email, customerName: user.name, });
| Property | Required | Description |
clickId | Yes | The dub_id value from the cookie. Pass empty string for deferred tracking. |
eventName | Yes | Name of the event (e.g. "Sign Up"). |
customerExternalId | Yes | Unique customer ID in your system. Used for deduplication and future attribution. |
customerName | No | Customer name. Random name generated if omitted. |
customerEmail | No | Customer email. |
customerAvatar | No | Avatar URL. |
metadata | No | Additional data (max 10,000 characters). |
12345const session = await stripe.checkout.sessions.create({ metadata: { dubCustomerId: user.id, }, });
1234567891011import { Dub } from "dub"; const dub = new Dub({ token: process.env.DUB_API_KEY }); await dub.track.sale({ customerExternalId: user.id, amount: 5900, // in cents ($59.00) paymentProcessor: "stripe", invoiceId: "in_123", eventName: "Subscription creation", });
| Property | Required | Description |
customerExternalId | Yes | Customer ID matching the lead event. |
amount | Yes | Sale amount in cents. |
paymentProcessor | No | e.g. "stripe", "shopify", "custom". |
eventName | No | Defaults to "Purchase". |
invoiceId | No | Used as idempotency key. |
currency | No | Defaults to "usd". |
metadata | No | Additional sale data. |
?via= parameter)123<DubAnalytics domainsConfig={{ refer: "go.yourcompany.link" }} />
https://yoursite.com?via=abc123, the script automatically tracks a click event.trackClick())123456789101112import { useAnalytics } from "@dub/analytics/react"; function ReferralPage() { const { trackClick } = useAnalytics(); useEffect(() => { const key = window.location.pathname.split("/").pop(); if (key) { trackClick({ domain: "go.yourcompany.link", key }); } }, [trackClick]); }
dub_partner_data cookie:1234567891011121314import { useAnalytics } from "@dub/analytics/react"; function DiscountBanner() { const { partner, discount } = useAnalytics(); if (!partner || !discount) return null; return ( <div> <img src={partner.image} alt={partner.name} /> <p>{partner.name} referred you — {discount.amount}{discount.type === "percentage" ? "%" : "$"} off</p> </div> ); }
app.example.com but you need the cookie on example.com:1<DubAnalytics cookieOptions={{ domain: ".example.com" }} />
example.sh) links to your app (example.com):123<DubAnalytics domainsConfig={{ outbound: ["example.com", "example.sh"] }} />
dub_id to outbound links between these domains.12345678await dub.track.sale({ clickId: cookies.get("dub_id"), customerExternalId: order.email, customerName: order.name, customerEmail: order.email, amount: 4900, invoiceId: order.id, });