Polar revenue attribution

Pass XPmetric visitor IDs into Polar Checkout Session metadata for revenue-by-channel reporting.

Connect Polar in Settings → Integrations, then pass XPmetric visitor IDs into Checkout Session metadata.

Prerequisites

  1. Install p.js on your site.
  2. Connect Polar with an Organization Access Token in Settings → Integrations → Polar.
  3. Create checkout sessions via the Polar API — static Checkout Links cannot carry per-visitor metadata.

With the default cookieless p.js, first-touch attribution is scoped to the UTC day of the visitor ID sent at checkout. A delayed payment can still match that day's visit when it carries the ID; a later visit gets a new ID. For cross-day first-touch, choose cookie mode in Settings → Sites: its p.cookie.js script uses the first-party _xpm_id cookie. Compare tracking modes.

Metadata keys

Use the same keys as Stripe:

  • xpm_visitor_id ← window.xpmetric.v
  • xpm_session_id ← window.xpmetric.s

Server route (Next.js + @polar-sh/sdk):

// app/api/checkout/route.ts — create a Polar Checkout Session server-side
import { Polar } from "@polar-sh/sdk";
import { NextResponse } from "next/server";

const polar = new Polar({
  accessToken: process.env.POLAR_ACCESS_TOKEN!,
  // server: "sandbox", // uncomment for Polar sandbox
});

export async function POST(req: Request) {
  const { productId, xpm_visitor_id, xpm_session_id } = await req.json();

  const checkout = await polar.checkouts.create({
    products: [productId],
    metadata: {
      xpm_visitor_id: xpm_visitor_id || "",
      xpm_session_id: xpm_session_id || "",
    },
    successUrl: `${process.env.NEXT_PUBLIC_APP_URL}/thanks?checkout_id={CHECKOUT_ID}`,
  });

  return NextResponse.json({ url: checkout.url });
}

Client checkout call:

// Client — wait briefly for XPmetric's first pageview response
const { v, s } = await window.xpmetric?.ready?.() ?? {};

const res = await fetch("/api/checkout", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    productId: "YOUR_POLAR_PRODUCT_ID",
    xpm_visitor_id: v || "",
    xpm_session_id: s || "",
  }),
});

const { url } = await res.json();
window.location.href = url;

XPmetric sync reads these keys from order metadata after connect.

@polar-sh/nextjs

If you use the Next.js adapter, pass metadata as a URL-encoded JSON query param on your checkout handler route — see the Polar settings panel in XPmetric for the exact snippet.

Verify

Complete a sandbox or live checkout, then check the site dashboard revenue chart and Channels → Revenue view after sync.