Integrations

Dodo Payments integration

Connect your Dodo Payments account to attribute purchases, renewals, and refunds to visitor sessions. See which pages, referrers, UTM campaigns, and devices are driving your sales.

Persist mode is required for revenue attribution. It's the only way to associate a payment with a visitor, however this requires explicit consent for EU users. Learn more.

How to connect Dodo Payments

Here's an exact step-by-step tutorial on how to integrate Dodo Payments.

  1. Head to your Dodo dashboard
  2. Create a new API key
  3. Copy the generated API key
  4. Head to your project's Settings
  5. Navigate to Integrations
  6. Hit the connect button for Dodo Payments
  7. Paste it in your API key
  8. Hit "Connect"

We'll then automatically create a webhook endpoint for your Dodo account and Visitors will begin receiving payment.succeeded and refund.succeeded events.

Enable persist mode

Without this we can't attribute transactions to real visitors. This will enable cookie-based tracking allowing you to read the visitor cookie.

Replace YOUR_TOKEN with your project token.
index.html
<script
  src="https://cdn.visitors.now/v.js"
  data-token="YOUR_TOKEN"
  data-persist>
</script>

How attribution works

When a Dodo event comes in we resolve the visitor through a fallback chain:

  1. Payment or refund metadata.visitor
  2. Any previous attribution
  3. Email matching

For subscriptions, we classify the first successful charge as new and subsequent successful charges as renewal.

For refunds, we track them as negative revenue.

Dodo checkout integration

When creating a Dodo Checkout session on your server, read the visitor cookie from the incoming request and pass it as metadata to your Dodo checkout.

app/api/checkout/route.ts
import DodoPayments from "dodopayments";
import { cookies } from "next/headers";

const dodo = new DodoPayments({
bearerToken: process.env.DODO_PAYMENTS_API_KEY!,
environment: "live_mode",
});

export async function POST() {
const visitor = (await cookies()).get("visitor")?.value;

  const session = await dodo.checkoutSessions.create({
    product_cart: [{ product_id: "prod_xxx", quantity: 1 }],
    customer: { email: "jane@example.com", name: "Jane" },
    return_url: "https://example.com/success",
    metadata: { visitor },
  });

  return Response.json({ url: session.checkout_url });

}

Email fallback with identify

If you can't pass the visitor cookie in every checkout (e.g. the purchase happens on a different domain), Visitors can still attribute revenue by matching the Dodo customer email to an identified visitor.

Call visitors.identify() with the user's email when they sign in:

visitors.identify({
  id: "user_123",
  name: "Jane Smith",
  email: "jane@example.com",
  // ...
})

When a Dodo event comes in without visitor metadata, Visitors will look up the customer email and match it to the identified profile. This is less reliable than passing metadata directly, but acts as a useful fallback.

Learn more about identifying users.

Troubleshooting

If revenue is showing up but it's not being attributed, ensure that:

  1. You are in persist mode.
  2. You are reading the visitor cookie set by persist mode correctly.
  3. You are passing it in metadata when creating the checkout session.

If you are doing all that and it's still not attributing correctly, contact our support team and we'll help you to diagnose the root cause.