ConversionsAPI-Tag-for-GoogleTagManager
ConversionsAPI-Tag-for-GoogleTagManager copied to clipboard
Tag parsing wrong contents array?
We are using a server-side tag setup for GTM where the data is passed to the server as a GA4 Purchase event and then sent along to FB CAPI using this Facebook Incubator tag template.
I've written a custom Javascript variable in GTM to parse a Google Analytics ecommerce "products" array and return it in the format FB CAPI wants for "contents":
As you can see, it takes the price, quantity, and sku for each item and saves them in the correct format. I am explicitly passing this array as "contents":
However, trying to pass the purchase events to the server is failing with code 400 and receives the following response:
"error":{"message":"Invalid parameter","type":"OAuthException","code":100,"error_subcode":2804008,"is_transient":false,"error_user_title":"Invalid Contents Parameter","error_user_msg":"The contents parameter you entered doesn\u2019t contain a list of JSON objects. Enter a list of JSON objects that contain the product IDs associated with the event plus information about the products. For example: [{ 'id' : 'ABC123', 'quantity' : '2', 'item_price' : 5.99}, { 'id' : 'XYZ789' , 'quantity' : 2, 'item_price' : 9.99}]","fbtrace_id":"ASsXl7dWNIzLxh8RdCpOp45"}}
Digging in, it seems like the tag is somehow creating its own "content" array and ignoring the one I'm sending. In the process, it seems to be grabbing the wrong field, using "name" instead of "sku". This is the request body it is sending (some data anonymized):
{"data":[{"event_name":"Purchase","event_time":1656000012,"event_source_url":"https://www.customer.com/order/checkout","action_source":"website","user_data":{"client_ip_address":"111.111.111.111","client_user_agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36","ph":"a1b2c3d4e5f6...abcdef","fbp":"fb.1.1111...1111"},"custom_data":{"currency":"USD","value":7.94,"order_id":"4f719af2-3637-42ee-8e8a-28e8f3783858","contents":[{"title":"Homestyle Huddle Wrap","item_price":7.49,"quantity":1}]}}],"partner_agent":"gtmss-1.0.0-0.0.5"}
Specifically, note the contents array:
"contents" : [
{
"title" : "Homestyle Huddle Wrap",
"item_price" : 7.49,
"quantity" : 1
}
]
This is not what's being passed, and it actually doesn't match any of our objects- we don't use "title" anywhere in our objects, so this object in this format has to be coming from this tag template.
However, that seems to be making it fail, since FB is expecting "id" but getting "title"? In other words, FB's tag seems to be ignoring the provided "contents" array and instead building its own, but FB CAPI seems to be rejecting the "contents" array built by FB's own tag.
Any thoughts on why this is happening and how to fix it? Why isn't the tag using the "contents" array I have already built and am sending to it, and why is the one it appears to be building failing?
event parameter should be "x-fb-cd-contents" rather than "contents" 👍 (also change 'price' to 'item_price' in your custom JS variable) — Kevin O'Connor, Digital Marketing Analyst www.iDimension.com http://www.idimension.com/?utm_id=VwkC +1 (866) 524.3733
On Thu, Jun 23, 2022 at 12:31 PM billboyles @.***> wrote:
We are using a server-side tag setup for GTM where the data is passed to the server as a GA4 Purchase event and then sent along to FB CAPI using this Facebook Incubator tag template.
I've written a custom Javascript variable in GTM to parse a Google Analytics ecommerce "products" array and return it in the format FB CAPI wants for "contents":
[image: image] https://user-images.githubusercontent.com/38093848/175348408-c14f6bf4-f3e4-461c-85c4-369788e19fe1.png
[image: image] https://user-images.githubusercontent.com/38093848/175345596-5fc99162-c084-4412-bd70-bcac52219ea8.png
As you can see, it takes the price, quantity, and sku for each item and saves them in the correct format. I am explicitly passing this array as "contents":
[image: image] https://user-images.githubusercontent.com/38093848/175346312-16a19d99-9991-452a-82f0-3fdfc78a3420.png
However, trying to pass the purchase events to the server is failing with code 400 and receives the following response:
{"error":{"message":"Invalid parameter","type":"OAuthException","code":100,"error_subcode":2804008,"is_transient":false,"error_user_title":"Invalid Contents Parameter","error_user_msg":"The contents parameter you entered doesn\u2019t contain a list of JSON objects. Enter a list of JSON objects that contain the product IDs associated with the event plus information about the products. For example: [{ 'id' : 'ABC123', 'quantity' : '2', 'item_price' : 5.99}, { 'id' : 'XYZ789' , 'quantity' : 2, 'item_price' : 9.99}]","fbtrace_id":"ASsXl7dWNIzLxh8RdCpOp45"}}
Digging in, it seems like the tag is somehow creating its own "content" array and ignoring the one I'm sending. In the process, it seems to be grabbing the wrong field, using "name" instead of "sku". This is the request body it is sending (some data anonymized):
{"data":[{"event_name":"Purchase","event_time":1656000012,"event_source_url":" https://www.customer.com/order/checkout","action_source":"website","user_data":{"client_ip_address":"111.111.111.111","client_user_agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/ 102.0.0.0 Safari/537.36","ph":"a1b2c3d4e5f6...abcdef","fbp":"fb.1.1111...1111"},"custom_data":{"currency":"USD","value":7.94,"order_id":"4f719af2-3637-42ee-8e8a-28e8f3783858","contents":[{"title":"Homestyle Huddle Wrap","item_price":7.49,"quantity":1}]}}],"partner_agent":"gtmss-1.0.0-0.0.5"}
Specifically, note the contents array:
"contents":[ { "title":" Homestyle Huddle Wrap", "item_price":7.49, "quantity":1 } ]
This is not what's being passed, and it actually doesn't match any of our objects- we don't use "title" anywhere in our objects, so this object in this format has to be coming from this tag template.
However, that seems to be making it fail, since FB is expecting "id" but getting "title"? In other words, FB's tag seems to be ignoring the provided "contents" array and instead building its own, but FB CAPI seems to be rejecting the "contents" array built by FB's own tag.
Any thoughts on why this is happening and how to fix it? Why isn't the tag using the "contents" array I have already built and am sending to it, and why is the one it appears to be building failing?
— Reply to this email directly, view it on GitHub https://github.com/facebookincubator/ConversionsAPI-Tag-for-GoogleTagManager/issues/37, or unsubscribe https://github.com/notifications/unsubscribe-auth/AE3LD7GITTZSHNPS2UHFYQDVQSGO7ANCNFSM5ZU7BZCQ . You are receiving this because you are subscribed to this thread.Message ID: <facebookincubator/ConversionsAPI-Tag-for-GoogleTagManager/issues/37@ github.com>
I can definitely change that. However, it was working fine for months earlier this year and last year with this exact setup, That also still does not really explain where "title" is coming from.
This does not appear to have resolved the issue.
This is the GA4 client side tag sent to server:
Note contents array:
{
"name": "x-fb-cd-contents",
"value": [
{
"id": 41263689,
"item_price": 5,
"quantity: 1
}
]
}
Server side FB CAPI tag is sending this:
{"data":[{"event_name":"Purchase","event_time":1656101185,"event_source_url":"https://www.customer.com/order/checkout","action_source":"website","user_data":{"client_ip_address":"111.111.111.111","client_user_agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36","ph":"a1b2c3...d4e5f6","fbp":"fb.1.111111.1111111"},"custom_data":{"currency":"USD","value":5.3,"order_id":"c06952e4-1a61-4d4b-8d75-a8f4763af651","contents":"[object Object]"}}],"partner_agent":"gtmss-1.0.0-0.0.5"}
Note the contents array:
"contents": "[object Object]"
It definitely is an array unless it is being transformed by the FB CAPI tag somehow. It's showing as an object, unless "[Object object]" is a string, and I'm unsure how that would be happening. However, I'm now getting this response from FB CAPI:
{"error":{"message":"Invalid parameter","type":"OAuthException","code":100,"error_subcode":2804019,"is_transient":false,"error_user_title":"Server Side Api Parameter Error","error_user_msg":"The parameter $['data'][0]['custom_data']['contents'] must be an array.","fbtrace_id":"AsrqiGyKVnywuvIsxfBeiqd"}}
The "title" stuff is gone but this just created a new issue. This was all working as recently as a month or two ago, even without renaming the "contents" array to "x-fb-cd-contents" or "price" parameter to "item_price". I'm unclear what's changed.
I could try sending the parameters in the client side GA4 tag as something like:
x-fb-cd-contents.id: 41263689 x-fb-cd-contents.item_price: 5 x-fb-cd-contents.quantity: 1
For other customers using user data for deduplication, I'm basically doing that with user_data- sending each of user_data.first_name, user_data.last_name, user_data.phone, and user_data.email as individual parameters in the client side GA4 tag. But I'm not sure how an array of multiple items could be sent that way, especially when I have no way to predict how many items a customer might be ordering.
Removing the contents array entirely just gets me back to the original issue. It's not required, so I was hoping I could at least get purchase tracking back by sending only "value", "currency", and "order_id". I do this for other customers whose setup does not make detailed purchase information available and it works fine.
Here's an example from another customer that is currently working:
So I took off "x-fb-cd-contents" and tried this instead:
I can't remove the "items" array if I want that data in GA4. But it seems like the FB CAPI tag is grabbing that and trying to convert it to a "contents" array, but we're back to the "title" parameter being put in and not having an "id" parameter.
This gets sent to server:
As you can see, no contents array at all.
But the CAPI tag sends this:
{"data":[{"event_name":"Purchase","event_time":1656103066,"event_source_url":"https://www.customer.com/order/checkout","action_source":"website","user_data":{"client_ip_address":"111.111.111.111","client_user_agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36","ph":"a1b2c3...d4e5f6","fbp":"fb.1.111111.11111111"},"custom_data":{"currency":"USD","value":5.3,"order_id":"93a65b23-9f6c-4fbf-a6b0-6b67c521c3af","contents":[{"title":"Sausage Biscuit Combo","item_price":5,"quantity":1}]}}],"partner_agent":"gtmss-1.0.0-0.0.5"}
Here we are with a "contents" array again, and again it weirdly contains a parameter called "title" that is definitely not coming from any of the data sent from the browser side tags, since as you can see none of those tags contain a "title" parameter for any item, even in "items" array intended for GA4's use.
And we're back to the server replying with:
{"error":{"message":"Invalid parameter","type":"OAuthException","code":100,"error_subcode":2804008,"is_transient":false,"error_user_title":"Invalid Contents Parameter","error_user_msg":"The contents parameter you entered doesn\u2019t contain a list of JSON objects. Enter a list of JSON objects that contain the product IDs associated with the event plus information about the products. For example: [{ 'id' : 'ABC123', 'quantity' : '2', 'item_price' : 5.99}, { 'id' : 'XYZ789' , 'quantity' : 2, 'item_price' : 9.99}]","fbtrace_id":"AVcvazXBTEbLQvodKfR49vk"}}
Why is the FB CAPI tag doing this, and how can I avoid it? I don't see how I can include items for GA4 without FB CAPI doing this. Removing the "items" array from the GA4 request entirely isn't a viable option.
Ultimately, the issue seems to be that the FB CAPI tag is taking this:
"items": [
{
"name": "Sausage Biscuit Combo",
"price": 5,
"quantity": 1,
"sku": 41263689
}
]
and turning it into:
"contents": [
{
"title": "Sausage Biscuit Combo",
"item_price": 5,
"quantity":1
}
]
But it should be turning it into this:
"contents": [
{
"id": 41263689,
"item_price": 5,
"quantity": 1
}
]
or at least this (which would be fine):
"contents": [
{
"id": "Sausage Biscuit Combo",
"item_price": 5,
"quantity": 1
}
]
These issues seem related:
https://github.com/facebookincubator/ConversionsAPI-Tag-for-GoogleTagManager/issues/20
https://github.com/facebookincubator/ConversionsAPI-Tag-for-GoogleTagManager/issues/27
the issue is that your items array doesn't have the item_id field, which GA4 requires BTW. That's what is supposed to get mapped to 'id' in the contents array by this commit back in March 2021: https://github.com/facebookincubator/ConversionsAPI-Tag-for-GoogleTagManager/commit/767618fcbff7f1bac5f62c5c6cfc44384c8bc483
function getContentFromItems(items) {
return items.map(item => {
return {
"id": item.item_id, // <--- this part right here
"title": item.item_name,
"item_price": item.price,
"brand": item.item_brand,
"quantity": item.quantity,
"category": item.item_category,
};
});
}
In this case, "sku" is a carryover from older UA ecommerce, where it was a required field. From the Google side, GA4 definitely doesn't require "item_id". After all, it's working fine without it. So it's actually a bit more complicated than saying "item_id" is required.
Regardless, the FB CAPI tag could (and I would argue, should) be handling the issue a lot more gracefully.
For instance, the CAPI could accept a request without "id"- while the error response lists "id", "item_price", and "quantity" as required fields (and I seem to remember them as listed required fields in the dev documentation back before they did everything with the change to "Meta"), I can't find anything in the current documentation saying any of parameters are required. I see this:
Note that "title" isn't even a listed as an available field (incidentally, neither are "brand" or "category").
However, even if "id" is required (as seems to be the case), "title" is not (as noted above, it doesn't even to seem to be a documented parameter). So it makes sense to prioritize "id". It could look for "id" first, then if not found, it could look for "sku" or "name" and use that as "id" instead, only including "name" if it already has "id".
Barring either of the above, It could simply not send the "contents" array if it can't match required fields, instead of failing out the entire request, since only "currency" and "value" are required. It seems like this is the kind of basic check that good code would make. I'm sure Facebook would rather accept the request in some form and get some data rather than getting nothing and having it fail entirely. This would work fine for my agency, and be preferable to not being able to send purchase requests at all.
Right now, despite GA4 handling the requests fine, the FB requests using the same array are failing. I have no way to send the "items" array as it currently exists to GA4 (which again, handles it fine) without also sending it to FB and having everything fail. The only solution on my end is to stop sending an "items" array to GA4 entirely, or to have my code team rewrite code across a number of websites. Neither are particularly tenable.
🤔 It does look like you're partially correct. Per Facebook pixel events reference https://developers.facebook.com/docs/meta-pixel/reference#object-properties, id is required in the contents array: [image: image.png] that's in the pixel-specific docs rather than the conversions API docs, but it's the same entity receiving the events, Facebook just has bad documentation. The conversions API docs in your screenshot don't explicitly say "required", but it is implied by the definition that ID is required ("list of JSON objects that contain product IDs"): [image: image.png]
I'll grant you, however, that the GA4 e-commerce documentation https://developers.google.com/analytics/devguides/collection/ga4/reference/events#purchase_item does say either item_id or item_name are required, so it would make sense to have the tag fall back to using the SKU or item_name as the id in the contents array if not available. So I see your point and I encourage you to submit a PR for it. [image: image.png]
In the meantime, for your use case, since you're already generating the items array with a custom JS variable why not just add the item_id as a copy of SKU? e.g.: "items": [ { "name": "Sausage Biscuit Combo", "price": 5, "quantity": 1, "sku": 41263689 } ]
becomes: "items": [ { "name": "Sausage Biscuit Combo", "price": 5, "quantity": 1, "sku": 41263689, "item_id": 41263689 } ]
That shouldn't cause any issues in GA4 but would solve your problem without waiting indefinitely for Facebook to merge a PR (I've had once since August 2021, and there are open PRs fixing issues since March 2021 without so much as a comment from FB/Meta... so I wouldn't hold your breath)
Message ID: <facebookincubator/ConversionsAPI-Tag-for-GoogleTagManager/issues/37/1165979578 @github.com>
That's actually not a bad suggestion. Thanks!
Hi, what would be the correct code today to get the correct values?