Paddle revenue attribution

Connect Paddle to your Clickport site with an API key and revenue shows up next to your traffic: a Revenue stat in the dashboard header, a revenue line on the main chart, and payments attributed back to the visit that made them. Setup is one paste in Clickport plus one line in your checkout call.

Cookie-free attribution, honestly scoped. Clickport joins each payment to the single session that opened checkout. There is no cross-session identity, so you get session attribution: the source, campaign, and channel of the visit that bought. What you don't get, by design, is customer lifetime tracking across weeks of return visits. No cookies means no persistent identity, and we don't fake one.

What you see in the dashboard

Once revenue events exist, a Revenue stat appears in the dashboard header, right next to Engagement (the labels compact to REV and ENG when both are showing). Click it to toggle a revenue line onto the main chart, bucketed exactly like the other metrics. The KPI row itself stays untouched: all standard KPIs keep their place.

REV€3,842ENG54%

Revenue lives in the header next to Engagement; the toggled pill draws the revenue line. The KPI row keeps its standard cells.

Real-life example. A SaaS selling a €49/year plan has 4,218 visitors in July and 102 purchases through Paddle: the header stat reads €3,842, net of two refunds. Click it and the green revenue line draws over the traffic chart, spiking on launch days.

Because every attributed payment carries its session's dimensions, revenue works with the rest of the dashboard:

  • Cross-filtering: filter to a source, campaign, country, or device and the Revenue stat re-computes for that slice.
  • Custom events: Purchases and Refunds appear as events in the Goals panel's custom events list, with revenue totals and averages.
  • Goals and funnels: add a custom-event goal on Purchase and funnels can end at the payment, with real amounts behind the conversion step.
  • Refunds and chargebacks net out: both land as negative revenue events attributed to the same session as the original purchase, so per-source revenue stays honest.
Which channel actually pays. The same SaaS announces the July launch on X and in its newsletter. X sends 1,450 visitors, the newsletter 380. Filter the Campaigns panel to each: the newsletter converted 21 purchases (€1,029), X converted 9 (€441). Four times fewer clicks, more than double the revenue. That is the comparison the Revenue stat exists for.

Add a goal on the Purchase event and it ranks alongside your existing goals, with revenue and average per conversion:

Goal
Visitors
CR
Revenue ↓
Avg
E
Purchase
102
2.4%
€3,842
€38
C
Opened checkout
487
11.5%
-
-
P
Viewed pricing
2,240
53.1%
-
-
F
Newsletter signup
760
18.0%
-
-
Purchase arrives from your Paddle account automatically. The funnel /pricing → Opened checkout → Purchase reads 2,240 → 487 → 102 with real money behind the last step.

A custom-event goal on Purchase, ranked with the rest of the Goals panel.

How to connect

Clickport asks for an API key you scope yourself, with read access only. Create a dedicated key for the connection instead of reusing one your backend already holds; it keeps the permissions minimal and lets you revoke it independently.

  1. In Paddle, open Developer tools → Authentication and click New API key.
  2. Grant it: Transactions — Read, Adjustments — Read. Optionally add Notifications — Write (see the sync modes section below). Everything else stays off.
  3. Copy the key (new keys start with pdl_live_apikey_; older keys have no prefix and work too).
  4. In Clickport, open Settings → Integrations → Revenue for your site, click Connect with API key on the Paddle card, and paste it.
Paddle
Learn more ↗
Connect Paddle with an API key to see revenue next to your traffic. Add one line to your checkout call and payments are attributed to the session that made them.
Connected
Real-time: Paddle notifies Clickport the moment a payment lands.
Disconnect Paddle

The Paddle card in Settings → Integrations → Revenue after connecting.

On connect, Clickport validates the key, imports the last 90 days of payments as a backfill, and starts syncing new ones. Revenue from the backfill appears within a few minutes.

Sync modes

  • Real-time (recommended): if the key includes Notifications — Write, Clickport creates a webhook destination on your Paddle account automatically. Payments appear in the dashboard the moment they land. Deliveries are signed and verified; the destination is removed again when you disconnect.
  • Periodic: without the notification scope, Clickport pulls new payments every 10 minutes. Same data, small delay.

How attribution works

Clickport's tracker knows its own session ID. Pass it into checkout as custom data and Paddle returns it with the completed transaction. Clickport joins it back to the session, and the payment inherits the visit's source, campaign, channel, country, and device.

If you open checkout with Paddle.js (overlay or inline), it's one added key:

Paddle.Checkout.open({
  items: [{ priceId: 'pri_...', quantity: 1 }],
  customData: { clickport_ref: window.clickport.checkoutRef() }
});

customData is a plain object, so clickport_ref merges alongside anything you already pass there. Clickport never touches your other keys. In a React or Vue app the call is the same, made inside your buy-button's click handler.

