Skip to content
SourceLoop
Payment tracking

How to track lead source in Dodo Payments

Tie every Dodo Payments transaction and recurring billing event back to the marketing channel that drove it. Global revenue attribution for SaaS and digital products.

On this page
  1. Why this matters
  2. What SourceLoop captures from Dodo Payments
  3. Before you start
  4. Step 1: Install the SourceLoop tracking script
  5. Step 2: Add a webhook in your Dodo Dashboard
  6. Step 3: Paste the signing secret back into SourceLoop
  7. Step 4: Wire attribution into your checkout
  8. (1) Payments API
  9. (2) Subscriptions API
  10. Step 5: Run a test payment to verify
  11. Where to see Dodo revenue in SourceLoop
  12. Contacts Hub: revenue per contact
  13. Attribution dashboard: revenue by channel

Dodo Payments is the merchant-of-record payments platform built for global SaaS and digital products, especially strong for sellers based outside the US who want a checkout that handles cross-border compliance and tax. The reporting gap, like every payments tool, is which marketing channel earned each customer.

SourceLoop fills that in. Every payment, every recurring renewal, every refund mapped back to the visitor’s original session, so Dodo’s transaction list finally has a “by source” view, not just “by amount” or “by date”.

Five steps, around ten minutes. Works on every Dodo Payments account.

Why this matters

Dodo handles both one-shot payments and recurring subscriptions. For one-shot purchases (an ebook, a course, a yearly license), first-touch revenue attribution is the whole story. For subscriptions, it’s the start of the story:

  • A founder discovers your tool via a YouTube video in May
  • They buy the $39/mo Starter plan
  • They upgrade to Pro ($129/mo) in August when their team scales
  • They keep renewing for the next 18 months

Without revenue tracking, YouTube gets credit for one “payment succeeded” event and never sees the $2,400+ in lifetime revenue. With Dodo wired into SourceLoop, every renewal, every plan change, every refund hangs off the same lead, and channel-level reporting reflects real MRR, not just first-payment counts.

What SourceLoop captures from Dodo Payments

Each Dodo customer arrives in SourceLoop tagged with:

  • Acquisition channel of the visitor at signup (paid, organic, social, referral, direct)
  • UTM parameters from the landing URL of the converting session
  • Pages browsed before checkout was opened
  • Time on site and return-visit count ahead of the purchase
  • Email + name from Dodo’s customer record
  • First-touch landing page plus the original referrer
  • Source of the converting session (often distinct from first-touch)
  • Full revenue history, payment succeeded (initial + renewals via subscription.renewed), subscription active (trial converted), plan changed, on hold, canceled, expired, failed, refunds
  • Device, country, browser

Before you start

You’ll need:

  • A SourceLoop workspace (free trial)
  • Edit access to the site that hosts your Dodo Payments checkout trigger or backend API
  • A Dodo Payments account with at least one product live
  • Developer access to your Dodo Dashboard, you’ll need it to add a webhook

Step 1: Install the SourceLoop tracking script

Sign in to SourceLoop, open Setup -> Tracking code in the sidebar, and copy the snippet.

SourceLoop Setup page with the tracking code snippet ready to copy

Paste it into the <head> of every page on your site, especially the pages that lead into a Dodo checkout. From this point on, every visitor session, UTM, and journey is being recorded. The next steps connect that data to the payments Dodo will start sending.

Step 2: Add a webhook in your Dodo Dashboard

Dodo sends payment and subscription events as webhooks. SourceLoop gives you a dedicated URL, you paste it into Dodo, and Dodo starts delivering events.

  1. In SourceLoop, open Setup -> Payment in the sidebar.
SourceLoop Setup Payment page showing the supported payment provider cards
  1. Click the Dodo Payments card. A drawer opens on the right with two tabs: Connect webhook and Wire attribution. Stay on the first tab and copy the webhook URL SourceLoop shows you.
SourceLoop payment provider drawer with the webhook URL and signing secret fields
  1. Open the Dodo Dashboard, navigate to Developer -> Webhooks, and click Add endpoint.
  2. Paste SourceLoop’s URL into the endpoint URL field.
  3. Under Events, enable the subscription, payment, and refund events. The recommended set: payment.succeeded, refund.succeeded, subscription.active, subscription.renewed, subscription.plan_changed, subscription.on_hold, subscription.cancelled, subscription.expired, subscription.failed.
  4. Save the endpoint. Dodo generates a signing secret, copy it.

Step 3: Paste the signing secret back into SourceLoop

Dodo signs every webhook with the secret it generated for the endpoint.

  1. Copy the signing secret from the endpoint detail page in Dodo.
  2. Back in the same SourceLoop drawer, paste it into the Signing secret field and click Save.

SourceLoop’s connection status flips from pending to active the first time Dodo delivers a verified event through.

Step 4: Wire attribution into your checkout

The webhook tells SourceLoop a payment happened. The attribution wiring tells SourceLoop which visitor session that payment belongs to. Without it, events still flow in, but stitching falls back to matching by customer email, lower fidelity, especially when a visitor pays without signing up first.

Once the tracker is installed, it exposes a small helper on every page that returns the two stitching identifiers for the current visitor:

window.sourceloop.checkoutMetadata()
// returns { sourceloop_anonymous_id: '...', sourceloop_id: '...' }

Pass that object through to Dodo using the API that matches your billing model. Use this guide to pick:

  • (1) Payments API — Use this for one-time purchases. Single-shot sales, lifetime deals, course purchases, license unlocks, anything where the customer pays once.
  • (2) Subscriptions API — Use this for recurring billing. Monthly or annual SaaS plans, memberships, subscription-based access. Metadata persists on the subscription object so every renewal event stays stitched to the original lead.

