Webclat / Signals
Signals  /  QA  /  CAPI-07

How do I map GA4-style item/product arrays into the Meta Conversions API purchase payload?

Answer in brief

Meta's CAPI Purchase event expects product-level detail inside custom_data.contents (each entry using id, quantity, and item_price), plus a separate content_ids array and a contents_type flag - not GA4's items array shape (item_id, item_name, price, quantity) passed through unchanged. The two schemas model the same purchase but use different key names and a different nesting structure, so a field-by-field remap is required.

Why this happens

GA4's ecommerce schema and Meta's CAPI schema were designed independently for two different reporting systems. Both model "a purchase has a list of products," but neither the field names nor the array nesting line up. A team that already collects GA4-shaped item data naturally wants to reuse that same array for CAPI rather than maintaining a second parallel structure.

Passing GA4's items array directly into Meta's contents field fails quietly: Meta ignores fields it does not recognize rather than erroring, so the purchase event still sends successfully with content_ids empty or missing. The top-level value and currency fields, which do overlap in meaning, still report correctly - which is exactly why the missing product-level detail is easy to miss until dynamic-ads catalog matching turns out not to work.

Fix it

  1. Keep GA4's items array as the source of truth if that is where product data already lives - do not restructure GA4 tracking to accommodate Meta.
  2. At the point the CAPI payload is built (client-side before sending, or in server-side GTM if that is where the call is assembled), map each GA4 item to a Meta contents entry: item_id to id, quantity to quantity, price to item_price.
  3. Populate content_ids as a flat array of just the product IDs pulled from the same items array - Meta requires this as a sibling field to contents, not something it derives automatically from it.
  4. Set contents_type to product (or the catalog content type your Meta catalog uses) so Meta knows how to interpret content_ids against your Product Catalog for dynamic-ad matching.
  5. Set the top-level value field to the full order total, not a per-item sum, in the same currency-scale convention (major units, for example 49.99 rather than cents) Meta's Purchase event expects, and currency as the ISO 4217 code.
  6. In server-side GTM, do this mapping inside a Custom JavaScript Variable that transforms the incoming items array, referenced by the CAPI tag's Contents field, rather than hand-writing the transform once per tag, so it stays maintainable if the item schema changes upstream.

How to verify it worked

  • Send a test purchase and inspect the event payload Meta received, via the Test Events tool's event detail view, for a populated contents array with correct id, quantity, and item_price per line item, and a non-empty content_ids array.
  • In Meta's Catalog Manager, if using dynamic ads, confirm the product IDs in content_ids match IDs that actually exist in the connected Product Catalog - a mapping that sends the wrong ID field (for example a GA4 SKU instead of the catalog's product ID) will pass CAPI validation but fail to match any catalog item.
  • Cross-check the top-level value reported for the test purchase against the actual order total in your own system - a mismatch usually means the value was summed from item_price fields with a rounding or currency-scale error rather than taken from the authoritative order total.

Want This Checked On Your Own Setup?

Send us the platform and the symptom and we will tell you whether this is the fix, or whether something else in your pipeline is masquerading as it.

Talk To The Practice