Meta Pixel Missing Value or Currency? Fix Purchase Parameters

Quick fix: Send Purchase as fbq('track', 'Purchase', { value: 49.99, currency: 'USD' }); where value is a plain number (no currency symbol, no thousands separator, not in cents) and currency is a three-letter ISO 4217 code. Then check the real request in DevTools to make sure your template actually filled both in.
Warnings about a missing or invalid value or currency usually appear on Purchase, but you'll see related problems on AddToCart, InitiateCheckout and other commerce events too. They matter because Meta can't report revenue or return on ad spend, and can't use value-based optimization, without a usable value and currency.
The fix is almost always in how your site builds the event data, not in Meta's settings. This guide shows the correct format, then walks through the ways sites get it wrong.
What Meta requires
Meta's pixel reference lists Purchase as the only standard event where value and currency are required. For events such as AddToCart, AddPaymentInfo, InitiateCheckout, Lead, ViewContent and Subscribe they are optional. On the server side, the Conversions API custom data reference says value is required for purchase events or any events that use value optimization, and that currency must be a valid ISO 4217 code.
| Parameter | Type | Correct example | Wrong examples |
|---|---|---|---|
value | Number (integer or float) | 49.99 | '$49.99', '49,99', '1,049.00', undefined |
currency | String, ISO 4217 code | 'USD', 'EUR', 'GBP' | '$', 'US Dollar', '' |
Use the uppercase three-letter code, which is how ISO 4217 codes are written and how Meta's own examples show them.
Correct examples
A Purchase event with value, currency and product data:
fbq('track', 'Purchase', {
value: 84.50,
currency: 'USD',
content_type: 'product',
contents: [
{ id: 'SKU-1001', quantity: 1 },
{ id: 'SKU-2040', quantity: 2 }
]
});
An AddToCart event. Value and currency are optional here, but include them if you want value reporting or value-based optimization:
fbq('track', 'AddToCart', {
value: 24.00,
currency: 'EUR',
content_type: 'product',
contents: [{ id: 'SKU-2040', quantity: 1 }]
});
Each object in contents needs an id and a quantity. If you run Advantage+ catalog ads, Meta's reference says AddToCart requires contents, and Purchase requires contents or content_ids, so add them even if the value warning is your only current problem.
The Conversions API equivalent puts the same fields in custom_data:
"custom_data": {
"value": 84.50,
"currency": "USD",
"content_type": "product",
"contents": [
{ "id": "SKU-1001", "quantity": 1 },
{ "id": "SKU-2040", "quantity": 2 }
]
}
Why the warning appears, most likely first
1. The template variable is empty on the live page
Most Purchase code is generated from a template: a platform snippet, a theme file, or a GTM tag that reads a dataLayer variable. If the variable is empty at the moment the pixel fires, the event goes out with value: undefined or no value at all.
Check: in DevTools, open the Network tab, filter by facebook.com/tr, and click the Purchase request. Event parameters appear in the query string or payload as cd[value] and cd[currency]. If they're missing or empty, the problem is on your side.
Common causes:
- A GTM variable points to the wrong dataLayer path, for example
valueinstead ofecommerce.value. - The tag fires on page load, before the dataLayer push that contains the order data.
- A theme or page builder outputs the code on a page where the order object isn't available.
Fix: fire the tag on the dataLayer event that carries the order data, not on a generic page view, and point variables to the exact path. Our guide to GTM Preview mode helps if you can't inspect variables.
2. The value is a formatted price string
Templates often output a price already formatted for display: $1,049.00, 49,99 €, or USD 49.99. That's fine for a customer but not for an event parameter.
Fix: output the raw numeric amount from your backend or ecommerce platform rather than the display string. If you can't, convert it before sending:
function toNumber(price) {
// Handles '1,049.00' style formatting. Adjust for locales
// that use a comma as the decimal separator.
var cleaned = String(price).replace(/[^0-9.\-]/g, '');
var n = parseFloat(cleaned);
return isNaN(n) ? null : n;
}
var orderValue = toNumber(rawTotal);
if (orderValue !== null) {
fbq('track', 'Purchase', { value: orderValue, currency: 'USD' });
}
Parsing display strings is fragile. A store in a locale that writes 1.049,00 will be parsed incorrectly by the function above. A raw numeric field from your platform is always safer.
3. The value is in minor units (cents)
Some APIs store amounts as integers in the smallest unit, so 49.99 becomes 4999. Meta won't warn about this because it's a valid number, but revenue in your reports will be off by a factor of 100. Divide by 100 (or by the correct factor for the currency) before sending.
4. Currency is a symbol, a name, or missing
A currency of '$' is ambiguous across many currencies. Use the code. Multi-currency stores should send the currency the customer actually paid in, together with the value in that currency, rather than hard-coding the store's base currency.
5. The event is fired twice, and one copy is empty
When two installations send Purchase, often only one has the order data. The empty copy is the one triggering the warning. Remove the duplicate installation as described in Meta Pixel duplicate events.
6. The server event is missing fields the browser event has
If you send Purchase through both channels, check the Conversions API payload too. A browser event can be perfect while the server event omits currency. Your server logs show what was sent. Deduplicated pairs should carry the same value and currency on both sides; see Pixel and Conversions API deduplication.
7. The value is captured at the wrong moment
This one doesn't usually trigger a warning, but it produces wrong revenue. If your code reads the cart total early, for example on the checkout page, and reuses it for Purchase, the value may not reflect discount codes, shipping changes or items removed at the last step. Read the value from the completed order, not from the cart.
A reliable pattern for Google Tag Manager
If you send Meta events through GTM, the cleanest setup is to have your site push the order data to the dataLayer once, with plain numbers and codes, and let the tag read it. A push on the confirmation page might look like this:
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
event: 'purchase',
ecommerce: {
transaction_id: '10482',
value: 84.50,
currency: 'USD'
}
});
Then, in GTM, create Data Layer Variables for ecommerce.value and ecommerce.currency, and fire your Meta Purchase tag on a Custom Event trigger matching purchase. Because the tag fires on the same event that carries the data, the variables are always populated when it runs. The transaction ID is also available to use as the event ID for deduplication.
Avoid building the value inside the tag with string concatenation or Custom JavaScript that reads text from the page. Page text changes with redesigns and translations, and the event breaks quietly when it does.
How to verify the fix
- Place a real or test order and inspect the Purchase request in DevTools. Confirm
cd[value]is a plain number andcd[currency]is a three-letter code. - Open the Test Events tab in Events Manager, repeat the order, and expand the Purchase event to check the received parameters.
- For server events, check the request body in your logs and confirm a
2xxresponse. - Give it a few days, then check the Diagnostics tab for your pixel. Warnings about past events can take time to clear once new events arrive correctly.
FAQ
Should value include tax and shipping?
Meta describes value as the value of the event to your business, and doesn't prescribe a formula. Choose one definition, such as order subtotal or total paid, and use it consistently on both browser and server events so your reports are comparable.
Can value be sent as a string like "49.99"?
Meta's pixel reference lists the type as integer or float. Send a JavaScript number, not a string, to avoid ambiguity.
Do I need value on AddToCart?
It isn't required, but Meta's Conversions API docs say value is needed for any event that uses value optimization. Including it also gives you more useful reports.
What if the value is zero, for a free order?
A zero value is a valid number. Send value: 0 with the currency, rather than leaving value out.
