Docs → Integration guide

Integration guide

uReferrals attributes affiliate conversions using a first-party cookie set on the customer's browser, then a server-verified conversion event. Same primitives regardless of how you install — the choice is only how you deliver them.

On this page

How attribution works

The tracker script (/t/tracker.js) does three things when it loads on your site:

  1. Reads ?ref=<code> off the current URL and writes a first-party cookie named _uref.
  2. Scopes the cookie to your parent domain (via data-cookie-domain=".yourdomain.com") so a visitor on www.yourdomain.com can still be identified on app.yourdomain.com.
  3. Exposes window.uReferrals so your app can read the referral back at checkout time.

Conversions are reported in one of two ways: either from a signed Stripe webhook we listen to on your behalf (Stripe Connect), or via POST /t/conversions from your server. We never trust the browser for the money-affecting event — client-side convert() exists but is only for narrow use-cases like non-payment signups.

Choose your install path

WordPress + WooCommerce
Install a plugin, paste two keys. Zero code.
Google Tag Manager
OAuth into Google, we create the tag for you. You publish.
Stripe Connect
Connect Stripe, we register the webhook. Most secure, zero code.
AI-assisted
Paste a prompt into Cursor / Claude Code. For split-app or unusual stacks.
Custom code
Full control: install the tracker snippet, POST from your backend.

WordPress + WooCommerce

The plugin handles both sides — it injects the tracker on every page and reports order-completed events server-side via the API. Best fit for storefronts.

  1. Download the plugin from any program page in your dashboard (Install tracking → Download WordPress plugin) — or direct link.
  2. WordPress admin → Plugins → Add new → Upload plugin → select the zip → Activate.
  3. Settings → uReferrals. Paste the publishable key and API key from your program.
  4. Set the cookie domain if marketing and checkout live on different subdomains — e.g. .yourdomain.com (with the leading dot).
  5. Save. The Status block at the bottom should flip to all ✅.
The plugin uses WooCommerce's woocommerce_order_status_completed and _processing hooks, so it reports conversions the moment orders finalize. Refund clawbacks fire on woocommerce_order_status_refunded.

Google Tag Manager

We install the tracker as a Custom HTML tag firing on All Pages. Prefill of publishable key and cookie domain happens automatically from your program config.

  1. Dashboard → Programs → open a program → Install trackingAdd to Google Tag Manager.
  2. Sign in with the Google account that owns your GTM container.
  3. Pick account → container → workspace. Confirm the cookie domain.
  4. We create the tag. Important: open GTM and hit Submit → Publish — nothing goes live until you do. GTM shows the workspace as "1 unpublished change" until then.
GTM is Custom-HTML only for now. Server-side GTM containers aren't supported yet — use Stripe Connect or the server-side API instead if that's your setup.

Stripe Connect (recommended for SaaS)

The highest-integrity option: Stripe fires a signed webhook to us on checkout.session.completed, we look at the customer's referral cookie, we credit the affiliate. Zero server code, un-spoofable, and clawbacks on charge.refunded happen automatically.

  1. Dashboard → PayoutsConnect Stripe.
  2. Complete Stripe's OAuth flow. We store your account ID and register a webhook endpoint on your behalf.
  3. Install the tracker on your site (either via GTM, custom snippet, or the AI prompt). The tracker sets the referral cookie — that's the only piece Stripe Connect needs from you.
  4. Test with a small live charge or a Stripe test-mode session. See Verify end-to-end.

Manual Stripe (own account + own webhook)

If you can't or don't want to use Stripe Connect (you run your own Stripe integration with your own webhook signing), forward the referral into metadata.ur_affiliate_ref when creating each Checkout session — then either report the conversion server-side to us, or register an additional webhook endpoint that forwards checkout.session.completed to POST /t/conversions.

Frontend — capture the ref before checkout

const meta = window.uReferrals?.metadataPayload?.() || {}
// meta === { ur_affiliate_ref: "abc123xyz0" } when a referral cookie is present
// otherwise {} — safe to always spread

await fetch('/api/checkout', {
  method: 'POST',
  body: JSON.stringify({ priceId: 'price_xxx', metadata: meta }),
})

Backend — forward into the Stripe session

const clientMeta = (req.body?.metadata || {})
const referralRef = typeof clientMeta.ur_affiliate_ref === 'string'
  ? clientMeta.ur_affiliate_ref.slice(0, 500)
  : undefined

const meta = referralRef ? { ur_affiliate_ref: referralRef } : {}

const session = await stripe.checkout.sessions.create({
  mode: 'subscription',
  line_items: [{ price: req.body.priceId, quantity: 1 }],
  success_url: 'https://yourapp.com/success',
  cancel_url:  'https://yourapp.com/pricing',
  metadata: { ...meta },                 // for the first payment
  subscription_data: { metadata: { ...meta } },  // REQUIRED for renewals
})
For recurring commissions, both metadata blocks matter. The top-level metadata attributes the first payment; subscription_data.metadata attaches the ref to the subscription so it rides onto every renewal invoice. Omit the second and your affiliates get credited once and never again.

Report the conversion (from your own Stripe webhook)

