First-party attribution is measurement built only on data your own domain collects and your own server stores: a cookie your server sets, an email or phone a visitor typed into your form, a click ID that arrived in your own landing page URL, an order from your own payment processor.
It survives cookie loss because none of it depends on one website being allowed to read another website’s data. That permission is the thing browsers keep withdrawing. Everything described below sits outside it.
The distinction is not a privacy posture. It is a question about where a value was created and who is allowed to read it — and it decides whether your reporting still works next quarter.
Why does attribution break when cookies disappear?
Because the classic ad-measurement stack rests on a browser behaviour that is no longer the default: a script from one company setting and reading its own cookie on every site that embeds it. That shared cookie is what let an ad platform recognise the same person on the ad and on your checkout page. Remove it and the two events stop being connected.
Several forces removed it, and they are not the same force:
- Third-party cookies are blocked by default in Safari and Firefox. A tracker’s cookie set on someone else’s domain is not stored at all. Nothing about your site changed; the join on the other end vanished.
- Safari’s Intelligent Tracking Prevention (ITP) also shortens the life of cookies written by JavaScript on your own domain. This one surprises people, because those cookies look first-party. They are first-party by domain and third-party by provenance, and the browser judges provenance.
- Ad blockers stop the tracking script from loading at all. Not degraded — absent. Those visitors still browse, still fill in forms, still buy. They produce no client-side events.
- Chrome’s plans have changed more than once. Building measurement on the assumption they settle in your favour is a bet, not a plan.
The symptom is always the same and always misread. Conversions arrive with no source, land in the Direct bucket, and that bucket grows until it is the biggest line in the report. Direct is not a channel. It is the shape of your missing data, which is why ad conversions show as Direct far more often than any media buyer’s instinct allows for.
What counts as first-party data in attribution?
Four categories, and one test for all of them: could a browser vendor take this away without your site changing? If not, it is first-party. A cookie your server sets, an identifier a person typed into your form, a click ID in your own URL, and a record in your own back office all pass. A cookie a third-party script sets on its own domain does not.

