> ## Documentation Index
> Fetch the complete documentation index at: https://dub-client-tracking-lead-sale.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Client-side tracking

> Learn how to track sales conversion events with Dub on the client-side

When it comes to [conversion tracking](/conversions/quickstart), a `sale` event happens when a user purchases your product or service. Examples include:

* Subscribing to a paid plan
* Usage expansion (upgrading from one plan to another)

## 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%3A-enable-conversion-tracking-for-your-links)

## Quickstart

<Steps>
  <Step title="Generate your publishable key">
    Before you can track conversions on the client-side, you need to generate a publishable key from your Dub workspace.

    To do that, navigate to your [workspace's Analytics settings page](https://app.dub.co/settings/analytics) and generate a new publishable key under the **Publishable Key** section.

    <Frame>
      <img src="https://mintcdn.com/dub-client-tracking-lead-sale/Fo3EyiwSOIeMUHrn/images/conversions/publishable-key.png?fit=max&auto=format&n=Fo3EyiwSOIeMUHrn&q=85&s=6a57838d13e6c8b902eb11bb20654e65" alt="Enabling conversion tracking for a workspace" width="3292" height="1520" data-path="images/conversions/publishable-key.png" />
    </Frame>
  </Step>

  <Step title="Allowlist your site's domain">
    Then, you'll need to allowlist your site's domain to allow the client-side conversion events to be ingested by Dub.

    To do that, navigate to your [workspace's Analytics settings page](https://app.dub.co/settings/analytics) and add your site's domain to the **Allowed Hostnames** list.

    This provides an additional layer of security by ensuring only authorized domains can track conversions using your publishable key.

    <Frame>
      <img src="https://mintcdn.com/dub-client-tracking-lead-sale/Fo3EyiwSOIeMUHrn/images/conversions/allowed-hostnames.png?fit=max&auto=format&n=Fo3EyiwSOIeMUHrn&q=85&s=dc5d87994706d2cb7d581cc0d5aa9505" alt="Enabling conversion tracking for a workspace" width="3308" height="1522" data-path="images/conversions/allowed-hostnames.png" />
    </Frame>

    You can group your hostnames when adding them to the allow list:

    * `example.com`: Tracks traffic **only** from `example.com`.
    * `*.example.com`: Tracks traffic from **all subdomains** of `example.com`, but **not** from `example.com` itself.

    <Tip>
      When testing things out locally, you can add `localhost` to the **Allowed
      Hostnames** list temporarily. This will allow local events to be ingested by
      Dub. Don't forget to remove it once you're ready to go live!
    </Tip>
  </Step>

  <Step title="Install @dub/analytics package">
    Next, install the Dub analytics script in your application.

    You can install the `@dub/analytics` script in several different ways:

    <CardGroup>
      <Card title="React" icon="react" href="/sdks/client-side/installation-guides/react">
        Add Dub Analytics to your React app
      </Card>

      <Card title="Manual installation" icon="browser" href="/sdks/client-side/installation-guides/manual">
        Add Dub Analytics to your website
      </Card>

      <Card title="Google Tag Manager" icon="google" href="/sdks/client-side/installation-guides/google-tag-manager">
        Add Dub Analytics via GTM
      </Card>

      <Card
        title="Framer"
        icon={
  <svg
    width="74"
    height="111"
    viewBox="0 0 74 111"
    fill="none"
    xmlns="http://www.w3.org/2000/svg"
    className="w-7 h-7"
  >
    <path d="M0 0H73.8374V36.9892H36.9187L0 0Z" fill="#eb5611" />
    <path d="M0 36.989H36.9187L73.8374 73.9796H0V36.989Z" fill="#eb5611" />
    <path d="M0 73.9797H36.9187V110.97L0 73.9797Z" fill="#eb5611" />
  </svg>
}
        href="/sdks/client-side/installation-guides/framer"
      >
        Add Dub Analytics to your Framer site
      </Card>

      <Card title="Shopify" icon="shopify" href="/sdks/client-side/installation-guides/shopify">
        Add Dub Analytics to your Shopify store
      </Card>

      <Card title="WordPress" icon="wordpress" href="/sdks/client-side/installation-guides/wordpress">
        Add Dub Analytics to your WP site
      </Card>

      <Card title="Webflow" icon="webflow" href="/sdks/client-side/installation-guides/webflow">
        Add Dub Analytics to your Webflow site
      </Card>
    </CardGroup>

    You must configure the **publishable key** you generated in step 1 when installing the analytics script. Without this key, client-side conversion tracking will not work.

    <CodeGroup>
      ```typescript React
      import { Analytics as DubAnalytics } from '@dub/analytics/react';

      export default function RootLayout({
        children,
      }) {
        return (
          <html lang="en">
            <body className={inter.className}>{children}</body>
            <DubAnalytics
              ...
              publishableKey="dub_pk_xxxxxxxx" // Replace with your publishable key
            />
          </html>
        );
      }
      ```

      ```html Other
      <script>
        !(function (c, n) { 
          c[n] = c[n] || function () { (c[n].q = c[n].q || []).push(arguments); }; 
          ["trackClick","trackLead","trackSale"].forEach(t => c[n][t] = (...a) => c[n](t, ...a)); 
          var s=document.createElement("script"); s.defer=1; s.src="https://dubcdn.com/analytics/script.conversion-tracking.js"; 
          s.setAttribute("data-publishable-key","dub_pk_xxxxxxxx"); // Replace with your publishable key
          document.head.appendChild(s); 
        })(window, "dubAnalytics");
      </script>
      ```
    </CodeGroup>
  </Step>
</Steps>

## Client-side sale tracking

Once the analytics script is installed, you can start tracking sale events in your application on the client-side.

<CodeGroup>
  ```typescript React
  import { useAnalytics } from "@dub/analytics/react";
  import { useState } from "react";

  export function CheckoutForm() {
    const { trackSale } = useAnalytics();
    // …
  }
    const handleSubmit = (e: React.FormEvent) => {
      e.preventDefault();

      // Track the sale event
      trackSale({
        eventName: "Purchase",
        customerExternalId: "cus_RBfbD57H",
        amount: 5000, // $50.00
        invoiceId: "in_1MtHbELkdIwH",
      });
    };

    return (
      <form onSubmit={handleSubmit}>
        ...
      </form>
    );
  }
  ```

  ```html Other
  <!DOCTYPE html>
  <html lang="en">
    <head>
      <meta charset="UTF-8" />
      <meta name="viewport" content="width=device-width, initial-scale=1.0" />
      <title>Checkout</title>
    </head>
    <body>
      <form id="checkoutForm">
        ...
        <button type="submit">Checkout</button>
      </form>

      <script>
        document.getElementById("checkoutForm").addEventListener("submit", function (e) {
          e.preventDefault();

          // Track the sale event
          dubAnalytics.trackSale({
            eventName: "Purchase",
            customerExternalId: "cus_RBfbD57H",
            amount: 5000, // $50.00
            invoiceId: "in_1MtHbELkdIwH",
          });
        });
      </script>
    </body>
  </html>
  ```
</CodeGroup>

Here are the properties you can include when sending a sale event:

| Property             | Required | Description                                                                                                                                            |
| :------------------- | :------- | :----------------------------------------------------------------------------------------------------------------------------------------------------- |
| `customerExternalId` | **Yes**  | The unique ID of the customer in your system. Will be used to identify and attribute all future events to this customer.                               |
| `amount`             | **Yes**  | The amount of the sale in cents.                                                                                                                       |
| `paymentProcessor`   | No       | The payment processor that processed the sale (e.g. [Stripe](/conversions/sales/stripe), [Shopify](/conversions/sales/shopify)). Defaults to "custom". |
| `eventName`          | No       | The name of the event. Defaults to "Purchase".                                                                                                         |
| `invoiceId`          | No       | The invoice ID of the sale. Can be used as a idempotency key – only one sale event can be recorded for a given invoice ID.                             |
| `currency`           | No       | The currency of the sale. Defaults to "usd".                                                                                                           |
| `metadata`           | No       | An object containing additional information about the sale.                                                                                            |

**When to track sale**

Track sale events only after a user successfully completes a purchase or payment-related action, such as:

* Completing a checkout or order
* Subscription payment
* Invoice payment
* Any paid trial or demo conversion

Ensure the event is triggered **only after the backend confirms the payment was successful**. This guarantees accurate sale data and prevents false or incomplete entries.

<Warning>
  Client-side conversion tracking comes with some limitations: - **Ad
  blockers**: Users with ad blockers may prevent tracking scripts from loading -
  **JavaScript disabled**: Events won't be tracked if users have JavaScript
  disabled - **Network issues**: Failed network requests won't retry
  automatically - **Privacy concerns**: Some users may block client-side
  tracking for privacy reasons For more accurate conversion tracking, consider
  using [server-side conversion tracking](/api-reference/endpoint/track-sale).
</Warning>

## View conversion results

And that's it – you're all set! You can now sit back, relax, and watch your conversion revenue grow. We provide 3 different views to help you understand your conversions:

* **Time-series**: A [time-series view](https://app.dub.co/dub/analytics?view=timeseries) of the number clicks, leads and sales.

<Frame>
  <img src="https://mintcdn.com/dub-client-tracking-lead-sale/Fo3EyiwSOIeMUHrn/images/conversions/timeseries-chart.png?fit=max&auto=format&n=Fo3EyiwSOIeMUHrn&q=85&s=71d3c78498e8befddb5d2fda748d7d54" alt="Time-series line chart" width="2400" height="1260" data-path="images/conversions/timeseries-chart.png" />
</Frame>

* **Funnel chart**: A [funnel chart view](http://app.dub.co/analytics?view=funnel) visualizing the conversion & dropoff rates across the different steps in the conversion funnel (clicks → leads → sales).

<Frame>
  <img src="https://mintcdn.com/dub-client-tracking-lead-sale/Fo3EyiwSOIeMUHrn/images/conversions/funnel-chart.png?fit=max&auto=format&n=Fo3EyiwSOIeMUHrn&q=85&s=1a70ca66d94eee8d705323f7fd33944e" alt="Funnel chart view showing the conversion & dropoff rates from clicks → leads → sales" width="2400" height="1260" data-path="images/conversions/funnel-chart.png" />
</Frame>

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

<Frame>
  <img src="https://mintcdn.com/dub-client-tracking-lead-sale/Fo3EyiwSOIeMUHrn/images/conversions/events-table.png?fit=max&auto=format&n=Fo3EyiwSOIeMUHrn&q=85&s=70741a124cdbaa226d35cec457e65f54" alt="The Events Stream dashboard on Dub" width="2400" height="1260" data-path="images/conversions/events-table.png" />
</Frame>
