Skip to content

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 purchase on order confirmation and refund as 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 Purchase event 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:*:

MeaningSourceCart fieldOrder fieldUsed by
GA client id_ga cookiefield:tracking:gaClientIdcart:tracking:gaClientIdGoogle Analytics
GA session id_ga_<container-id> cookiefield:tracking:gaSessionId:G-XXXXXXXXXXcart:tracking:gaSessionId:G-XXXXXXXXXXGoogle Analytics
Meta browser id_fbp cookiefield:tracking:fbpcart:tracking:fbpMeta
Meta click id_fbc cookie / fbclidfield:tracking:fbccart:tracking:fbcMeta
Awin click valueawc query parameterfield:tracking:awccart:tracking:awcAwin

Commerce also captures a small amount of client context automatically when the cart is created, from the request headers — no storefront code required:

MeaningCaptured fromCart fieldOrder field
Client user-agentUser-Agent headerfield:client:userAgentcart:client:userAgent
Client IPResolved shopper IPfield:client:ipcart:client:ip
Storefront originOrigin, falling back to Refererfield:storefrontUrlcart: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:

bash
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 extra cart: namespace keeps them clearly separated from app-authored order fields, and they are echoed back in the rendered cart's fields.
  • 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:

AppValue basis
Google AnalyticsGoods excl. tax and excl. shipping; tax and shipping sent as their own parameters
MetaExcl. tax, incl. shipping — the standard for the Purchase event
AwinGoods 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:

AppDestinations per order
Google AnalyticsMany. Every property configured for the order's channel — typically a master property plus the channel's own
MetaOne pixel
AwinOne 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

© 2026 Hantera AB. All rights reserved.