Polar tells you what you earned. It cannot tell you what earned it.
Connect it and every payment is matched to the visit that led to it, so the revenue card breaks down by channel, campaign and landing page beside the traffic that produced it.
What you get
Payments attributed to a source. A sale traced back to the search, the post or the campaign that brought the customer.
The subscription goals, with no code from you — the full list covers trials, upgrades, downgrades, pauses, cancellations and churn.
MRR, with a yearly plan counted as its monthly equivalent rather than as a spike and then a crash.
Your history, imported once on connection — including its attribution, which is unusual and explained below.
Connecting
Create an access token
Settings → Developers → New Token, and tick five boxes:
| Scope | What it is for |
webhooks:write | Setting up event delivery |
orders:read | Payments and refunds |
subscriptions:read | MRR and churn |
products:read | Product names |
checkouts:read | Attribution from your checkout |
Tick webhooks:write first — it is the one that fails loudest and latest.
A missing read scope shows up the first time that data is needed; a missing
webhooks:write stops the connection from being made at all.
Nothing pre-ticks these. Polar has no equivalent of Stripe's permissioned link, so this list is the instruction.
Polar's new-token dialog with the five scopes ticked: Webhooks (write) and read on Orders, Subscriptions, Products and Checkouts. Light theme, cropped to the scope list.
Find your organization ID
Settings → General → Profile, the field named Identifier — a UUID like
98897d14-e6e4-448b-9fa7-26c812cd7881.
You supply this rather than us picking it, because a token can reach several organizations and only you know which one this site sells through. It is also checked against the token, so a token pointed at a different organization is caught before any money is read.
Paste both into TrueStat
Settings → Integrations → Polar. The token is encrypted before it is stored, and the webhook is created for you.
Site settings, Integrations tab: the Polar card with the Access token and Organization ID fields, before any connection. Light theme, cropped to the card.
Sandbox and production are different addresses. A sandbox token is refused by the production API with a plain "invalid token" that reads exactly like an expired one. The link in the connection screen already points at the right dashboard for your environment — use it rather than navigating there yourself.
Linking a payment to a visitor
Without this, payments still appear — but under Unattributed, because nothing connects the payment to the visit that led to it.
Our script stores a visitor id in a cookie. How you pass it to Polar depends on how your checkout opens:
On Polar, metadata reaches your history too. Its API returns checkout metadata on listed orders, so payments made before you connected arrive already attributed — which no other provider we support can do.
What the numbers mean
Amounts include tax. A €100 sale with €20 VAT is recorded as €120, matching what Polar shows.
Fees are recorded, not subtracted. Polar is the merchant of record, so its fee is stored beside the amount — the revenue figure is the gross, which is the number that reconciles with your dashboard.
A plan change is counted as the difference. Moving a customer from $29 to $79 records $50 of new MRR, not $79 — the $29 was already there.
A downgrade can produce a negative payment, and it is real.
Moving to a cheaper plan makes Polar issue a credit for the unused time, and that credit arrives as an order with a negative total. It is not a refund: nothing was returned to the card, the charge and the credit simply cancel out.
You will see both rows. Their sum is what the customer actually paid, and it is what your Polar dashboard shows.
The Revenue card with a Polar connection: total, new versus renewal, and refunds over the selected range. Light theme, cropped to the card.
Your history comes with you
Connecting imports the organization's past orders and subscriptions, so the dashboard is not empty on day one.
Polar's history keeps its attribution
This is the one place Polar does better than the others. Its API returns the checkout metadata on a listed order, so imported payments arrive already matched to the visit that produced them — as far back as your records go.
Stripe, Paddle and LemonSqueezy all lose that on import: their listed objects carry no metadata, so history lands under Unattributed and attribution starts from the first payment after connecting.
The revenue breakdown by channel shortly after connecting Polar, with imported payments already carrying a source rather than sitting under Unattributed. Light theme, cropped to the breakdown.
Re-syncing later
Settings → Integrations → Polar → Re-sync history rebuilds payments and subscriptions from the organization.
It is safe to repeat: a payment already recorded is not counted twice. Your recorded lifecycle events — upgrades, pauses, trial conversions — are kept as they happened, because no provider can reproduce when they happened after the fact.
Disconnecting
Settings → Integrations → Polar → Disconnect removes the webhook from your organization, deletes the stored token, and clears the revenue this connection wrote. Your pageviews and goals are untouched.
If something is not working
The token was refused. Usually the environment: a sandbox token cannot read production, and the error does not say so. Check which dashboard you created it in.
The connection failed while creating the webhook. webhooks:write was not
ticked. Tokens cannot be edited — create a new one with all five scopes.
Payments arrive but everything is Unattributed. The checkout is not
passing ts_vid in its metadata. Check that you read
window.truestat.visitorId at click time rather than at page load.
A payment is missing. Only orders that actually collected money are
recorded — an order still pending, and the zero-amount order Polar writes
when a free trial starts, are not revenue and are deliberately skipped.