Wire each one you use, both share the same metadata field name.

(1) Payments API

Create the payment server-side with metadata. Dodo attaches it to the payment object and propagates it onto refund events.

Server (Node.js):

const payment = await fetch('https://api.dodopayments.com/payments', {
  method: 'POST',
  headers: {
    Authorization:  'Bearer ' + process.env.DODO_API_KEY,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    product_cart: [{ product_id: 'prod_xxx', quantity: 1 }],
    customer:     { email: userEmail, name: userName },
    payment_link: true,
    metadata:     meta,
  }),
}).then(r => r.json());

return { url: payment.payment_link };

(2) Subscriptions API

Same pattern, different endpoint. Metadata persists on the subscription object so every renewal event stays stitched.

Server (Node.js):

const sub = await fetch('https://api.dodopayments.com/subscriptions', {
  method: 'POST',
  headers: {
    Authorization:  'Bearer ' + process.env.DODO_API_KEY,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    product_id:   'prod_xxx',
    customer:     { email: userEmail, name: userName },
    payment_link: true,
    metadata:     meta,
  }),
}).then(r => r.json());

return { url: sub.payment_link };

Step 5: Run a test payment to verify

Open the page with your Dodo checkout in an incognito window, append ?utm_source=test&utm_medium=verify&utm_campaign=dodo-check to the URL, and complete a real transaction. Dodo test mode is the safest path if you’d rather not move real money, just toggle to test mode in the dashboard while testing.

Within seconds of Dodo confirming the payment, the customer should appear at the top of the Contacts Hub in SourceLoop with the test UTMs attached and a revenue event linked to the same contact.

Where to see Dodo revenue in SourceLoop

Contacts Hub: revenue per contact

Every Dodo customer becomes a contact row at app.sourceloop.ai/contacts with a revenue column showing what they’ve paid you to date. Click a contact to expand the full revenue ledger, initial payment, every renewal, every plan change, every refund, alongside the visitor’s pre-purchase journey.

Filter, sort, or segment the hub by revenue to surface your highest-value customers, or by source to see which channels are bringing in paying users vs. just sign-ups.

SourceLoop Contacts Hub showing a Dodo customer with the revenue column, full pre-purchase journey, and revenue history

Attribution dashboard: revenue by channel

app.sourceloop.ai/dashboards/traffic adds a revenue column alongside the breakdowns you already see: source, medium, campaign, landing page, content, term, device, country. So instead of “YouTube referral drove 400 sessions”, you see “YouTube referral drove 400 sessions and $5,100 in attributed Dodo revenue.”

Switch attribution models from the dropdown at the top to see how the numbers shift:

  • Last Non-Direct (the default, matches Google Analytics)
  • First Touch / First Non-Direct for top-of-funnel weighting
  • Last Touch for closing-channel weighting
  • Linear to split credit evenly across every touchpoint
  • Position-Based (U-Shaped) for 40% first / 40% last / 20% middle
  • Time Decay to weight recent touches higher (7-day half-life)

A YouTube video that introduces your product but doesn’t close the sale looks weak under Last Touch and dominant under First Touch. Picking the right model depends on whether you’re measuring discovery or conversion, the switcher lets you flip between them in one click.

SourceLoop attribution dashboard with Dodo revenue column grouped by source, medium, and campaign

Once Dodo revenue is flowing, push it back to Google Ads, Meta, and LinkedIn as offline conversions with revenue values so the bidding algorithms optimise toward real paying customers, not free signups or vanity clicks. Connect your Google Ads account covers the wiring.

Frequently asked questions

  1. Does this work with both the Dodo Payments API and the Subscriptions API?

    Yes. Both surfaces are covered, and they share the same webhook setup. Only the attribution wiring in step 4 differs, and the article walks through each.

  2. Are subscription renewals attributed back to the original source?

    Yes. Every `subscription.renewed` event gets stitched onto the same contact that started the subscription, so MRR and LTV stay tied to the channel that earned the original signup, not just the first payment.

  3. How do refunds and chargebacks show up?

    Refunds (`refund.succeeded`) and failed states (`subscription.failed`, `subscription.expired`) flow into SourceLoop and reduce the contact's attributed revenue. The attribution dashboard nets them against the original source.

  4. Dodo has a "Share link" button in the dashboard that produces a static payment link. Are clicks on those links attributed?

    Not directly. Static payment links don't carry per-visitor metadata, so SourceLoop falls back to email matching for those purchases. For accurate per-visitor stitching, create payments through the Dodo API and pass the metadata, the article shows how.

  5. I sell globally through Dodo. Do exchange rates and local currencies cause issues?

    No. Dodo reports gross transaction values in the original currency through the webhook, and SourceLoop captures the same amount. The attribution dashboard's revenue column shows your store's reporting currency.

  6. Will my Dodo webhooks to other tools (Slack, CRM, my own backend) still fire?

    Yes. SourceLoop subscribes as an additional endpoint. Every other destination you've configured continues to receive Dodo events independently.

Track every conversion to its true source

Capture and send full attribution data from every signup, lead, booking, and sale to your CRM and ad platforms, so you know exactly what's driving revenue.

Without SourceLoop

Untagged

Kayden Floyd

kayden@abc.com

  • SourceUnknown
  • MediumUnknown
  • CampaignUnknown
  • Landing pageUnknown
Journey
No touchpoints captured

With SourceLoop

Auto-tagged

Kayden Floyd

kayden@abc.com · Acme Co.

  • Channel Paid Social
  • CampaignFree_demo
  • Landing page/pricing
Journey
Synced to HubSpot Google Ads Meta