Conversion Tracking
A family of apps that report conversions to advertising and analytics platforms server-side, from the order rather than from the browser. Each app listens for the same order lifecycle events, maps them to its platform's event format, and sends them from a reactor.
Server-side reporting exists because browser tags are unreliable: ad blockers, tracking prevention, and shoppers who close the tab before the thank-you page all lose conversions. The order actor, by contrast, always knows a purchase happened.
Where a platform de-duplicates on a transaction identifier, these apps send the order number, so a browser tag firing for the same order collapses into one conversion instead of double-counting.
Available tracking apps
- Google Analytics 4 — GA4 Measurement Protocol. Sends
purchaseon order confirmation andrefundas units are returned, attributed via the GA client id captured at the storefront. Reports to several properties per order — a master property plus the channel's own — for multi-site setups. - Meta Conversions — Meta Conversions API. Sends a
Purchaseevent with hashed customer data, de-duplicated against the browser Pixel on the order number. - Awin — Awin server-to-server conversion tracking. Reports a sale when an order is confirmed, attributed via the Awin click value, with per-channel and per-country advertiser resolution.
The tracking-id convention
Every one of these apps needs something the browser knows and the server does not: a cookie value, a click id, a session id. The storefront captures it and puts it on the cart; Commerce carries it onto the order; the tracking app reads it off the order graph.
The shared namespace for this is field:tracking:*, which Commerce projects onto the order as cart:tracking:*:
| Meaning | Source | Cart field | Order field | Used by |
|---|---|---|---|---|
| GA client id | _ga cookie | field:tracking:gaClientId | cart:tracking:gaClientId | Google Analytics |
| GA session id | _ga_<container-id> cookie | field:tracking:gaSessionId:G-XXXXXXXXXX | cart:tracking:gaSessionId:G-XXXXXXXXXX | Google Analytics |
| Meta browser id | _fbp cookie | field:tracking:fbp | cart:tracking:fbp | Meta |
| Meta click id | _fbc cookie / fbclid | field:tracking:fbc | cart:tracking:fbc | Meta |
| Awin click value | awc query parameter | field:tracking:awc | cart:tracking:awc | Awin |
Commerce also captures a small amount of client context automatically when the cart is created, from the request headers — no storefront code required:
| Meaning | Captured from | Cart field | Order field |
|---|---|---|---|
| Client user-agent | User-Agent header | field:client:userAgent | cart:client:userAgent |
| Client IP | Resolved shopper IP | field:client:ip | cart:client:ip |
| Storefront origin | Origin, falling back to Referer | field:storefrontUrl | cart:storefrontUrl |
The client IP is captured at creation rather than completion because a cart is often completed by a PSP callback, whose IP is the payment provider's, not the shopper's.
Adding a new platform needs no Commerce change
The namespace is vendor-neutral. A new tracking app picks a key under field:tracking:, the storefront stamps it, and it arrives on the order — no change to apps.commerce at all.
The GA session id is keyed by measurement id
_ga (the client id) is one cookie for the whole domain, but GA keeps session state in _ga_<container-id> — one cookie per measurement id. A site tagged with several GA properties has several unrelated session ids, so the key carries the measurement id it belongs to. Sending one property's session id to another attributes the event to a session that does not exist there.
Capturing them at the storefront
Reading these values and getting them onto the cart is a storefront concern, and it has real subtleties: the ids are available on the landing page before a cart exists, awc appears only on the first page view, and tag-manager tags usually run before your bundle loads.
→ Conversion Tracking in the Storefront SDK docs covers the capture-and-buffer pattern, a <head> queue stub for Google Tag Manager, and per-platform recipes.
Storefronts not using the SDK write the same fields through the set-field ingress directly:
POST /ingress/commerce/carts/{cartId}/set-field/tracking:gaClientId
{ "value": "1234567890.1712345678" }Why field: and not order:
Commerce projects three prefixes onto the order, and the choice matters here:
field:<key>→cart:<key>— for values that originate at the storefront, i.e. from an untrusted client. The extracart:namespace keeps them clearly separated from app-authored order fields, and they are echoed back in the rendered cart'sfields.order:<key>→<key>— for values an app authored server-side. These land unprefixed in the order's shared dynamic map, so they must be vendor-prefixed to avoid collisions.
Tracking ids come from the browser, so they belong in field:. An app that derives its own attribution data server-side should use order: with a vendor-prefixed key instead.
Reporting the conversion value
The apps deliberately do not agree on what a conversion is worth, because the platforms don't:
| App | Value basis |
|---|---|
| Google Analytics | Goods excl. tax and excl. shipping; tax and shipping sent as their own parameters |
| Meta | Excl. tax, incl. shipping — the standard for the Purchase event |
| Awin | Goods excl. tax and excl. shipping — commissionable value only |
Each app follows its platform's convention rather than a house style, so the numbers line up with what the platform's own reporting expects.
One target or many
The apps also differ in how many destinations a single order reaches:
| App | Destinations per order |
|---|---|
| Google Analytics | Many. Every property configured for the order's channel — typically a master property plus the channel's own |
| Meta | One pixel |
| Awin | One advertiser, resolved country → channel → app default |
The multi-property case is specific to analytics, where a group-level roll-up alongside per-market properties is a standard reporting setup rather than an edge case.
See Also
- Conversion Tracking (Storefront SDK) — capturing and stamping the tracking ids
- Cart Dynamic Fields — the underlying prefix mechanism
- Cart Lifecycle — where
set-fieldfits in the flow