# How to track lead source in Polar

Tie every Polar order, subscription, and renewal back to the marketing channel that drove it. Revenue attribution for open-source maintainers and developer-tool SaaS.

Source: https://sourceloop.ai/help/track-lead-source-in-polar/
Updated: 2026-05-28

---

Polar is the merchant-of-record platform built around the GitHub-native developer ecosystem, sponsorships, paid issues, license products, and SaaS, all from the same primitives. The blind spot, like every payments tool, is **which marketing channel earned each subscriber**. SourceLoop fills that in without changing how Polar charges your customers.

Every order, every subscription event, every refund mapped back to the visitor's original session, so Polar's revenue dashboard finally answers the marketing question too, not just "what did we make" but "which content, repo, or sponsorship link produced it".

Five steps, around ten minutes. Works on every Polar organisation.

## Why this matters

Polar is heavy on indirect channels, GitHub README links, Discord drops, dev blog mentions, conference repos. The revenue lifecycle that comes out the other side is hard to map without attribution that follows the customer through:

- A developer reads your README in March, clicks the Polar buy link, and starts the $19/mo plan
- They upgrade to $99/mo in July when their team grows
- They renew every month for two years
- They cancel when they migrate to a self-hosted alternative

Without revenue tracking, "github" gets credit for one event and never sees the $2,000+ that flowed from it. With Polar wired into SourceLoop, every state change, every renewal, every cancel hangs off the same contact, and channel-level MRR finally has signal.

## What SourceLoop captures from Polar

Each Polar customer arrives in SourceLoop tagged with:

- **Acquisition channel** of the visitor at signup (paid, organic, social, referral, direct, GitHub)
- **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 Polar's customer record
- **First-touch landing page** plus the original referrer
- **Source of the converting session** (often distinct from first-touch)
- **Full revenue history**, orders (initial + renewals), subscription created / active (trial converted) / updated / canceled / revoked
- **Device, country, browser**

## Before you start

You'll need:

- A **SourceLoop workspace** ([free trial](https://app.sourceloop.ai/sign-up))
- **Edit access** to the site that hosts your Polar buy link or backend API
- A **Polar organisation** with at least one product live
- **Admin access** to your Polar 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](/help/screenshots/sourceloop-tracking-code-script.png)

Paste it into the `<head>` of every page on your site, especially the pages with your Polar Checkout buttons or buy links. From this point on, every visitor session, UTM, and journey is being recorded. The next steps connect that data to the orders Polar will start sending.

## Step 2: Add a webhook in your Polar Dashboard

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

1. In SourceLoop, open **Setup -> Payment** in the sidebar.

![SourceLoop Setup Payment page showing the supported payment provider cards](/help/screenshots/sourceloop-payment-page.png)

2. Click the **Polar** 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](/help/screenshots/sourceloop-payment-webhook-drawer.webp)

