This workflow corresponds to n8n.io template #11089 β we link there as the canonical source.
The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide β
{
"id": "mXgQJT7qXMEFQAow",
"name": "Server-Side Meta Ads Tracking Template [PUBLIC]",
"tags": [],
"nodes": [
{
"id": "de88e89c-acfd-4592-8f73-0f1b56dba93b",
"name": "Edit Normalize PII",
"type": "n8n-nodes-base.set",
"position": [
-752,
0
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "9545094c-a24a-4689-b212-4bc351f8f08b",
"name": "normalized_email",
"type": "string",
"value": "={{ $json.body.email.trim().toLowerCase() }}"
},
{
"id": "fe26118b-5e9e-4c3f-acf0-e995a32779d1",
"name": "normalized_phone",
"type": "string",
"value": "={{ $json.body.phone.replace(/\\D/g, '') }}"
},
{
"id": "59a2b784-44c4-44c4-bf28-2e8a27cc8975",
"name": "firstName",
"type": "string",
"value": "={{ $json.body.firstName.trim().toLowerCase() }}"
},
{
"id": "72ada7ed-e895-445e-ac4f-f5d8102ba46a",
"name": "lastName",
"type": "string",
"value": "={{ $json.body.lastName.trim().toLowerCase() }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "cf2debc3-7cc0-450f-9e58-9b981333c537",
"name": "Crypto - Hash Email",
"type": "n8n-nodes-base.crypto",
"position": [
-512,
0
],
"parameters": {
"type": "SHA256",
"value": "={{ $json.normalized_email }}",
"dataPropertyName": "hashed_em"
},
"typeVersion": 1
},
{
"id": "b6821a25-cbb2-4083-9693-30cf3da3aaac",
"name": "Crypto - Hash Phone",
"type": "n8n-nodes-base.crypto",
"position": [
-256,
0
],
"parameters": {
"type": "SHA256",
"value": "={{ $json.normalized_phone }}",
"dataPropertyName": "hashed_ph"
},
"typeVersion": 1
},
{
"id": "1a61578d-b32a-41f8-9e24-a635a645eda0",
"name": "Set - Compute Timestamps & Map Fields",
"type": "n8n-nodes-base.set",
"position": [
400,
0
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "c2ccdb0e-05c6-4f02-9daf-c495a261d82a",
"name": "conversion_timestamp",
"type": "number",
"value": "={{ Math.floor(Date.now() / 1000) }}"
},
{
"id": "a434a6c6-c4fe-48a1-b808-58cf42378f1d",
"name": "event_name",
"type": "string",
"value": "SubmitApplication"
},
{
"id": "1323fcc0-95e8-461b-9cb5-f0106b10345d",
"name": "hashed_em",
"type": "string",
"value": "={{ $('Crypto - Hash Email').item.json.hashed_em }}"
},
{
"id": "7a276391-9aab-41a1-8514-63b0c5350011",
"name": "hashed_ph",
"type": "string",
"value": "={{ $json.hashed_ph }}"
},
{
"id": "19d9b649-873f-4018-b7b9-a7070143abb1",
"name": "hashed_firstName",
"type": "string",
"value": "={{ $json.hashed_firstName }}"
},
{
"id": "15d5a6d2-6c71-40a4-8ad8-fe929d94e9b4",
"name": "hashed_lastName",
"type": "string",
"value": "={{ $json.hashed_lastName }}"
},
{
"id": "dda7617f-a148-4b8f-9459-50baa386507e",
"name": "fbc",
"type": "string",
"value": "={{ $('Webhook').item.json.body.fbc }}"
},
{
"id": "fab3e276-ead2-4654-ae09-5f6f3bcef3e6",
"name": "fbp",
"type": "string",
"value": "={{ $('Webhook').item.json.body.fbp }}"
},
{
"id": "8bf3b47f-f737-4262-8f86-27f287ed6560",
"name": "ipAddress",
"type": "string",
"value": "={{ $('Webhook').item.json.headers['x-forwarded-for'] }}"
},
{
"id": "4f88bdd9-d7cf-4f8e-84b3-db55f50e10ed",
"name": "userAgent",
"type": "string",
"value": "={{ $('Webhook').item.json.headers['user-agent'] }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "13f09e7a-7684-41d1-9396-413f71727703",
"name": "Crypto - First Name",
"type": "n8n-nodes-base.crypto",
"position": [
-48,
0
],
"parameters": {
"type": "SHA256",
"value": "={{ $json.firstName }}",
"dataPropertyName": "hashed_firstName"
},
"typeVersion": 1
},
{
"id": "798bdcb5-3861-4a9a-a355-a776e510773c",
"name": "Crypto - Last Name",
"type": "n8n-nodes-base.crypto",
"position": [
160,
0
],
"parameters": {
"type": "SHA256",
"value": "={{ $json.lastName }}",
"dataPropertyName": "hashed_lastName"
},
"typeVersion": 1
},
{
"id": "9f465c29-2bfd-443f-8bc9-ba259f3d5751",
"name": "Sending Events To Facebook Pixel",
"type": "n8n-nodes-base.httpRequest",
"position": [
864,
0
],
"parameters": {
"url": "https://graph.facebook.com/v24.0/PIXEL_ID_HERE/events",
"method": "POST",
"options": {},
"jsonBody": "={{ $json }}",
"sendBody": true,
"sendHeaders": true,
"specifyBody": "json",
"authentication": "genericCredentialType",
"genericAuthType": "httpBearerAuth",
"headerParameters": {
"parameters": [
{
"name": "Content-Type",
"value": "application/json"
}
]
}
},
"typeVersion": 4.2
},
{
"id": "9df179f5-643b-4a2e-8a51-fd407b16183d",
"name": "Webhook",
"type": "n8n-nodes-base.webhook",
"position": [
-976,
0
],
"parameters": {
"path": "meta-conversion-api",
"options": {},
"httpMethod": "POST",
"responseMode": "responseNode"
},
"typeVersion": 2.1
},
{
"id": "7a962bb1-7d34-46b5-82d7-3f777ee9ad4f",
"name": "Respond to Webhook",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
1072,
0
],
"parameters": {
"options": {
"responseCode": 200
},
"respondWith": "allIncomingItems"
},
"typeVersion": 1.4
},
{
"id": "2b5d641f-7cb4-4a2e-b708-66dbf56396c0",
"name": "Preparing for HTTP Request Payload",
"type": "n8n-nodes-base.code",
"position": [
624,
0
],
"parameters": {
"jsCode": "// Get the incoming data from the previous node.\n// n8n provides this as the '$json' variable.\nconst incomingData = $json;\n\n// Create the final, perfectly structured payload for the Facebook CAPI node.\nconst capiPayload = {\n data: [\n {\n event_name: incomingData.event_name,\n event_time: incomingData.conversion_timestamp,\n action_source: 'website',\n\n // Build the user_data object by mapping your fields to Meta's fields.\n user_data: {\n // --- These are the two lines we are fixing ---\n // We are now 100% sure they match your input data.\n fn: incomingData.hashed_firstName,\n ln: incomingData.hashed_lastName,\n\n // The rest of the mapping\n em: incomingData.hashed_em,\n ph: incomingData.hashed_ph,\n fbc: incomingData.fbc,\n fbp: incomingData.fbp,\n client_ip_address: incomingData.ipAddress,\n client_user_agent: incomingData.userAgent,\n },\n },\n ],\n};\n\n// Return the transformed data so the next node can use it.\nreturn capiPayload;"
},
"typeVersion": 2
},
{
"id": "39e00abc-81c2-475c-b084-9fe1b1db8771",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1840,
-448
],
"parameters": {
"width": 592,
"height": 880,
"content": "## Send Server-Side Conversions to the Meta Ads API (CAPI)\n\nThis workflow acts as a server-side endpoint to send conversion events directly to the Meta (Facebook) Conversions API. This helps you get more accurate ad tracking that isn't affected by browser ad blockers or iOS privacy changes.\n\n**Watch the full setup tutorial on YouTube:**\nhttps://youtu.be/_fdMPIYEvFM\n\n## How it works\n1. **Webhook Trigger:** It starts when it receives data at its unique URL.\n2. **Normalize & Hash PII:** It cleans up the user data (email, phone, etc.) and securely hashes it using SHA-256, as required by Meta.\n3. **Format Payload:** It assembles the hashed data, event details, and browser info (`fbc`, `fbp`, IP address) into a perfectly structured payload for the CAPI.\n4. **Send to Meta:** It sends the final data directly to Meta's servers.\n\n## \u26a0\ufe0f How to set up\n### Step 1: Configure Your Data Source\nThis workflow is triggered by a Webhook. You need to send data to it from your website form, CRM, or backend. The data **MUST** be sent as a JSON object.\n\nThe required fields are `email`, `phone`, `firstName`, `lastName`, `fbc`, and `fbp`. For a live example of the data structure, please see the **pinned data on the Webhook node**.\n\n### Step 2: Configure the Workflow\n1. **Copy the Webhook URL:** Click on the \"Webhook\" trigger node and copy the **Test URL** for testing, or the **Production URL** for your live application.\n2. **Customize Event Name (Optional):** In the \"Set - Compute Timestamps & Map Fields\" node, you can change the `event_name` from `SubmitApplication` to whatever you need (e.g., `Purchase`, `Lead`).\n3. **Add Your Meta Pixel ID:** In the final \"Sending Events To Facebook Pixel\" node, replace `PIXEL_ID_HERE` in the **URL** with your actual Meta Pixel ID.\n4. **Add Your Access Token:** In the same node, go to the **Authentication** tab and create a new **Bearer YOUR_TOKEN_HERE** credential. Paste the CAPI Access Token you generated from Meta Events Manager."
},
"typeVersion": 1
},
{
"id": "695dd7b8-2030-4114-9e91-f426a55e0ba7",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1056,
160
],
"parameters": {
"height": 272,
"content": "**\ud83d\udc47 STEP 1: START HERE**\n\nThis is your endpoint. Copy the URL from this node and configure your website form or backend to send a POST request with a JSON body to it.\n\nSee the main yellow note and the **pinned data on this node** for the required JSON data structure!"
},
"typeVersion": 1
},
{
"id": "eb626055-ef90-420d-a569-715797fd6c7f",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
-560,
160
],
"parameters": {
"color": 4,
"width": 864,
"height": 128,
"content": "**\ud83d\udd12 STEP 2: SECURE & HASH DATA**\n\nThis section automatically cleans and hashes the incoming user data to meet Meta's CAPI requirements.\n\nNo configuration is needed here\u2014it just works!"
},
"typeVersion": 1
},
{
"id": "018c683d-5d26-4931-9cc4-f7f8bd23aafc",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
752,
176
],
"parameters": {
"width": 512,
"height": 224,
"content": "**\ud83d\ude80 STEP 3: SEND TO META**\n\nThis is the final and most important step.\n\n**Action Required:**\n1. Replace **`PIXEL_ID_HERE`** in the **URL** with your real Meta Pixel ID.\n2. Under **Authentication**, create a new **Bearer YOUR_TOKEN_HERE** credential and paste in your CAPI Access Token from Meta Events Manager."
},
"typeVersion": 1
}
],
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "55ded24f-0574-40b7-8a5e-414ab42f5e24",
"connections": {
"Webhook": {
"main": [
[
{
"node": "Edit Normalize PII",
"type": "main",
"index": 0
}
]
]
},
"Crypto - Last Name": {
"main": [
[
{
"node": "Set - Compute Timestamps & Map Fields",
"type": "main",
"index": 0
}
]
]
},
"Edit Normalize PII": {
"main": [
[
{
"node": "Crypto - Hash Email",
"type": "main",
"index": 0
}
]
]
},
"Crypto - First Name": {
"main": [
[
{
"node": "Crypto - Last Name",
"type": "main",
"index": 0
}
]
]
},
"Crypto - Hash Email": {
"main": [
[
{
"node": "Crypto - Hash Phone",
"type": "main",
"index": 0
}
]
]
},
"Crypto - Hash Phone": {
"main": [
[
{
"node": "Crypto - First Name",
"type": "main",
"index": 0
}
]
]
},
"Sending Events To Facebook Pixel": {
"main": [
[
{
"node": "Respond to Webhook",
"type": "main",
"index": 0
}
]
]
},
"Preparing for HTTP Request Payload": {
"main": [
[
{
"node": "Sending Events To Facebook Pixel",
"type": "main",
"index": 0
}
]
]
},
"Set - Compute Timestamps & Map Fields": {
"main": [
[
{
"node": "Preparing for HTTP Request Payload",
"type": "main",
"index": 0
}
]
]
}
}
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Struggling with inaccurate Meta Ads tracking due to iOS 14+ and ad blockers? π This workflow is your solution. It provides a robust, server-side endpoint to reliably send conversion events directly to the Meta Conversions API (CAPI).
Source: https://n8n.io/workflows/11089/ β original creator credit. Request a take-down β
More Web Scraping workflows β Β· Browse all categories β
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
Community Node Disclaimer: This workflow uses KlickTipp community nodes.
Community Node Disclaimer: This workflow uses KlickTipp community nodes.
This n8n template provides enterprise-level version control for your workflows using GitHub integration. Stop losing hours to broken workflows and manual exports β get proper commit history, visual di
This flow creates dummy files for every item added in your *Arrs (Radarr/Sonarr) with the tag .
This workflow acts as a central API gateway for all technical indicator agents in the Binance Spot Market Quant AI system. It listens for incoming webhook requests and dynamically routes them to the c