Cookies your server sets, not your script
A Set-Cookie header sent by your own server carries different weight than document.cookie written by JavaScript. Same domain, same name, same value — different lifetime, because browsers treat script-written storage as the likelier tracking vector.
It buys the most and costs the least, and almost nobody does it, because the JavaScript version looks fine right up until a returning visitor arrives as a stranger.
Identifiers the person handed you
An email address and a phone number are the most durable identifiers in marketing, because they are not storage. They cannot be cleared, blocked, capped or expired. They are also the only identifiers that cross devices without a guess — which is why tracking leads across devices is a contact-data problem, not a cookie problem.
Normalisation decides whether this works. Ava.Chen@Gmail.com and ava.chen+forms@gmail.com are one mailbox and two different strings; 0412 345 678 and +61412345678 are one phone number. Store what was typed and your joins quietly stop firing.
Click IDs that arrived in your own URL
When someone clicks an ad, the platform appends an identifier to the destination URL: fbclid for Meta, gclid, gbraid and wbraid for Google, msclkid for Microsoft, ttclid for TikTok, epik for Pinterest. By the time that URL reaches your server, the ID is yours. No blocker can strip a query parameter out of a request that already arrived.
The mistake is reading it only in the browser: a blocked script never sees it, and a redirect that drops the query string destroys it. Capture it server-side on the first request.
Records from your own systems
The order in Shopify, the payment in Stripe, the appointment in your booking tool. This data was never in a browser and was never at risk — and it is the only place the actual revenue lives, which makes it the anchor everything else gets matched back to.
Is a first-party cookie the same as first-party attribution?
No, and conflating them is the expensive mistake here. A first-party cookie is one storage mechanism on one device in one browser. First-party attribution is a system that keeps working when that cookie is gone — because it holds other identifiers, and because the joining happens on a server you control rather than in a browser you do not.
A vendor can hand you a first-party cookie and still give you third-party-shaped fragility: written by their script, ITP caps it; blocked, it never exists; on a second device, it cannot follow.
The useful mental model is provenance, not location. Ask where the value was created, not what domain it sits on. Script-created is fragile regardless of domain. Server-created is durable. Person-supplied is the most durable of all, and the only kind that crosses devices.
How do you get first-party data to the ad platform?
Through a server-side conversions endpoint. Every major platform accepts conversion events posted directly from your server with hashed customer information attached, instead of waiting for a browser pixel. Meta’s is the Conversions API; Google, Microsoft, TikTok and Pinterest each have their own version.
The mechanics matter more than the concept. You hash the identifiers you hold — email lowercased and trimmed, phone in E.164 digits-only form — and send them with the event, per the Conversions API parameter spec. The platform hashes its own user records the same way and looks for a match. The platform’s own cookies, plus the visitor’s IP address and user agent, are sent unhashed because the platform needs them raw.
How many of those fields you can fill is what the platform scores as event match quality, and it is arithmetic rather than magic: hashed email is Meta’s highest-weight parameter, hashed phone is second, and a payload carrying both plus the platform cookies, IP and user agent reaches a band an email-only payload structurally cannot.
Two honest limits travel with this. Server-side dispatch does not replace your client-side base tag — the platform’s own cookie is captured in the browser, and without it your server events arrive anonymous and match worse. And you control what gets sent; the platform controls whether it matches. Consent, opt-outs and their identity graph are all on their side of the line.
What can you build yourself without buying anything?
More than most vendors admit. Five things, each with the limit that comes with it:
- Set your visitor cookie from your server. A
Set-Cookieheader from your own domain, with a long expiry. Biggest single improvement available, and it does nothing for cross-device. - Capture click IDs server-side from the landing request. Store
fbclid,gclid,gbraid,wbraid,msclkid,ttclidandepikbefore any redirect can eat them. Needs a server-rendered landing page or an edge handler. - Normalise email and phone before you store or hash them. Lowercase, trim, strip Gmail dots and
+suffixes, convert phones to E.164. Cheap and permanent — and it only helps for people who submitted something. - Post conversions to the platform APIs from your backend. Well documented and entirely doable, and a real engineering commitment once you account for retries, deduplication and per-platform payload rules.
- Deduplicate your CRM on normalised email and phone. Worth doing regardless of anything else here.
The ceiling is the same for all five, and it is not technical. Every one of them starts working at submit time. A visitor who typed their email and then closed the tab has handed you a first-party identifier — and if nothing captured the field before the page unloaded, it is gone. Someone in that state is a partial lead: identified in fact, invisible in your data. No amount of server-side plumbing downstream conjures an identifier that was never captured upstream.
How does PartialLeads do first-party attribution?
Every layer of PartialLeads is first-party by construction, because it was built after the cookie era rather than retrofitted into it.
Capture. One script tag, roughly 10KB gzipped, no tag manager required. It captures email and phone on input and blur with a short debounce, and flushes any pending field on submit, pagehide or visibilitychange — so the last thing typed before a tab closes is not lost. It reads UTMs from the URL, falls back to the referrer when an iframe embed has stripped them, and relays campaign data across frame boundaries for GoHighLevel, Typeform and Jotform embeds. Every click ID listed above is captured, and when the Meta _fbc cookie is missing or malformed the backend reconstructs it from the fbclid in the URL. It does not synthesise _fbp out of nothing — nobody can.
Identity. The visitor ID is set by the server as a first-party cookie, with local storage as a backup, precisely so Safari’s cap on script-written cookies does not quietly delete your returning visitors. A six-tier cluster resolver then unions a person’s sessions across visitor ID, email, phone, IP plus user agent, a bounded device fingerprint, and a shared click ID — with strong tiers outranking weak ones rather than averaging with them.
Revenue. Orders arrive from Shopify, WooCommerce, Stripe, GoHighLevel or a universal webhook and match back to a session on a ranked ladder — echoed visitor ID, then email, then phone, then IP — writing both a first-touch and a last-touch row that snapshot campaign parameters, click IDs, referrer and landing page as they stood. Refunds get their own row and net against revenue. Purchases that match nothing still land, recoverable when identity arrives later.
Dispatch. Conversions fire server-side to Meta, Google Ads, Pinterest, TikTok and Microsoft, with a deterministic event_id derived from the pixel, event name and record, and uniqueness enforced in the dedup tables — so a redelivered webhook physically cannot double-count. With email and phone as required form fields, PartialLeads consistently delivers EMQ 9+ — observed across customer accounts. Email-only forms cap structurally lower, because you cannot transmit a match parameter you never collected. Requiring a phone field costs some conversion rate; partial capture softens that trade, because a visitor who types a phone number and then abandons still produces a full-PII event.

