Paddle revenue analytics for Plain HTML
This guide adds ProductLense to a Plain HTML site and connects Paddle, so every Paddle payment is attributed to the channel, campaign and landing page that first brought the customer. It takes four steps and about ten minutes.
1. Add ProductLense to Plain HTML
The script goes in the <head> of every page. Replace SITE_ID with the id from Settings → Sites.
<head>
<!-- ... -->
<script>window.productlense=window.productlense||function(){(window.productlense.q=window.productlense.q||[]).push(arguments)}</script>
<script defer data-site="SITE_ID" src="https://api.productlense.app/a.js"></script>
</head>2. Identify signed-in users
<script>
// After signup or login, with your own user id:
window.productlense('identify', 'user_123', { email: '[email protected]' });
window.productlense('event', 'Signup', { plan: 'starter' });
</script>3. Connect Paddle
Setup steps
- In Paddle, open Developer tools → Authentication and create an API key with read access.
- In ProductLense, open Settings → Billing connections → Paddle and paste the key.
- In Paddle → Developer tools → Notifications, add a webhook endpoint with the URL ProductLense shows after you save the connection (pattern https://api.productlense.app/api/webhooks/{provider}/{connection_id}).
- Subscribe the destination to the events listed below and paste the secret key into ProductLense.
- ProductLense backfills 12 months of transactions and adjustments.
Credentials and permissions
| Field | Secret | Where to find it |
|---|---|---|
| API key | Yes, encrypted at rest | Paddle → Developer tools → Authentication. Needs read access to customers, subscriptions, transactions and adjustments. |
| Webhook secret key | Yes, encrypted at rest | The pdl_ntfset_... key shown when you create the notification destination pointing at ProductLense. |
Webhook
URL pattern, shown with your connection id after you save:
https://api.productlense.app/api/webhooks/paddle/{connection_id}Events: transaction.completed, transaction.updated, adjustment.created, adjustment.updated, subscription.created, subscription.updated, subscription.canceled, customer.created, customer.updated
Verification: Paddle-Signature header: timestamp plus h1 HMAC-SHA256, rejected after 5 minutes.
What ProductLense reads
- Customers
- Customers with email and custom data.
- Subscriptions
- Subscriptions with status and billing interval.
- Payments
- Completed transactions.
- Refunds
- Refund and chargeback adjustments.
- Fees
- Grand total minus earnings: Paddle’s cut and tax, so net revenue equals your payout.
What ProductLense never touches
- Never creates, changes, refunds or cancels anything: read-only API calls and incoming webhooks only.
- Never moves money, issues payouts, or reads bank account details.
- Never sees full card numbers; providers do not expose them.
- Never sends your customer data to the AI model: Ask and the daily insight see aggregates only.
Match payments to your users
Set custom_data.pl_user_id on the Paddle customer to the id you pass to identify for the strongest match; otherwise ProductLense matches by email.
await fetch('https://api.paddle.com/customers', {
method: 'POST',
headers: { Authorization: `Bearer ${process.env.PADDLE_API_KEY}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ email: user.email, custom_data: { pl_user_id: user.id } }),
});Paddle on Plain HTML: questions
- Where does the ProductLense script go in Plain HTML?
- In the <head> of every page. Paste the script tag into the <head> of every page, replacing SITE_ID. The script is about 2.3 KB, loads with defer, sets no cookies, and records route changes in single-page apps through the history API, so no extra router code is needed.
- How do I identify users in Plain HTML?
- Call window.productlense('identify', userId) once the signed-in user is known, as in the snippet example on this page. Use the same id you store on Paddle as pl_user_id, so Paddle payments match by id rather than by email.
- Does ProductLense work with Paddle?
- Yes. ProductLense connects to Paddle with aPI key, webhook secret key, backfills 12 months of history, and stays current through signed webhooks plus a nightly reconcile. One connection is included on Starter; Growth and Scale allow every provider at once on the same site.
- What data does ProductLense read from Paddle?
- Customers, subscriptions, payments, refunds and fees, read-only. Payments: completed transactions. Refunds: refund and chargeback adjustments. Fees: grand total minus earnings: Paddle’s cut and tax, so net revenue equals your payout.
- Can ProductLense change anything in my Paddle account?
- No. ProductLense only makes read calls and receives webhooks. It never creates, changes, refunds or cancels anything, never moves money, and never sees card numbers. Credentials are encrypted at rest, and the AI features only ever see aggregated numbers, never your customers’ data.
Free up to 10k events a month. No card.
Add the script, connect Stripe or any of 14 other billing providers, and see revenue by channel the same day.