Real-life example. A pricing page has three plan buttons, each already calling Paddle.Checkout.open with its own priceId. Adding customData: { clickport_ref: window.clickport.checkoutRef() } to the shared checkout helper is the entire integration. From the next deploy on, every purchase carries its visit.

Server-created transactions

If your backend creates transactions via the Paddle API (including hosted checkout links for them), pass the token server-side instead. Read it in the browser with clickport.checkoutRef(), send it with your checkout request, and set it as custom data:

// In the browser: send the token to your backend with the checkout request
const ref = window.clickport.checkoutRef(); // "cp-1234567890"

// On your server: pass it when creating the transaction
const txn = await paddleApi.post('/transactions', {
  items: [{ price_id: 'pri_...', quantity: 1 }],
  custom_data: { clickport_ref: ref },
});
What stays unattributed. Subscription renewals count toward total revenue but never toward a source, even though Paddle copies the original custom data onto every renewal. A renewal happens without a visit, and attributing it to a session from months ago would quietly turn session attribution into lifetime-value guessing, so we don't. Each purchase carries an attributed property so you can see the split in the event's property breakdown.
What that means in practice. A customer clicks your March newsletter, subscribes to the €19/month plan: March shows a €19 Purchase attributed to the newsletter. The April, May, and June renewals each add €19 to total revenue with no source. Your newsletter's revenue number stays what that campaign actually closed, not a growing echo of it.

Refunds correct the record

When you approve a refund (or a chargeback lands), Clickport writes a negative revenue event dated at the refund, carrying the original visit's source and campaign. If one of July's 21 newsletter purchases refunds in August, the newsletter's revenue self-corrects by that €49 without you touching anything.

Manual revenue tracking still works

The Paddle integration and the custom events API compose. If you sell through something else too, or want revenue on non-payment events, keep using:

clickport.track('Order Completed', { plan: 'yearly' }, { amount: 149, currency: 'EUR' });

The Revenue stat and chart line sum every event that carries revenue, whichever way it got there. Selling through Stripe as well? The Stripe integration runs side by side with this one.

Multi-currency

Amounts are recorded in the currency the customer paid, including tax: the checkout total, which is the number that matches what your customer saw. Zero-decimal currencies (yen and won) are handled correctly.

Paddle is a merchant of record, so customers often pay in their local currency and your revenue arrives mixed. Pick a reporting currency on the same Integrations tab and Clickport converts every payment into it at the daily European Central Bank reference rate of its payment date: one currency everywhere, past payments included. The original charged amounts are always kept unchanged, and switching back to "As charged" restores them. Without a reporting currency, totals are displayed in whichever currency carries the largest share.

Disconnecting

Click Disconnect Paddle on the Integrations card. Clickport deletes the encrypted key immediately and removes the webhook destination it created on your Paddle account. Revenue already imported stays in your analytics; reconnecting later won't double-import it, because every processed payment is remembered by its Paddle ID.

Troubleshooting

"Paddle did not accept the key"

The key is wrong, revoked, or from the sandbox environment. Clickport connects to live Paddle accounts; create the key in your production dashboard and paste it again.

"The key needs read access to Transactions and Adjustments"

The key exists but lacks the read permissions. Edit the key in Paddle, grant Transactions — Read and Adjustments — Read, and paste it again.

Payments arrive but show as unattributed

  • The one-line customData pass-through has to be in your checkout call. Without it there is no token to join, and that's the most common cause.
  • The buyer must have the Clickport tracker loaded on the page that opened checkout. If checkout starts from a page without the tracker (an email link, a separate landing page), there's no session to join.
  • Subscription renewals are unattributed by design; see the note above.
  • Ad blockers that block the tracker also block attribution for that visitor. The payment still counts via Paddle, just without a source.

Revenue totals differ from the Paddle dashboard

Clickport records the checkout total: what the customer paid, including tax. Paddle's own reporting often leads with earnings, which subtracts tax and Paddle's fee. Clickport also timestamps at payment time in your dashboard timezone, while Paddle may group by UTC days or settlement dates. Both differences are expected.

Privacy and data handling

  • Your API key (and the webhook signing secret, in real-time mode) is AES-256-GCM-encrypted at rest. Disconnecting deletes it immediately.
  • The key is read-only by your own scoping; Clickport cannot modify anything in your Paddle account beyond the webhook destination you optionally allow it to create.
  • Clickport stores the payment amount, currency, timestamp, and Paddle object IDs. No customer names, emails, or card details are read or stored.
  • Attribution uses the session token alone. No cookies, no fingerprinting, no cross-session identity. Connecting or disconnecting the integration is recorded in your site's audit trail.