Proof. The Attribution report shows first-touch, last-touch and a resolved model side by side, each with its own purchase count, so you see the models disagree instead of being handed one number. Underneath it, Recovered Attribution itemises what a raw last-click view loses, by mechanism: ad clicks re-linked to a first touch, sessions with no utm_source that the classifier resolved to a real channel, and revenue from buyers whose session never finished a form. The Leads list renders each person’s touches as a chain of badges — a grey dot where the source is genuinely unknown, a green square for the conversion — so a journey reads without opening the record.
| What breaks | The mechanism | Where you see it in the dashboard |
|---|---|---|
| Third-party cookie blocked, ad click and sale never join | First-party identifiers only, joined server-side | Attribution report, resolved model |
| Safari shortens a script-written cookie’s life | Visitor cookie set by the server, not the script | Returning visitors stay stitched on the Journey |
| Ad blocker stops the pixel from firing | Server-side conversion dispatch to five platforms | CAPI activity log, delivery rate |
| Click ID lost to a blocked or malformed cookie | _fbc reconstructed from the fbclid in the URL |
CAPI activity log payloads |
| Conversion arrives with no source, lands in Direct | Session classifier plus visit-sibling inheritance | Recovered attribution, reclassified sessions |
| Ad clicked on a phone, purchase made on a desktop | Email, phone and payment-customer joins across devices | Journey timeline, conversion paths |
| Purchase in Shopify or Stripe has no click attached | Ranked purchase-to-session match ladder | Purchases ledger, matched vs unmatched |
| Form fields typed but never submitted | Field capture on input with a terminal flush | Leads list, Partial badges |
| Platform cannot match the conversion to a person | Full hashed identifier set sent server-side | Event match quality in Events Manager |
| Retried webhook fires the same conversion twice | Deterministic event_id plus unique dedup tables |
CAPI activity log |
One constraint, stated plainly, because it separates honest measurement from a sales pitch. First-party attribution guarantees delivery, not matching. Purchases fire from a server-side webhook, so every order in your back office produces a conversion event regardless of what the browser did — reconcile it yourself by comparing your order count to dispatched events. Whether the platform then ties that event to a user and a click depends on identifiers, consent and their own graph. We control the dispatch. They control the match. Nobody controls both.
Tell us what's broken. We'll fix your tracking — free.
Describe the tracking/attribution problem you're stuck on and we'll map it to a fix: server-side conversions to Meta, Google, TikTok and Pinterest, plus first-party tracking that survives Safari. No code required.
Sources
- Meta for Developers — Conversions API overview: https://developers.facebook.com/docs/marketing-api/conversions-api
- Meta for Developers — Conversions API, customer information parameters: https://developers.facebook.com/docs/marketing-api/conversions-api/parameters/customer-information-parameters
- Meta for Developers — Conversions API, server event parameters: https://developers.facebook.com/docs/marketing-api/conversions-api/parameters/server-event
- Meta for Developers — Deduplicate Pixel and Conversions API events: https://developers.facebook.com/docs/marketing-api/conversions-api/deduplicate-pixel-and-server-events