Meta Conversions
Server-side Meta Conversions API integration. The tracking-meta app sends a Purchase event when an order is confirmed, so conversions are attributed even when the browser Pixel is blocked.
How it works
OnOrderConfirmedobserves orders and, on thenot confirmed → confirmedtransition, schedules the reactor with the order number.meta.purchase.createloads the order, builds the event, and POSTs it tohttps://graph.facebook.com/{apiVersion}/{pixelId}/events.
De-duplication
The server event's event_id is the order number, the same value the browser Pixel sends for its own Purchase. Meta collapses the two into a single conversion, so running both the Pixel and this app does not double-count.
Customer data & privacy
Customer parameters (em, ph, fn, ln, ct, zp, country, external_id) are normalized (lowercased and trimmed) and SHA-256 hashed to lowercase hex per Meta's spec before being sent. external_id is the order's customer number.
fbp, fbc, the client user-agent and the client IP are sent raw, as Meta expects. Any field that is missing is omitted rather than sent empty — that only affects Meta's event match quality, never whether the event is accepted.
Tracking ids
The identifiers come off the order under the shared cart: namespace, having been stamped on the cart by the storefront:
| Meaning | Order field |
|---|---|
Meta browser id (_fbp) | cart:tracking:fbp |
Meta click id (_fbc) | cart:tracking:fbc |
| Client user-agent | cart:client:userAgent |
| Client IP | cart:client:ip |
| Storefront origin | cart:storefrontUrl |
The user-agent, client IP and storefront origin are captured automatically when the cart is created; only fbp and fbc need storefront code. Without them the event still works off the hashed customer data, at lower match quality.
event_source_url is taken from cart:storefrontUrl, falling back to the channel registry's storefrontBaseUrl.
Conversion value
custom_data.value is reported excl. tax, but incl. shipping — the standard for Meta's Purchase event. For tax-inclusive orders the tax is stripped (orderTotal − orderTaxTotal); tax-exclusive totals are already net.
Per-item contents[].item_price stays at the catalog listing price, since those feed product matching rather than bidding optimization.
Different platforms, different values
The Google Analytics app excludes shipping from its conversion value and reports it separately, following GA4's own convention.
Settings
| Setting | Secret | Description |
|---|---|---|
enabled | no | Master switch. When off, the reactor does nothing. |
pixelId | no | Meta Pixel / Dataset ID that receives the events. |
accessToken | yes | Conversions API access token from Events Manager. |
apiVersion | no | Graph API version, e.g. v19.0 (default). |
testEventCode | no | Optional. Routes events to the Test Events view. |
The app is inert until enabled is on and both pixelId and accessToken are set, so installing it has no effect until it is configured.
Verifying
Set testEventCode and place a test order, or schedule the reactor directly for a known order number. The event then appears under Events Manager → Test Events.
See Also
- Conversion Tracking — the app family and shared conventions
- Storefront Integration — capturing
fbpandfbc - Cart Dynamic Fields — how the ids reach the order