pixellint

Pixels · marketers · PMs · engineers

Purchase does not belong on the landing page

The landing page is where click ids land and where you write first-party cookies. The thank-you page is where money or a lead is real. Mixing the two is the most expensive GTM mistake in this library. Hosted checkout makes the mix-up a cross-domain problem.

Landing: store click ids, fire PageView

Capture fbclid, gclid, ttclid into cookies on the first hit. Fire PageView or page_view. Do not fire Lead just because the form exists on the page. Do not fire Purchase because the product is on the page. Do not fire AddToCart on DOM Ready of a PDP; fire it when the cart actually changes.

This is also where _fbp and _ga get written. If you delay the pixel until the thank-you page, you never stamp the click id from the landing URL, because that URL is gone. A thank-you-only Meta pixel is a conversion without a click join unless CAPI supplies fbc you stored server-side. Store on landing even if you convert later.

Thank-you: fire the conversion once

Fire the conversion once, with value and currency if it is a sale. Meta Purchase needs cd[value] and cd[currency] as ISO 4217 on facebook.com/tr. Google Ads needs conversion_id in the path and a label so the hit lands on the conversion action; guid=ON and script=0 on the image fallback. Use a trigger that cannot match the landing URL. Thank-you?order= is better than a regex that also matches /checkout.

If thank-you is a modal on the same URL, you do not have a page trigger. You need a dataLayer event from the app when the order id is real. If the user can refresh /thank-you, gate on order id in sessionStorage or on the server, or you reprint Purchase on every reload. Derive event_id from the order id so CAPI and the pixel collapse.

Hosted checkout is another host

Shopify checkout, Stripe Checkout, PayPal, and some booking tools send the user to a domain you do not control, then back. Click ids and _fbp live on your landing host. The hosted thank-you page cannot read them. The conversion either fires there as a new user with no click id, or it never fires because you only tagged your domain.

Fixes: Shopify customer events / additional scripts that run on thank-you and a server event from the order webhook; Stripe success URL back on your domain plus a webhook CAPI call; cookie domain and redirect map if checkout is a subdomain you do own (checkout.example.com) with Domain=.example.com. View-through in the ads manager is not a substitute for a lost gclid.

Where the click id sits versus where Purchase fires

Click id storage is a landing-page job. Purchase is a thank-you job. The join is the cookie or the server record you wrote in between. If the landing page is ads.example.com and thank-you is shop.example.com, you need cross-subdomain cookies or a backend that saw both. If thank-you is a different site entirely, you need the webhook.

A GTM container that fires PageView and Purchase on All Pages will train Meta on landings. ROAS looks heroic for a week. Then the model discounts you, or finance notices units sold. Split the triggers. QA with a real click id in the landing URL and a real order id on thank-you, and confirm the conversion request still carries fbc or gclid.

SPA and checkout-as-a-route

If checkout is /checkout and thank-you is /checkout/complete without a document load, PageView-on-load never sees the conversion route. History Change or a router callback must fire Purchase there, and must not fire it on /checkout. Strict Mode and double dataLayer pushes are how you get two Purchases for one order. Guard on order id.

Do not fire Purchase when the route is /checkout?success=1 if that query is also used for a failed 3-D Secure return. Read the order status from the API. Pixels that trust the URL are how declined cards become conversions. The server already knows; CAPI can fire from that knowledge even if the SPA never reaches a clean thank-you.

Check the artifact

Paste the pixel URL or JSON body into the playground. Same engine as pixellint validate. Nothing leaves the tab.