pixellint

vendor/meta-conversions-api · vendor documented

Meta Conversions API wants seconds, not Date.now()

A Purchase posts to the Graph API events edge and returns 200. Events Manager stays empty. The usual suspect is the access token. The usual bug is the clock.

event_time is a Unix timestamp in seconds, ten digits, and at most seven days old when it arrives. Date.now() is milliseconds. The event lands far in the future, outside the window, and never attributes.

event_time is seconds, not milliseconds

Send Math.floor(Date.now() / 1000). The same Date.now() is the correct unit on LinkedIn and Amplitude. Copying a payload between vendors without converting the clock is a silent miss on one of them.

Rule: vendor.meta-conversions-api.body.event_time.invalid

Hash the email. Do not hash the IP.

em, ph, name, city, and the rest of the customer information parameters are SHA-256 hex digests. client_ip_address and client_user_agent are sent in the clear. Hashing those two makes the event unmatchable.

Rule: vendor.meta-conversions-api.body.hashed_plaintext_field

Purchase needs value and currency

A payload that only names the product is a legal JSON object and an incomplete conversion. Currency is an ISO 4217 code (USD), not a dollar sign.

Rule: vendor.meta-conversions-api.body.purchase_requires_value_and_currency

What this pack matches

Hosts
graph.facebook.com
Paths
…/events…
Vendor docs
developers.facebook.com/docs/marketing-api/conversions-api/using-the-api

Rules

Codes are stable. A finding in CI, MCP, or the playground lands on the same id.