3. Open the [Polar Dashboard](https://polar.sh/), navigate to **Settings -> Webhooks**, and click **Add endpoint**.
4. Paste SourceLoop's URL into the endpoint URL field.
5. Under **Events**, select the events SourceLoop needs to read. The recommended set: `order.created`, `subscription.created`, `subscription.active`, `subscription.updated`, `subscription.canceled`, `subscription.revoked`.
6. Save the endpoint. Polar generates a **Signing secret** (prefixed `whsec_...`), copy it.

> **Multiple endpoints are fine**
> You can add SourceLoop alongside any webhook endpoint you've already configured. Polar delivers each event to every endpoint independently.

## Step 3: Paste the signing secret back into SourceLoop

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

1. Copy the `whsec_...` value from the endpoint detail page in Polar.
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 Polar 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 for one-off buys where the customer has no pre-purchase site history.

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

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

Pass that object through to Polar using the method that matches your checkout. Use this guide to pick:

- **(1) Checkouts API** — Recommended for any production setup. If you create the checkout server-side using the Polar SDK (or the underlying REST API) and redirect the customer to the returned URL, this is you. Picked by SaaS, paid licenses, and anyone who needs server-validated prices or pre-applied discounts.
- **(2) Polar Checkout Links** — Static `buy.polar.sh/...` URLs you paste into a GitHub README, Discord, a docs page, or a blog post. Easiest to deploy, lower fidelity than the API because the metadata travels through query parameters.

Wire each one you use.

### (1) Checkouts API

Pass `metadata` when creating the checkout server-side. Polar attaches it to the resulting Order and Subscription so every downstream event stays stitched.

Server (Node.js):

```js
import { Polar } from '@polar-sh/sdk';

const polar = new Polar({ accessToken: process.env.POLAR_ACCESS_TOKEN });

const checkout = await polar.checkouts.create({
  products:   ['prod_xxx'],
  successUrl: 'https://your.site/thanks',
  metadata:   meta,
});

return { url: checkout.url };
```

### (2) Polar Checkout Links

Patch each Polar buy link with `metadata[key]` query parameters before the visitor clicks.

```html
[Subscribe](https://buy.polar.sh/polar_cl_xxx)

<script>
  document.querySelectorAll('a.polar-buy').forEach(a => {
    const m = window.sourceloop.checkoutMetadata();
    const u = new URL(a.href);
    u.searchParams.set('metadata[sourceloop_anonymous_id]', m.sourceloop_anonymous_id);
    u.searchParams.set('metadata[sourceloop_id]',           m.sourceloop_id);
    a.href = u.toString();
  });
</script>
```

> **Customer-supplied metadata must be enabled on the link**
> Confirm in your Polar Dashboard that customer-supplied metadata is enabled for the checkout link. If it's disabled, the query parameters are dropped, and SourceLoop falls back to matching by customer email.

> **Let your AI assistant do the wiring**
> If you'd rather not patch every Polar integration point by hand, paste the snippets above into Cursor, Claude Code, or your IDE assistant with the prompt "Apply these Sourceloop attribution patterns to every Polar integration in this codebase. Show me the files you plan to touch before editing." It'll find every `polar.checkouts.create` call and every `buy.polar.sh` link, and patch them in one pass.

## Step 5: Run a test order to verify

Open the page with your Polar checkout in an **incognito window**, append `?utm_source=test&utm_medium=verify&utm_campaign=polar-check` to the URL, and complete a real transaction. Polar's test mode is the safest path if you'd rather not move real money.

Within seconds of Polar confirming the order, 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.

> **Not seeing the event?**
> Inside SourceLoop, open the Polar connection card and check the **Last event** timestamp. If it's stale, the webhook isn't reaching SourceLoop, check Settings -> Webhooks -> the endpoint's delivery log in Polar. If events are received but the contact isn't linking, the most common cause is `metadata` not being passed at checkout, or customer-supplied metadata being disabled on the link, double-check step 4.

## Where to see Polar revenue in SourceLoop

### Contacts Hub: revenue per contact

Every Polar customer becomes a contact row at [app.sourceloop.ai/contacts](https://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 order, every renewal, every plan change, every cancellation, 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 (GitHub, Reddit, your docs site) are bringing in paying subscribers vs. just stargazers.

![SourceLoop Contacts Hub showing a Polar customer with the revenue column, full pre-purchase journey, and revenue history](/help/screenshots/sourceloop-lead-journey-demo.webp)

### Attribution dashboard: revenue by channel

[app.sourceloop.ai/dashboards/traffic](https://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 "github.com referral drove 1,200 sessions", you see "github.com referral drove 1,200 sessions and $3,400 in attributed Polar 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)

For developer products, the README typically gets a discovery role and the docs get the conversion. First Touch shows you the README is doing its job; Last Touch shows you the docs page is closing. Both numbers are real, depending on which question you're asking.

![SourceLoop attribution dashboard with Polar revenue column grouped by source, medium, and campaign](/help/screenshots/sourceloop-attribution-dashboard.webp)

Once Polar revenue is flowing, push it back to **Google Ads, Meta, and LinkedIn as offline conversions with revenue values** so the bidding algorithms optimise toward paying customers, not just clicks. [Connect your Google Ads account](/help/connect-google-ads/) covers the wiring.

## Frequently Asked Questions

### Does this work with the Polar Checkouts API and Polar's static Checkout Links?

Yes. Both surfaces are covered. The webhook setup is identical for both, only the attribution wiring in step 4 differs. The article walks through each method.

### Are subscription renewals attributed back to the original source?

Yes. Every `order.created` event tied to a recurring subscription cycle gets stitched onto the same contact that started the subscription, so MRR stays tied to the channel that earned the original signup.

### How do refunds and cancellations show up?

Cancellations come through as `subscription.canceled` and `subscription.revoked`, which SourceLoop records as a state change on the contact. Refunds reduce the contact's attributed revenue and flow back to the original source in the dashboard.

### I'm using Polar as a GitHub-integrated sponsorship / paid issues product. Anything different?

No. Whether Polar is hosting sponsorships, paid issues, products, or full subscriptions, every order or subscription event flows through the same webhook channel. SourceLoop attributes them the same way.

### My Polar Checkout Link is shared on GitHub README and Discord, not on a tracked page. Are those purchases attributed?

When the customer clicks a Checkout Link from outside your tracked site, SourceLoop can't see a pre-purchase journey. The purchase is still captured (via the webhook) but the source shows as "Direct" since there's no UTM trail. Patch the Checkout Link with metadata via JavaScript on a tracked page to keep the source intact.

### Will my Polar webhooks to other tools (Slack, my backend) still fire?

Yes. SourceLoop subscribes as its own endpoint. Every other endpoint you've configured continues to receive Polar events independently.
