---
name: referralmeter-install
description: Install Referralmeter affiliate tracking in a web app (script tag, signup call, checkout metadata, billing webhook) and prove it works with a live verification run. Use when the user asks to add Referralmeter, an affiliate program, or referral tracking to their app.
---

# Install Referralmeter and verify it

You need the program's public key (`pk_…`) and a secret key (`sk_…`, write scope). The user finds both in Referralmeter → Install & verify. If the Referralmeter MCP server is connected, call `get_program` for the public key and `get_install_instructions` for steps tailored to this program, and use `start_verification` / `get_verification` instead of curl.

Keep the secret key in an environment variable named `REFERRALMETER_SECRET_KEY`. Never commit it and never send it to the browser.

## 1. Detect the stack

Read `package.json`. Framework: `next`, `react`, `vite`, `remix`, `astro`, `sveltekit`, `plain`. Billing: look for the SDK in dependencies (`stripe`, `@polar-sh/sdk`, `@lemonsqueezy/lemonsqueezy.js`, `@paddle/paddle-js` or `@paddle/paddle-node-sdk`, `creem`, `dodopayments`). If you can't tell, ask the user.

## 2. Add the tracking script

```html
<script src="https://referralmeter.com/t.js" data-key="pk_…" async></script>
```

- **Next.js**: In the root layout (`app/layout.tsx`, or `pages/_document.tsx` on the Pages Router), inside `<head>`. A plain `<script>` tag works; don't wrap it in a component that only renders on some routes.
- **React (SPA)**: In `index.html`, inside `<head>`.
- **Vite**: In `index.html`, inside `<head>`.
- **Remix / React Router**: In `app/root.tsx`, inside `<head>` next to `<Links />`.
- **Astro**: In the base layout every page uses (e.g. `src/layouts/Layout.astro`), inside `<head>`. Add `is:inline` so Astro doesn't bundle it.
- **SvelteKit**: In `src/app.html`, inside `<head>`.
- **Plain HTML**: In `<head>` of every page a visitor can land on, including the pricing and signup pages.

## 3. Report signups

Right after an account is created, where the new user's email is known:

```js
window.referralmeter?.signup(user.email, { uid: user.id });
```

If signup only completes on the server, POST to `https://referralmeter.com/api/v1/referrals` with `{"email","external_id","referral","ip"}` and the secret key as a Bearer token; `referral` is `window.referralmeter.ref()` sent up from the signup form.

## 4. Pass the referral into checkout

### Stripe

```js
// Browser: read the referral and send it to the endpoint that creates the Checkout Session.
const ref = window.referralmeter?.ref() ?? null;

// Server, in stripe.checkout.sessions.create({...}):
client_reference_id: ref ?? undefined,
metadata: { referralmeter_ref: ref ?? "" },
subscription_data: { metadata: { referralmeter_ref: ref ?? "" } }, // subscriptions only

// Payment Links, the pricing table and Buy Buttons need no code: the script adds client_reference_id itself.
```

### Polar

```js
const ref = window.referralmeter?.ref() ?? null; // send to your server

// Server, when creating the checkout (Polar SDK: polar.checkouts.create):
metadata: { referralmeter_ref: ref ?? "" },
```

### Lemon Squeezy

```js
const ref = window.referralmeter?.ref() ?? null;

// Checkout API (POST /v1/checkouts), in attributes:
checkout_data: { custom: { referralmeter_ref: ref ?? "" } },

// Or on a hosted checkout URL:
// https://<store>.lemonsqueezy.com/buy/<variant>?checkout[custom][referralmeter_ref]=<ref>
```

### Paddle

```js
// Paddle.js overlay or inline checkout:
Paddle.Checkout.open({
  items: [/* … */],
  customData: { referralmeter_ref: window.referralmeter?.ref() ?? "" },
});

// Or server-side, when creating a transaction: custom_data: { referralmeter_ref: ref }
```

### Creem

```js
const ref = window.referralmeter?.ref() ?? null;

// Server, when creating the checkout session (POST /v1/checkouts):
metadata: { referralmeter_ref: ref ?? "" },
```