Field Required What it checks Rule ids Source
access_token required The events edge authenticates with an access token on the request. Fix: Send a system user access token, and keep it server-side. vendor.meta-conversions-api.param.access_token.missing
vendor.meta-conversions-api.param.access_token.empty
docs
test_event_code optional It routes events to the Events Manager test tool instead of production reporting, so it should not appear on live traffic. Fix: Drop `test_event_code` outside of testing. vendor.meta-conversions-api.param.test_event_code.empty docs
pii.unhashed_email required A query parameter carries what looks like a raw email address. Conversions API customer information must be normalized and SHA-256 hashed. Fix: Hash the value with SHA-256 and send it in the event payload rather than on the URL. vendor.meta-conversions-api.pii.unhashed_email docs
testing.test_event_code_present recommended The request carries `test_event_code`, which routes events to the Events Manager test tool instead of production reporting. Fix: Drop `test_event_code` before this runs against live traffic. vendor.meta-conversions-api.testing.test_event_code_present docs
event_name required It is the standard or custom event name, and it has to match the browser event for deduplication to work. Fix: Set `event_name` to the standard event, such as `Purchase`, or to your custom event name. vendor.meta-conversions-api.body.event_name.missing
vendor.meta-conversions-api.body.event_name.empty
docs
event_time required Meta documents it as a Unix timestamp in seconds, and it can be up to 7 days before the event is sent. A 13-digit value is milliseconds and lands far in the future. Fix: Send seconds, not milliseconds: divide a JavaScript `Date.now()` by 1000 and floor it. vendor.meta-conversions-api.body.event_time.missing
vendor.meta-conversions-api.body.event_time.empty
vendor.meta-conversions-api.body.event_time.invalid
docs
action_source required It tells Meta where the conversion happened, and Meta accepts a fixed set of values. Fix: Use one of the documented values; website conversions are `website`. vendor.meta-conversions-api.body.action_source.missing
vendor.meta-conversions-api.body.action_source.empty
vendor.meta-conversions-api.body.action_source.invalid
docs
user_data required Customer information is required on every server event, and it is what Meta matches the conversion to a person with. Fix: Add a `user_data` object with at least one normalized, hashed identifier. vendor.meta-conversions-api.body.user_data.missing docs
event_id recommended Meta recommends it for deduplication: the browser pixel and the server event have to carry the same `event_id` and `event_name` to be counted once. Fix: Generate one id per conversion and send the same value from the pixel and the Conversions API. vendor.meta-conversions-api.body.event_id.missing
vendor.meta-conversions-api.body.event_id.empty
docs
event_source_url optional It is the page URL where the conversion happened, and Meta requires it for website events. Fix: Send the full URL of the page, including the scheme. vendor.meta-conversions-api.body.event_source_url.empty
vendor.meta-conversions-api.body.event_source_url.invalid
docs
opt_out optional When true, the event is used for attribution only and not for ads delivery optimization. docs
data_processing_options[] optional Meta accepts `LDU` for Limited Data Use, or an empty array. Fix: Send `["LDU"]` to enable Limited Data Use, or `[]` to leave it off. vendor.meta-conversions-api.body.data_processing_options[].empty
vendor.meta-conversions-api.body.data_processing_options[].invalid
docs
data_processing_options_country optional It is 1 for the United States, or 0 to let Meta geolocate. vendor.meta-conversions-api.body.data_processing_options_country.empty
vendor.meta-conversions-api.body.data_processing_options_country.invalid
docs
data_processing_options_state optional It is 1000 for California, or 0 to let Meta geolocate. vendor.meta-conversions-api.body.data_processing_options_state.empty
vendor.meta-conversions-api.body.data_processing_options_state.invalid
docs
custom_data.value optional Meta requires it for purchase events and for any event that uses value optimization. Fix: Send the monetary value as a number, without a currency symbol. docs
custom_data.currency optional Meta requires a valid ISO 4217 three-digit currency code. Fix: Use the three-letter code, such as `USD`. vendor.meta-conversions-api.body.custom_data.currency.empty
vendor.meta-conversions-api.body.custom_data.currency.invalid
docs
user_data.em optional Email must be trimmed, lowercased, and SHA-256 hashed before it is sent. Fix: Normalize the address, hash it with SHA-256, and send the hex digest. vendor.meta-conversions-api.body.user_data.em.empty
vendor.meta-conversions-api.body.user_data.em.invalid
docs
user_data.em[] optional Every email in the list must be normalized and SHA-256 hashed. Fix: Normalize each address, hash it with SHA-256, and send the hex digests. vendor.meta-conversions-api.body.user_data.em[].empty
vendor.meta-conversions-api.body.user_data.em[].invalid
docs
user_data.ph optional Phone numbers must have symbols and letters removed, carry the country code, and be SHA-256 hashed. Fix: Normalize the number to digits with the country code, hash it with SHA-256, and send the hex digest. vendor.meta-conversions-api.body.user_data.ph.empty
vendor.meta-conversions-api.body.user_data.ph.invalid
docs
user_data.ph[] optional Every phone number in the list must be normalized and SHA-256 hashed. Fix: Normalize each number to digits with the country code and hash it with SHA-256. vendor.meta-conversions-api.body.user_data.ph[].empty
vendor.meta-conversions-api.body.user_data.ph[].invalid
docs
user_data.fn optional First name must be lowercased and SHA-256 hashed. vendor.meta-conversions-api.body.user_data.fn.empty
vendor.meta-conversions-api.body.user_data.fn.invalid
docs
user_data.ln optional Last name must be lowercased and SHA-256 hashed. vendor.meta-conversions-api.body.user_data.ln.empty
vendor.meta-conversions-api.body.user_data.ln.invalid
docs
user_data.ge optional Gender is sent as a lowercase initial and SHA-256 hashed. vendor.meta-conversions-api.body.user_data.ge.empty
vendor.meta-conversions-api.body.user_data.ge.invalid
docs
user_data.db optional Date of birth is normalized to YYYYMMDD and SHA-256 hashed. vendor.meta-conversions-api.body.user_data.db.empty
vendor.meta-conversions-api.body.user_data.db.invalid
docs
user_data.ct optional City is lowercased with punctuation and spaces removed, then SHA-256 hashed. vendor.meta-conversions-api.body.user_data.ct.empty
vendor.meta-conversions-api.body.user_data.ct.invalid
docs
user_data.st optional State is the lowercase two-character code, SHA-256 hashed. vendor.meta-conversions-api.body.user_data.st.empty
vendor.meta-conversions-api.body.user_data.st.invalid
docs
user_data.zp optional Zip is lowercased without spaces or dashes, then SHA-256 hashed. vendor.meta-conversions-api.body.user_data.zp.empty
vendor.meta-conversions-api.body.user_data.zp.invalid
docs
user_data.country optional Country is the lowercase ISO 3166-1 alpha-2 code, SHA-256 hashed. Fix: Hash the two-letter code rather than sending it in the clear. vendor.meta-conversions-api.body.user_data.country.empty
vendor.meta-conversions-api.body.user_data.country.invalid
docs
user_data.external_id optional Meta recommends hashing the advertiser's own identifier with SHA-256. vendor.meta-conversions-api.body.user_data.external_id.empty
vendor.meta-conversions-api.body.user_data.external_id.invalid
docs
user_data.client_ip_address optional It is sent unhashed, and it must be the real IPv4 or IPv6 address of the browser. Fix: Send the client address as-is; do not hash it and do not send your server's address. vendor.meta-conversions-api.body.user_data.client_ip_address.empty docs
user_data.client_user_agent optional It is sent unhashed, and it must be the browser's user agent rather than your HTTP client's. Fix: Forward the browser `User-Agent` header from the original request. vendor.meta-conversions-api.body.user_data.client_user_agent.empty docs
user_data.fbc optional Meta documents the click id cookie as `fb.${subdomain_index}.${creation_time}.${fbclid}`. Fix: Send the `_fbc` cookie verbatim, or rebuild it in the documented format. vendor.meta-conversions-api.body.user_data.fbc.empty
vendor.meta-conversions-api.body.user_data.fbc.invalid
docs
user_data.fbp optional Meta documents the browser id cookie as `fb.${subdomain_index}.${creation_time}.${random_number}`. Fix: Send the `_fbp` cookie verbatim. vendor.meta-conversions-api.body.user_data.fbp.empty
vendor.meta-conversions-api.body.user_data.fbp.invalid
docs
user_data.lead_id optional It is the numeric id Meta generated for a Lead Ads lead. vendor.meta-conversions-api.body.user_data.lead_id.empty
vendor.meta-conversions-api.body.user_data.lead_id.invalid
docs
body.purchase_requires_value_and_currency required A `Purchase` event is missing `custom_data.value` or `custom_data.currency`. Meta documents both as required for purchase events. Fix: Add `custom_data.value` as a number and `custom_data.currency` as an ISO 4217 code. vendor.meta-conversions-api.body.purchase_requires_value_and_currency docs
body.website_requires_source_url required The event is marked `action_source: website` but carries no `event_source_url`, which Meta requires for website events. Fix: Send the page URL the conversion happened on. vendor.meta-conversions-api.body.website_requires_source_url docs
body.ldu_requires_country required Limited Data Use is enabled but `data_processing_options_country` is missing. Fix: Send `data_processing_options_country` as 1 for the United States, or 0 to let Meta geolocate. vendor.meta-conversions-api.body.ldu_requires_country docs
body.unhashed_email required A field carries what looks like a raw email address. Meta requires customer information to be normalized and SHA-256 hashed before it is sent. Fix: Trim the address, lowercase it, hash it with SHA-256, and send the hex digest. vendor.meta-conversions-api.body.unhashed_email docs
body.hashed_plaintext_field required This field looks like a SHA-256 digest, but Meta documents it as one of the parameters that is sent unhashed. Fix: Send the raw value. Hashing it makes the event unmatchable. vendor.meta-conversions-api.body.hashed_plaintext_field docs

Validate a payload

pixellint validate json @payload.json --rulepack vendor/meta-conversions-api

Or paste it into the playground. Same engine, in the browser, nothing sent anywhere.

cargo install pixellint · npm install pixellint