Meta Conversions API node for n8n
Meta Conversions APIsends Meta (Facebook) conversion events from n8n. Map raw values and the node normalizes and SHA-256 hashes them to Meta's spec, omits absent fields rather than sending a hash of an empty string, and keeps your access token in a credential instead of the workflow. MIT licensed. Source, npm.
Meta reference: Conversions API get started, server event parameters, customer information parameters
Setup
In n8n: Settings, Community nodes, Install, then enter the package name.
n8n-nodes-meta-conversions-apiAdd a trigger, a Webhook is the common one, then add Meta Conversions API. Webhook into the node is the whole workflow.
- Dataset ID: from Events Manager under Data sources.
- Event Name and Action Source, plus Event Source URL for website events, which Meta requires.
- Map at least Email or Phone under Customer Information, plus Client IP Address and Client User Agent.
- Set Options, Test Event Code while testing, then remove it to go live.
Credential
The credential holds the token and nothing else. Dataset ID is a node parameter, because one token often covers several datasets and a node-level value can be an expression.
| Field | Where to find it |
|---|---|
| Access Token | Events Manager, your dataset, Settings, Generate access token. For a token that outlives your personal login, use Business Settings, Users, System users, with the ads_management permission. Meta has five kinds of token and only two are worth using: which one to pick. |
| API Version | Graph API version, e.g. v23.0. Defaults to v23.0. |
Test resolves the token's owner through the Graph API, which proves the token is valid and unexpired. It does not check access to a dataset, since the credential does not know which one you mean. A token that is valid but not permitted on a given dataset surfaces as an error on the node, naming it.
Parameters
| Parameter | What it is | Where to find it / accepted values |
|---|---|---|
| Dataset ID | The dataset the event is written to. Formerly the pixel ID. | Events Manager, Data sources. The ID sits under the dataset name. Supports an expression, so one workflow can route to several datasets. |
| Event Name | The event Meta records. | Meta's 17 standard events plus PageView, or Custom Event to type your own. A custom name must match Ads Manager exactly, including case. |
| Action Source | Where the conversion happened. Required on every event. | website, app, email, phone_call, chat, physical_store, system_generated, business_messaging, other. Must match the dataset type. |
| Event Source URL | The page URL the event happened on. | Required by Meta for website events. Shown only when Action Source is Website. |
| Event ID | Deduplication key against the browser pixel. | Whatever your pixel sends as eventID for the same event. Leave empty and the node generates one from the execution ID, which is idempotent on retry but will not deduplicate against the pixel. |
| Event Time | When the event happened. | Unix seconds (1784059038), Unix milliseconds, or an ISO date. Leave empty for now. Meta rejects the whole request if any event is over 7 days old. |
| Value | Monetary value of the conversion. | Empty sends no value. 0 is sent as a real value. Required for Purchase. |
| Currency | ISO 4217 code for Value. | Only sent when Value is set. Defaults to USD. |
Value and currency
An event either has a value or it does not, and you should not need a Switch to express that. If Value resolves to empty, the node omits custom_data entirely. If it resolves to a number, the node sends value and currency. One field covers both cases.
0 is a real value and is sent. A non-numeric value such as N/A raises an error naming the item rather than booking the conversion at zero. Purchase is the one standard event where Meta requires a value, so the node refuses to send one without it.
Customer information
Map raw values. Each is normalized to Meta's rules and SHA-256 hashed where Meta requires it. Fields left empty are omitted, never sent as a hash of an empty string, because SHA256("") is a well-formed hash of nobody. Values that are already SHA-256 digests are passed through rather than hashed twice.
| Field | Sent as | Normalization |
|---|---|---|
em, hashed | Trimmed and lowercased. Values without an @ are dropped. | |
| Phone | ph, hashed | Digits only, leading zeros stripped, no plus sign. Needs a country code, or set Default Country Calling Code. |
| First Name | fn, hashed | Lowercased, punctuation removed. |
| Last Name | ln, hashed | Lowercased, punctuation removed. |
| City | ct, hashed | Lowercased, spaces and punctuation removed. |
| State | st, hashed | Lowercased alphanumerics. Two-letter ANSI code for US states. |
| Zip Code | zp, hashed | Lowercased, no spaces. US ZIP+4 truncated to five digits. |
| Country | country, hashed | Lowercase ISO 3166-1 alpha-2. usa is dropped, us is sent. |
| Date of Birth | db, hashed | Any parseable date, converted to YYYYMMDD in UTC. |
| Gender | ge, hashed | Reduced to f or m. |
| External ID | external_id, hashed | Your stable user ID, trimmed. Keep it consistent across events. |
| Client IP Address | client_ip_address, raw | IPv4 or IPv6. An X-Forwarded-For chain is reduced to the client IP. |
| Client User Agent | client_user_agent, raw | Passed through. Meta lists it as required for website events. |
| Fbc (Click ID) | fbc, raw | The _fbc cookie. A bare fbclid is upgraded to fb.1.<time>.<fbclid>. |
| Fbp (Cookie ID) | fbp, raw | The _fbp cookie. |
| Lead ID | lead_id, raw | Meta lead ad ID. |
| Subscription ID | subscription_id, raw | Your subscription ID for this user. |
Meta's phone format is Meta's alone
Meta wants bare digits: +1 (213) 373-4253 hashes as 12133734253, with no plus sign. Other ad platforms disagree, and every wrong shape still returns events_received: 1. Map the raw number and let the node format it.
Where fbc and fbp come from: the _fbc and _fbp cookies set by the Meta pixel on your site. If you have no pixel, pass the fbclid query parameter from the landing URL as Fbc and the node formats it. Both are the strongest signals available, because they tie the event to an actual ad click.
Custom data
Key and value pairs sent inside custom_data, such as content_name or your own fields. Values are sent as-is.
Reserved keys
Server event parameters such as action_source, event_name and event_id live at the top of the event, not inside custom_data. Meta ignores them when nested, so the node rejects them here and points at the option that sets them.
Options
Meta reference: main body parameters
| Option | What it does |
|---|---|
| Test Event Code | Routes the event to Test Events instead of counting it. Events Manager, your dataset, Test Events. The code is per-dataset. |
| Default Country Calling Code | Prepended to phone numbers that arrive without one, e.g. 1. A phone without a country code will not match. |
| API Version | Overrides the Graph API version from the credential. |
| Opt Out | Uses the event for attribution only, not for delivery optimisation. |
| Action Source URL Referrer | The HTTP referrer of the page that triggered the event. |
| Limited Data Use | Applies Meta's LDU flag. Reveals country and state options. |
| Batch Events | Sends all input items in one request, up to Meta's limit of 1000, grouped by dataset. Off by default: Meta rejects the entire batch if any single event is invalid. |
Output
Meta reference: using the API
One item per event, carrying Meta's response and the event as sent.
{
"events_received": 1,
"messages": [],
"fbtrace_id": "AfGdnLPtkz0_2Tw-U3Rl87K",
"dataset_id": "1234567890123456",
"test_event_code": "TEST12345",
"event": {
"event_name": "Schedule",
"event_time": 1784059038,
"action_source": "website",
"user_data": {
"em": ["87924606b4131a8ace...."],
"client_ip_address": "254.254.254.254",
"client_user_agent": "Mozilla/5.0 ..."
},
"event_id": "12345",
"event_source_url": "https://example.com/thanks",
"custom_data": { "value": 5, "currency": "USD" }
}
}The event is returned exactly as it reached Meta, so you never have to guess what was hashed: an email mapped in raw leaves as a digest under em. test_event_code is present only when set, so a test send is distinguishable from a real one in the output.
Errors
The node validates before sending and fails on the item at fault. Turn on Settings, Continue on fail to route failures to a second branch instead.
| Check | Fails when | Why |
|---|---|---|
| Event Source URL | Empty on a website event | Meta requires it |
| Event Time | Over 7 days old | Meta rejects the whole request, not just that event |
| Value | Present but not a number | Otherwise the conversion books at 0 silently |
| Purchase | No value | Meta requires value and currency on Purchase |
| Custom Data | Uses a reserved key | Meta ignores server event parameters nested in custom_data |
| Customer Information | Nothing survives normalization | An event with no identifier cannot be attributed to anyone |
Testing
- Events Manager, your dataset, the Test Events tab. Copy the test event code. It is per-dataset.
- On the node, under Options, add Test Event Code and paste it.
- Execute. The event should appear in Test Events within a few seconds.
- When it looks right, remove the code. While it is set, the event does not count as a real conversion.
In Test Events, Received from: Server confirms the event came from the API rather than the pixel, and User data keys lists the identifiers Meta actually read out of it, which is the only place you can see that the hash survived the trip.
events_received: 1 is not success
It means Meta parsed the request. Not that the event was accepted, matched, attributed, or treated as a test. An event with no usable identifiers returns exactly the same response as one that worked. Judge the setup on event match quality in Events Manager, never on the response.
Events return success but never appear in Test Events? The action source usually does not match the dataset type. An offline event set will not show website events: Meta accepts the request, answers events_received: 1, and counts the event as a real conversion instead of a test. Offline datasets need physical_store. Also check the marketing-channel selector on the Test Events tab, which filters what you see, and confirm the code came from the dataset you are sending to.
Best practices covers what Meta asks you to do beyond getting the request accepted.