Cookies + cref
OpenPartner attribution is a cross-domain problem. The click happens on the partner’s
share URL (share.creator.com/r/foo or app.openpartner.dev/r/...). The conversion happens
on the brand’s site (acme.com/signup). Different domains. The browser won’t share cookies
between them. Referer headers get stripped by Safari ITP, by privacy-focused browsers, and
by any HTTPS → HTTP transition.
So how does the conversion get attributed back to the right partner?
The trick: cref
Every click on a share link generates a unique clickId (a ULID). The router:
- Records the
Clickrow server-side, keyed by the clickId - Appends
?cref=<clickId>to the destination URL as a query param (or, when the destination contains the{click_id}macro, puts the clickId there instead) - 302-redirects the user to that URL
The user lands on https://acme.com/signup?cref=01ARZ3NDEKTSV4RRFFQ69G5FAV.
From here the brand’s site needs to hold on to that clickId until the visitor signs up, then tell OpenPartner who signed up. There are two ways to do it.
With the OpenPartner SDK (the script tag or @openpartner/sdk), on page load the SDK:
- Reads
creffrom the URL and keeps it in local storage (openpartner:cref), so it survives single-page-app navigation and later visits. - Optionally mirrors it into a first-party cookie on the brand’s own domain,
op_ref, so the brand’s server can read it too (for example as a Stripe Checkoutclient_reference_id). The script tag turns this cookie on by default (data-cookie="off"turns it off). In@openpartner/sdkit’s off unless you passreferralCookie, whosedaysoption sets its lifetime (default 90).
When the visitor signs up or logs in, the brand’s app calls:
await op.identify(user.id);Without the SDK: the brand’s server reads cref from the signup URL, carries it through
its own signup flow, and calls POST /attribution/identify with { cref, userId } when the
account is created. Nothing is stored in the visitor’s browser on the brand’s side, which also
makes it easy to wait for cookie consent.
Either way, identify does the stitching server-side:
- The cref is matched back to the original
Clickrow, so we know the partner. - An
Identityrow links the userId to the clickId, so every later event from this userId attributes without needing the cref again. - Conversions are reported from the brand’s server or Stripe, not the browser:
POST /attribution/events(or the server SDK’strackEvent) with the same userId, or the Stripe App. See Events. - The program’s attribution model decides who gets credit (last-click usually, but see
Attribution models), and a
Commissionrow is created from the rule.
Why first-party cookies work where third-party don’t
Third-party cookies (a cookie set on openpartner.dev while the user is on acme.com) are
blocked (or, in Firefox, kept in a separate jar for each site) by:
- Safari ITP (default since 2020)
- Firefox Total Cookie Protection (default since 2022)
- Brave (default)
- Chrome in Incognito windows (default), and in normal windows for anyone who turns them off in settings
Chrome still allows them in normal windows by default. Google dropped its plan to phase them out in July 2024, said in April 2025 that it wouldn’t add a new prompt for them either, and in October 2025 retired the Privacy Sandbox APIs that were meant to replace them, such as Topics, Protected Audience and Attribution Reporting.
Chrome’s default doesn’t make them safe to depend on. A platform that still needs a third-party cookie to carry the click from the partner’s link to your site can lose it in any of the browsers above, and the conversions that follow go unattributed.
First-party cookies (set on acme.com itself, by acme.com’s own scripts) aren’t blocked by
any of these. Safari does limit how long storage written by scripts lasts (see below). The
cref query-param-to-first-party-storage hop is what lets attribution survive ITP and the
other protections above.
Cookie lifetime vs. attribution window
These are different things:
- The router’s
_crefcookie is set when the click happens, on the router’s configured cookie domain, and lasts 90 days. A hosted tracking link can’t set a cookie for the brand’s own, unrelated domain, so the clickId reaches the brand’s site through thecrefURL parameter instead. - The SDK’s storage on the brand’s site: local storage, kept until cleared (though Safari
can clear script-written storage after 7 days without a visit), plus the optional
op_refcookie with a lifetime you choose. - The attribution window is the program’s commission policy, set per program from 1 to 365 days (default 60). It’s measured from the click to the conversion. See Attribution window.
Browser storage only has to bridge the gap between the click and identify. Once identify has
linked the userId to the click, nothing in the browser matters any more: later events are
attributed from the Identity row.
The customer’s first attributed conversion has to fall within the attribution window. With “Renewals stay with the partner who earned the customer” on (the default), what follows keeps that attribution after the window closes. A repeat of a conversion type (a renewal invoice, say) keeps the partners that conversion had. A new type of conversion with no click left in the window goes to the partners of the customer’s latest attributed conversion.
What if the user clears cookies?
They lose the cref → the next conversion from them isn’t attributable to that click. Same fate as any cookie-based system.
What we can do (and openpartner does): if the same userId was identified earlier with a
cref, we have an Identity row linking userId ↔ clickId. So if the user signs up on
mobile (cookie present) and then converts on desktop after signing in (cookie absent but
userId known), we still attribute via the Identity table.
This “logged-in stitching” is what lets attribution survive cross-device. See Identity stitching for the detail.
Why not UTMs?
UTMs (utm_source, utm_campaign, etc.) are display-layer marketing tags — they go in the
URL, get logged in analytics, and disappear. They don’t track individual users; they track
campaigns.
For partner attribution, you need a unique-per-click identifier that persists across the session and follows the user to conversion. That’s what cref is. UTMs and cref are complementary, not alternatives — many brands set both.
What if I see double-attribution?
A user clicks Partner A’s link, then Partner B’s link, then converts. Who gets credit? Depends on the campaign’s attribution model:
- Last-click (default) — Partner B
- First-click — Partner A
- Linear — A and B split 50/50
- Position 40/20/40 — A 40%, B 40% (since they’re first and last with no middle)
The cref cookie on the brand’s site holds the last click — but the server has all clicks in the window from the same user (via the Identity table) and computes the model server-side.
Full deep-dive: Attribution models.