How to track Paddle revenue by traffic source
By Devendra Variya, co-founder of Virling. Published 2026-11-05.
To track Paddle revenue by traffic source, give each visitor an ID, pass it to Paddle as custom data when they check out, and join each transaction back to the visits that came before it. Paddle knows who paid and how much. It does not know which page or channel they came from.
Step 1: set a visitor ID
Your analytics script sets one first-party ID per visitor and remembers the first source: referrer, UTM tags or direct. Put the script on the page that opens checkout as well as on your marketing pages.
Step 2: send the ID to Paddle at checkout
Pick the option that matches how you sell:
- Paddle.js: pass the ID as
customDatawhen you open checkout - Transactions you create on your server: set
custom_dataon the transaction with the ID from the visitor's cookie
Now every transaction carries the visitor who made it. If your checkout code can run before the analytics script has loaded, wait for the script first, or the value will be empty.
Step 3: read transactions and join them to visits
Read completed transactions from Paddle with a read-only API key, then match each one's ID to that visitor's earlier visits. Credit one of them with a rule you keep fixed (see first touch or last touch).
Step 4: handle refunds and renewals
Two things change the numbers after the first sale. Refunds and chargebacks lower a transaction's revenue, so a channel that looks good on day one can shrink later. Subscription renewals carry no custom data of their own, so they should keep the channel of the first payment instead of landing in Direct.
Step 5: report revenue per channel
Group the joined transactions by channel and divide by visitors to get revenue per visitor. That is the table that tells you where to spend time.
What goes wrong
- Forgetting step 2: transactions arrive with no visitor and fall into Direct
- Reading the ID before the script has loaded, so checkout opens with an empty value
- Using a different name for the ID in checkout than the one your analytics expects, so nothing matches
- Counting only the first sale and ignoring refunds, which overstates a channel
Doing it with Virling
Virling reads Paddle Billing through a read-only key with the transaction.read and adjustment.read permissions, plus subscription.read for retention. It imports the last 90 days on the first run, then new transactions every minute, and it does the join for you. It reads the ID from virling_vid in the transaction's custom data. The snippet is in the docs, and the setup is on the Paddle integration page.
Frequently asked questions
Can Paddle show which traffic source a sale came from?
Not on its own. Paddle records the transaction, not the visit. You need to pass a visitor ID into checkout as custom data and join it to your analytics.
Where do I put the visitor ID in Paddle?
In custom data. With Paddle.js, pass customData when you open checkout. For transactions you create on your server, set custom_data on the transaction.
Which channel do Paddle renewals get?
Renewals carry no custom data of their own, so they keep the channel of the subscription's first payment.
Does this work in the Paddle sandbox?
Yes. Virling accepts sandbox keys, which start with pdl_sdbx_, so you can test the join before going live.
Start a 14-day free trial at app.virling.com.