Identity · engineers · marketers · PMs
Checkout on another host drops the click id
The landing page wrote _fbp and stored gclid; the hosted cart lives on checkout.shopify.com or pay.example.net. Thank-you fires Purchase as a new person with an empty query string, and the platform calls it view-through or unmatched.
Cookies are host-scoped
A cookie set on www.example.com is not sent to checkout.example.com unless you set Domain=.example.com and the checkout host is actually that parent. A cookie set on example.com is not sent to shopify.com at all. Subdomain vs apex is enough to break _fbp and _ga. The leading dot in Domain=.example.com is the parent-domain form. It still will not cross a different registrable domain.
Consent banners that set cookies on one host and tags that read them on another fail closed. Check document.cookie on the thank-you host, not on the landing host, before you declare the pixel healthy. Chrome's host-only cookies (no Domain attribute) stay on the exact host that set them. That is the default a lot of tags use, and it is why www and checkout disagree.
Click ids have to travel
Put gclid, fbclid, ttclid, msclkid, li_fat_id, and twclid on the URL that leaves for checkout, or stash them in your backend keyed by a first-party session you control. Hosted checkouts that strip unknown query params will drop them unless the integration documents a passthrough. Shopify, Stripe Checkout, and similar have vendor-specific notes. Read those. Do not assume query passthrough.
Persist click ids server-side at landing even if you also decorate the outbound URL. The URL can still be stripped. The server row cannot, unless you keyed it on a cookie that also failed to cross the host. Key it on something you control on both sides: a session id you pass as a path segment the checkout allows, or a logged-in customer id.
GA4 linker is analytics stitching
Google's linker decorates outbound links with _gl so GA4 can stitch client_id across domains. Configure the linker in gtag or GTM with the extra domains. That is analytics stitching. It does not fill fbclid on Meta. It does not fill ttclid. Do the click-id passthrough yourself.
A working _gl and a missing gclid is a common screenshot in QA: GA4 users look continuous, Google Ads conversions do not. The linker is not auto-tagging. Auto-tagging is gclid on the arrival from Google Ads. Your hop to checkout has to keep it.
Prefer the order as the source
When checkout is someone else's origin, fire Purchase from the order webhook with the click ids and cookies you stored at landing. The thank-you pixel can still run for users who stay on your host. Dedup with event_id so pixel plus CAPI is one conversion.
A GTM container loaded on both hosts with no shared storage still fires twice as two users. Shared storage or server events. Not two independent pixels. If the thank-you host is shopify.com, your GTM on example.com never ran there unless you installed it on the checkout too, which many hosted checkouts restrict.
Domain attribute checklist
Landing host, checkout host, collector host (sGTM). If they share a parent, set Domain=.parent.com on the cookies you need, including the session id that keys server-side click ids. If they do not share a parent, you cannot cookie-share. Use the URL, the backend, or the webhook. Those are the only three pipes.
Pixellint is not affiliated with Google or Meta. It will not detect a cross-domain drop. An empty fbp on a CAPI Purchase is valid JSON. Check document.cookie on the thank-you host and the session row at landing. pixellint validate json only sees what you still had the guts to send.
// WRONG: cookie host-only on www, checkout on another host
Set-Cookie: _fbp=fb.1.t.r; Path=/; Max-Age=63072000
// RIGHT when both hosts are under example.com
Set-Cookie: _fbp=fb.1.t.r; Path=/; Domain=.example.com; Max-Age=63072000
// ALSO RIGHT: ignore cookie survival, persist click ids server-side
session.click.gclid = landing.get('gclid');
session.click.fbclid = landing.get('fbclid');
// order webhook reads session.click, sends CAPI / Ads upload
Check the artifact
Paste the pixel URL or JSON body into the
playground. Same engine as
pixellint validate. Nothing leaves the tab.