// In your existing checkout.session.completed handler:
await fetch('https://api.ureferrals.com/t/conversions', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-API-Key': process.env.UREFERRALS_API_KEY,
  },
  body: JSON.stringify({
    referralCode: session.metadata.ur_affiliate_ref,
    externalCustomerId: session.customer,
    amount: session.amount_total / 100,
  }),
})

AI-assisted (Cursor, Claude Code, v0)

For custom stacks — Vite + Express, T3, Remix, split marketing/app monorepos, unusual frameworks — the fastest path is our AI prompt. It detects your architecture (single-app vs split-app), installs the tracker in the right places, wires an env var, and updates your Stripe session code.

  1. Grab the pre-filled version from any program in your dashboard: Copy AI integration prompt. It includes your publishable key + cookie domain.
  2. Or grab the public template and swap in your key manually.
  3. Paste into Cursor / Claude Code / v0 with the target repo open. The AI should confirm which layout it detected before writing code.
  4. Set NEXT_PUBLIC_UREFERRALS_KEY on every deployed environment and rebuild.

Custom code — the raw primitives

1. Install the tracker on every page

Drop into <head>:

<script src="https://api.ureferrals.com/t/tracker.js"
        data-key="uref_pk_YOUR_PUBLISHABLE_KEY"
        data-cookie-domain=".yourdomain.com"></script>

The data-cookie-domain attribute is only needed for cross-subdomain funnels. On a single-domain site you can omit it.

2. Report conversions server-side

POST https://api.ureferrals.com/t/conversions
X-API-Key: urk_YOUR_API_KEY
Content-Type: application/json

{
  "referralCode": "abc123xyz0",
  "externalCustomerId": "cust_123",
  "amount": 99.00
}

referralCode comes from the cookie (server-side, from your own request context) or from window.uReferrals.metadataPayload() passed through your checkout. amount is in the currency your program is configured for (USD by default). Idempotency is keyed on externalCustomerId + referralCode — same pair reported twice = one conversion.

Node.js

await fetch('https://api.ureferrals.com/t/conversions', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-API-Key': process.env.UREFERRALS_API_KEY,
  },
  body: JSON.stringify({
    referralCode,
    externalCustomerId: customerId,
    amount,
  }),
})

Python

import os, requests

requests.post(
    'https://api.ureferrals.com/t/conversions',
    headers={
        'Content-Type': 'application/json',
        'X-API-Key': os.environ['UREFERRALS_API_KEY'],
    },
    json={
        'referralCode': referral_code,
        'externalCustomerId': customer_id,
        'amount': amount,
    },
)

cURL

curl -X POST https://api.ureferrals.com/t/conversions \
  -H "X-API-Key: urk_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"referralCode":"abc123","externalCustomerId":"cust_123","amount":99}'

Verify end-to-end

Before promoting to a real affiliate, prove the loop closes. Steps 1–4 don't need a payment; steps 5–7 do.

  1. Static check — dashboard → program page → Verify installation. Confirms the tracker script is present, keys match, and cookie-domain is set.
  2. Cookie sets — incognito, visit https://api.ureferrals.com/t/<any-affiliate-code>. You should land on your site with ?ref= in the URL. DevTools → Application → Cookies → look for _uref.
  3. Cookie survives — click through to your checkout/app page. _uref should still be there (this is where cross-subdomain scoping matters).
  4. Metadata forwarded — for manual Stripe: create a test-mode Checkout session. Stripe Dashboard → the session → Metadata should contain ur_affiliate_ref. For Stripe Connect: skip this step, we handle it.
  5. Test checkout — complete the flow. Card 4242 4242 4242 4242 in test mode.
  6. Conversion appears — within ~10 seconds, the conversion shows in your program under the affiliate whose code you used.
  7. Refund flow — refund the test charge. Within ~10 seconds, the conversion status flips to clawback_pending.

Common questions

My marketing and checkout are on different subdomains — will attribution work?

Only if you set data-cookie-domain=".yourparent.com" (with the leading dot) on the tracker. Without it, the cookie is host-only and won't follow visitors to a different subdomain.

What happens if the tracker runs on a page with no ?ref=?

Nothing. The tracker no-ops. It's safe to include on every page unconditionally.

Can I use both the WordPress plugin AND Stripe Connect?

Yes, but you'll double-count conversions. Pick one. Use the plugin if WooCommerce is your source of truth for orders; use Stripe Connect if your Stripe account processes charges directly (subscriptions, non-Woo storefronts).

Do I need one program per app, or one per company?

One per product line. Each program has its own key pair, commission rate, and cookie window — mixing them across products makes reporting messy. For staging vs prod, most builders just use the same program keys and filter test data downstream.

How long does the referral cookie last?

Configurable per program — default 30 days. Change it in program settings.

What about refunds and clawbacks?

All paths handle refunds. Stripe Connect fires automatically on charge.refunded. The WordPress plugin fires on woocommerce_order_status_refunded. Custom integrations POST to /t/refunds with either stripeChargeId or externalCustomerId+amount to identify the conversion. The endpoint is idempotent — safe to retry.

The effect depends on the conversion's current state: scheduled or available commissions flip to refunded (nothing to claw back — the money never moved). withdrawn commissions create a clawback_pending row that nets against the affiliate's next earning.

Stuck? Talk to a human — we'll walk through your setup. Or open your dashboard and use the Verify installation button on any program page for a targeted health check.