# Stripe revenue attribution

> Connect a restricted Stripe key and attribute successful Stripe payments to analytics sessions.

- Canonical: https://tracekit.dev/docs/analytics/stripe

The key stays on the server.
Never place a complete Stripe key in client code, documentation, or screenshots.

## Connect Stripe

Stripe connection is optional.
Only project owners can connect, replace, configure, or remove Stripe.
TraceKit accepts one `rk_live_...` key.
It rejects test, secret, publishable, and whitespace-modified keys.

Create a restricted key with these permissions:

  <a
    href="https://dashboard.stripe.com/apikeys/create?name=TraceKit%20Revenue%20Attribution&permissions%5B%5D=rak_connected_account_read&permissions%5B%5D=rak_charge_read&permissions%5B%5D=rak_checkout_session_read&permissions%5B%5D=rak_invoice_read&permissions%5B%5D=rak_product_read"
    target="_blank"
    rel="noopener noreferrer"
    className="not-prose my-3 inline-flex min-h-11 items-center gap-2 rounded-lg bg-blue-600 px-4 py-2 text-sm font-semibold text-white no-underline transition-colors hover:bg-blue-700 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-600"
  >
    Create a read-only Stripe API key
    <span aria-hidden="true">↗</span>
  </a>

  1. Scroll down and select **Create key**.
  2. Do not change the selected permissions.
  3. Copy the key and paste it into TraceKit.
  4. Keep the key active so TraceKit can refresh revenue.

Replace an existing TraceKit key if it lacks **Charges: Read** or **Invoices: Read** access.

| Stripe resource | Permission | Validation call | Purpose |
|-----------------|------------|-----------------|---------|
| Account data | Read | `GET /v1/account` | Validate the connected Stripe account. |
| Charges | Read | `GET /v1/charges?limit=1` | Import successful payments from supported Stripe payment flows. |
| Checkout Sessions | Read | `GET /v1/checkout/sessions?limit=1` | Add attribution metadata and product details when available. |
| Invoices | Read | `GET /v1/invoices?limit=1` | Identify renewals and products for invoice payments. |
| Products | Read | `GET /v1/products?limit=1` | Support saved product filters. |
| All other resources | None | No preflight call | Apply least privilege. |

Enter the restricted key in the project owner Stripe settings.
TraceKit validates the Account, Charges, Checkout Sessions, Invoices, and Products calls.

## Add Checkout metadata

Put attribution identifiers directly on `Checkout Session.metadata`.
Read the host-only cookies in a same-origin Next.js server route.

```ts
import { cookies } from 'next/headers';

const cookieStore = await cookies();
const visitorId = cookieStore.get('tracekit_visitor_id')?.value;
const sessionId = cookieStore.get('tracekit_session_id')?.value;

if (!visitorId || !sessionId) {
  return new Response('TraceKit analytics IDs are unavailable', { status: 400 });
}

const session = await stripe.checkout.sessions.create({
  mode: 'payment',
  line_items: [{ price: 'price_...', quantity: 1 }],
  success_url: 'https://example.com/success',
  cancel_url: 'https://example.com/cancel',
  metadata: {
    tracekit_visitor_id: visitorId,
    tracekit_session_id: sessionId,
  },
});
```

Use this example only when the Checkout route shares the browser hostname.

The Browser SDK exposes no public visitor or session identity getter.
Host-only cookies use `Path=/` and `SameSite=Lax`.
HTTPS adds `Secure`.
The visitor cookie lasts 365 days.
The session cookie expires after 30 minutes of inactivity.
Host-only cookies do not reach another API host.
Blocked cookies prevent the server route from reading attribution IDs.
Payments without readable IDs remain visible as unmatched.

| Metadata field | Status | Meaning |
|----------------|--------|---------|
| `tracekit_visitor_id` | Required for attribution | Browser visitor ID with 32 lowercase hexadecimal characters, and not all zeroes. |
| `tracekit_session_id` | Required for attribution | Browser session ID with 32 lowercase hexadecimal characters, and not all zeroes. |
| `tracekit_trace_id` | Optional | Enables `View checkout trace` when the trace exists. |
| `tracekit_user_id` | Optional | Stores an opaque internal user ID for future use. |

## Verify sync and attribution

TraceKit polls successful Charges every five minutes.
Analytics revenue needs no webhook setup.

TraceKit imports only successful, paid, captured, live-mode Charges.
Checkout Sessions enrich matching Charges with attribution metadata and product details.
TraceKit does not count Checkout Sessions as separate payments.
Revenue uses the gross captured amount.
Refunds do not reduce reported revenue.
Renewals are included by default.
Excluding renewals changes reports only.
TraceKit does not import subscription cancellations.
TraceKit performs no foreign-exchange conversion.
The selected dashboard currency controls which imported revenue appears.

The first import covers the 30-day analytics retention window.
Later syncs resume from a cursor and reconcile the prior 24 hours.
Unmatched payments stay visible.
Removing Stripe deletes its connection settings and imported payments.

## Continue

- [Return to Analytics setup](/docs/analytics) for browser installation.
- [Read the analytics reference](/docs/analytics/reference) for attribution and revenue states.