### Dodo Payments

```js
const ref = window.referralmeter?.ref() ?? null;

// Server, when creating the payment, subscription or checkout session:
metadata: { referralmeter_ref: ref ?? "" },
```

### Other / custom billing

```js
// Send the referral to your server with the purchase:
const ref = window.referralmeter?.ref() ?? null;

// Then, on your server, when a payment succeeds:
await fetch("https://referralmeter.com/api/v1/track/sale", {
  method: "POST",
  headers: { authorization: `Bearer ${process.env.REFERRALMETER_SECRET_KEY}`, "content-type": "application/json" },
  body: JSON.stringify({ event_id: payment.id, amount: payment.amountCents, currency: "usd",
    customer_external_id: user.id, customer_email: user.email, referral: ref, livemode: !isTestPayment }),
});
// Refunds: POST /api/v1/track/refund { event_id, payment_id, amount }
```

## 5. Connect billing

- **Stripe**: Billing connections → Stripe → paste a restricted key with only "Webhook Endpoints: Write" permission. Referralmeter creates the webhook endpoint in your Stripe account itself, so there is no signing secret to copy. Events: checkout.session.completed, checkout.session.async_payment_succeeded, invoice.paid, refund.created, charge.dispute.created, customer.subscription.deleted.
- **Polar**: Polar → Settings → Webhooks → Add endpoint. URL: the Polar webhook URL from Referralmeter's Billing connections page. Format: Raw. Copy the signing secret back into Billing connections. Events: order.paid, refund.created, refund.updated, subscription.revoked.
- **Lemon Squeezy**: Lemon Squeezy → Settings → Webhooks → +. URL: the Lemon Squeezy webhook URL from Billing connections. Choose a signing secret and paste the same value into Billing connections. Events: order_created, subscription_payment_success, order_refunded, subscription_payment_refunded, subscription_expired.
- **Paddle**: Paddle → Developer tools → Notifications → New destination. URL: the Paddle webhook URL from Billing connections. Copy the destination's secret key (pdl_ntfset_…) into Billing connections. Events: transaction.completed, adjustment.created, adjustment.updated, subscription.canceled.
- **Creem**: Creem → Developers → Webhooks → Add webhook. URL: the Creem webhook URL from Billing connections. Copy the signing secret into Billing connections. Events: checkout.completed, subscription.paid, refund.created, dispute.created, subscription.canceled, subscription.expired.
- **Dodo Payments**: Dodo Payments → Developer → Webhooks → Add endpoint. URL: the Dodo webhook URL from Billing connections. Copy the signing secret (whsec_…) into Billing connections. Events: payment.succeeded, refund.succeeded, dispute.opened, subscription.cancelled, subscription.expired.

The webhook URL is shown in Referralmeter → Billing connections. If you can't reach the user's billing dashboard, give the user these exact steps and wait for them to confirm.

## 6. Verify

Deploy the changes first (the test link opens the live site). Then:

```sh
curl -s -X POST https://referralmeter.com/api/v1/verifications -H "Authorization: Bearer $REFERRALMETER_SECRET_KEY"
```

The response has `testLink` and `id`. Ask the user to open `testLink` in a fresh browser window, sign up with a new test account and pay with a test card in test mode. Poll every 5 seconds:

```sh
curl -s https://referralmeter.com/api/v1/verifications/<id> -H "Authorization: Bearer $REFERRALMETER_SECRET_KEY"
```

Each response lists `steps` (click, lead, payment, commission, optional refund) with timestamps, a `next` sentence and `diagnostics`. When a step stays empty, fix what they point at, redeploy, and keep polling. Stop when `status` is `passed`, then show the user `certificate_url`.

## Rules

- Test payments and verification runs are recorded but never paid out, so verifying is safe.
- Don't change prices, plans or existing analytics.
- Referralmeter never moves money; there is nothing to set up for payouts.

## MCP (optional)

```sh
claude mcp add --transport http referralmeter https://referralmeter.com/api/mcp --header "Authorization: Bearer sk_…"
```

Docs: https://referralmeter.com/docs · API: https://referralmeter.com/api/v1/openapi.json
