> ## Documentation Index
> Fetch the complete documentation index at: https://speakeasy-20cf8bdf.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Clerk

> Learn how to track lead conversion events with Clerk and Dub

When it comes to conversion tracking, a `lead` event happens when a user performs an action that indicates interest in your product or service. This could be anything from:

* Signing up for an account
* Adding a product to cart
* Joining a mailing list

<Frame>
  <img className="rounded-lg border border-gray-100" src="https://assets.dub.co/help/conversion-lead-event.png" alt="A diagram showing how lead events are tracked in the conversion funnel" />
</Frame>

In this guide, we will be focusing on tracking new user sign-ups for a SaaS application that uses Clerk for user authentication.

## Prerequisites

Before you get started, make sure you follow the [Dub Conversions quickstart guide](/conversions/quickstart) to get Dub Conversions set up for your links:

1. [Enable conversion tracking for your links](/conversions/quickstart#step-1-enable-conversion-tracking-for-your-links)
2. [Install the @dub/analytics client-side SDK](/sdks/client-side/introduction)
3. [Install the Dub server-side SDK](/conversions/quickstart#step-3-install-the-dub-server-side-sdk)

## 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:

<iframe width="100%" height="469px" className="rounded-xl" src="https://www.loom.com/embed/7338589f0c0c4ee1b71c9f2aa28aac87?sid=04c67f3b-1bec-468a-b0c7-5b24d24cd96e" title="Loom video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen />

Here's a quick summary of the steps:

<Steps>
  <Step title="Add environment variables">
    Add the following environment variables to your app:

    ```bash theme={null}
    # 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_key
    ```
  </Step>

  <Step title="Add a custom claim to your Clerk session token">
    Add the following JSON as a [custom claim](https://clerk.com/docs/references/nextjs/add-onboarding-flow#add-custom-claims-to-your-session-token) to your Clerk session token:

    ```json Clerk Session Token theme={null}
    {
      "metadata": "{{user.public_metadata}}"
    }
    ```
  </Step>

  <Step title="Extend the `@dub/analytics` package with Clerk's `useUser` hook">
    Extend the [`@dub/analytics` package](/sdks/client-side/introduction) to include a `trackLead` server action.

    ```tsx components/dub-analytics.tsx theme={null}
    "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:

    ```tsx app/layout.tsx theme={null}
    import { DubAnalytics } from "@/components/dub-analytics";

    export default function RootLayout({ children }: { children: React.ReactNode }) {
      return (
        <html>
          <body>
            <DubAnalytics />
            {children}
          </body>
        </html>
      );
    }
    ```
  </Step>

  <Step title="Implement the `trackLead` server action">
    On the server side, implement the `trackLead` server action. Alternatively, you can also create an API route instead:

    <CodeGroup>
      ```tsx /actions/track-lead.ts theme={null}
      // 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",
              externalId: 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 };
        }
      }
      ```

      ```tsx /api/track-lead/route.ts theme={null}
      // This is an API route
      import { NextRequest, NextResponse } from "next/server";

      export async function POST(req: NextRequest) {
        // read dub_id from the request cookies
        const dubId = req.cookies.get("dub_id")?.value;
        if (dubId) {
          // Send lead event to Dub
          await dub.track.lead({
            clickId: dubId,
            eventName: "Sign Up",
            externalId: id,
            customerName: name,
            customerEmail: email,
            customerAvatar: avatar,
          });
        }

        const clerk = await clerkClient();
        await clerk.users.updateUser(id, {
          publicMetadata: {
            dubClickId: dubId || "n/a",
          },
        });
        const res = NextResponse.json({ ok: true });
        // Delete the dub_id cookie
        res.cookies.set("dub_id", "", {
          expires: new Date(0),
        });
        return res;
      }
      ```
    </CodeGroup>
  </Step>
</Steps>

Here's the full list of attributes you can pass when sending a lead event:

| Property         | Required | Description                                                                                                              |
| :--------------- | :------- | :----------------------------------------------------------------------------------------------------------------------- |
| `clickId`        | **Yes**  | The unique `dub_id` parameter that the lead conversion event is attributed to.                                           |
| `eventName`      | **Yes**  | The name of the event. Example: "Sign up".                                                                               |
| `externalId`     | **Yes**  | The unique ID of the customer in your system. Will be used to identify and attribute all future events to this customer. |
| `customerEmail`  | No       | The email address of the customer. If not passed, a random email address will be generated.                              |
| `customerName`   | No       | The name of the customer. If not passed, a random name will be generated (e.g. "Big Red Caribou").                       |
| `customerAvatar` | No       | The avatar URL of the customer. If not passed, a random avatar URL will be generated.                                    |

## Example App

To learn more about how to track leads with Clerk, check out the following example app:

<Card title="Dub + Clerk Example App" icon="github" href="https://github.com/dubinc/examples/tree/main/conversions/clerk">
  See how to track new user sign-ups with Clerk and the Dub SDK.
</Card>

## View your conversions

Once you've enabled conversion tracking for your links, all your tracked conversions will show up on your [Analytics dashboard](https://app.dub.co/analytics). We provide 3 different views to help you understand your conversions:

* **Time-series**: A [time-series view](https://dub.co/help/article/dub-analytics#1-time-series-analytics-chart) of the number clicks, leads and sales.

<Frame>
  <img src="https://mintcdn.com/speakeasy-20cf8bdf/-Y0j4C06SQOILvRL/images/conversions/timeseries-chart.png?fit=max&auto=format&n=-Y0j4C06SQOILvRL&q=85&s=7d752129ab0f59fb7ac44b5c83d608c9" alt="Time-series line chart" width="1600" height="900" data-path="images/conversions/timeseries-chart.png" />
</Frame>

* **Funnel chart**: A funnel chart view visualizing the conversion & dropoff rates across the different steps in the conversion funnel (clicks → leads → sales).

<Frame>
  <img src="https://mintcdn.com/speakeasy-20cf8bdf/-Y0j4C06SQOILvRL/images/conversions/funnel-chart.png?fit=max&auto=format&n=-Y0j4C06SQOILvRL&q=85&s=bd252526bae397088168478a8097c10d" alt="Funnel chart view showing the conversion & dropoff rates from clicks → leads → sales" width="1600" height="900" data-path="images/conversions/funnel-chart.png" />
</Frame>

* **Real-time events stream**: A [real-time events stream](https://dub.co/help/article/real-time-events-stream) of every single conversion event that occurs across all your links in your workspace.

<Frame>
  <img src="https://mintcdn.com/speakeasy-20cf8bdf/-Y0j4C06SQOILvRL/images/conversions/events-table.png?fit=max&auto=format&n=-Y0j4C06SQOILvRL&q=85&s=256bd06254e543c40f1ae268424e17e1" alt="The Events Stream dashboard on Dub" width="1600" height="900" data-path="images/conversions/events-table.png" />
</Frame>
