// snippet import removed // snippet import removed // snippet import removed // snippet import removed
In this guide, we will be focusing on tracking new user sign-ups for a SaaS application that uses Clerk for user authentication.
Configure Clerk
Next, configure Clerk to track lead conversion events when a new user signs up. Here’s a quick video showing how to do this:
Here’s a quick summary of the steps:
Add environment variables
Add the following environment variables to your app:
# get it here: https://dashboard.clerk.com/apps/new
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=your_publishable_key
CLERK_SECRET_KEY=your_secret_key
# get it here: https://d.to/tokens
DUB_API_KEY=your_api_keyAdd a custom claim to your Clerk session token
Add the following JSON as a custom claim to your Clerk session token:
{
"metadata": "{{user.public_metadata}}"
}Extend the `@dub/analytics` package with Clerk's `useUser` hook
Extend the @dub/analytics package to include a trackLead server action.
"use client";
import { trackLead } from "@/actions/track-lead";
import { useUser } from "@clerk/nextjs";
import { Analytics, AnalyticsProps } from "@dub/analytics/react";
import { useEffect } from "react";
export function DubAnalytics(props: AnalyticsProps) {
const { user } = useUser();
useEffect(() => {
if (!user || user.publicMetadata.dubClickId) return;
// if the user is loaded but hasn't been persisted to Dub yet, track the lead event
trackLead({
id: user.id,
name: user.fullName!,
email: user.primaryEmailAddress?.emailAddress,
avatar: user.imageUrl,
}).then(async (res) => {
if (res.ok) await user.reload();
else console.error(res.error);
});
// you can also use an API route instead of a server action
/*
fetch("/api/track-lead", {
method: "POST",
body: JSON.stringify({
id: user.id,
name: user.fullName,
email: user.primaryEmailAddress?.emailAddress,
avatar: user.imageUrl,
}),
}).then(res => {
if (res.ok) await user.reload();
else console.error(res.statusText);
});
*/
}, [user]);
return <Analytics {...props} />;
}Then, add the DubAnalytics component to your app’s root layout component:
import { DubAnalytics } from "@/components/dub-analytics";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html>
<body>
<DubAnalytics />
{children}
</body>
</html>
);
}Implement the `trackLead` server action
On the server side, implement the trackLead server action. Alternatively, you can also create an API route instead:
// This is a server action
"use server";
import { dub } from "@/lib/dub";
import { clerkClient } from "@clerk/nextjs/server";
import { cookies } from "next/headers";
export async function trackLead({
id,
name,
email,
avatar,
}: {
id: string;
name?: string | null;
email?: string | null;
avatar?: string | null;
}) {
try {
const cookieStore = await cookies();
const dubId = cookieStore.get("dub_id")?.value;
if (dubId) {
// Send lead event to Dub
await dub.track.lead({
clickId: dubId,
eventName: "Sign Up",
customerExternalId: id,
customerName: name,
customerEmail: email,
customerAvatar: avatar,
});
// Delete the dub_id cookie
cookieStore.set("dub_id", "", {
expires: new Date(0),
});
}
const clerk = await clerkClient();
await clerk.users.updateUser(id, {
publicMetadata: {
dubClickId: dubId || "n/a",
},
});
return { ok: true };
} catch (error) {
console.error("Error in trackLead:", error);
return { ok: false, error: (error as Error).message };
}
}Example App
To learn more about how to track leads with Clerk, check out the following example app:
Dub + Clerk Example App
See how to track new user sign-ups with Clerk and the Dub SDK.