This workflow corresponds to n8n.io template #14721 — we link there as the canonical source.
This workflow follows the Google Sheets → HTTP Request recipe pattern — see all workflows that pair these two integrations.
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": "xxxxxxxxx",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "Meta Ads Insights to Google Sheets (Backfill & Weekly Sync ETL)",
"tags": [],
"nodes": [
{
"id": "a0e731a9-5868-4143-a057-134d5815f13e",
"name": "Manual Trigger (Historical Backfill)",
"type": "n8n-nodes-base.manualTrigger",
"position": [
-1312,
5728
],
"parameters": {},
"typeVersion": 1
},
{
"id": "43c27e49-8444-493a-8bcb-c8f720e613b2",
"name": "Append to Log Sheet (Account B)",
"type": "n8n-nodes-base.googleSheets",
"position": [
496,
6016
],
"parameters": {
"columns": {
"value": {
"since": "={{ $json.since }}",
"until": "={{ $json.until }}",
"reason": "={{ $json.reason }}",
"status": "={{ $json.status }}",
"account": "={{ $json.account }}",
"timestamp": "={{ $json.timestamp }}",
"execution_id": "={{ $json.execution_id }}"
},
"schema": [
{
"id": "status",
"type": "string",
"display": true,
"required": false,
"displayName": "status",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "reason",
"type": "string",
"display": true,
"required": false,
"displayName": "reason",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "account",
"type": "string",
"display": true,
"required": false,
"displayName": "account",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "since",
"type": "string",
"display": true,
"required": false,
"displayName": "since",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "until",
"type": "string",
"display": true,
"required": false,
"displayName": "until",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "execution_id",
"type": "string",
"display": true,
"required": false,
"displayName": "execution_id",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "timestamp",
"type": "string",
"display": true,
"required": false,
"displayName": "timestamp",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "name",
"value": "Account_B_Log"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "YOUR_SPREADSHEET_ID",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_SPREADSHEET_ID/edit",
"cachedResultName": "Meta Ads Report"
}
},
"typeVersion": 4.7
},
{
"id": "a76c2362-6495-4c2b-91d6-92bc08f99159",
"name": "Workflow Overview",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2560,
5008
],
"parameters": {
"color": 7,
"width": 1100,
"height": 516,
"content": "## Meta Ads Insights to Google Sheets (Backfill & Weekly Sync ETL)\n\nThis workflow extracts Meta Ads performance data and loads it into Google Sheets for reporting or use as a BI source such as Looker Studio. It supports two operating modes in a single workflow.\n\n---\n\n### Two Paths, One Workflow\n\n**Path 1 \u2014 Historical Backfill (Manual Trigger)** \nRun once to populate past data. Set `start_date` and `end_date` in the *Set Date Range* node. The *Generate Weekly Periods* node splits the range into 7-day chunks and processes them one by one to reduce the chance of API throttling.\n\n**Path 2 \u2014 Incremental Sync (Schedule Trigger, every 7 days)** \nRuns automatically and pulls the last 7 days. The date range is calculated dynamically, so no manual input is needed.\n\n---\n\n### Granularity Per Account\n- **Account A** \u2014 `level=campaign`, weekly\n- **Account B** \u2014 `level=ad` + `time_increment=1`, daily per ad\n\n---\n\n### Known Limitation\nThis template uses append-only writes. Re-running over the same date range will produce duplicate rows. Manual deduplication or a cleanup step may be needed.\n\n---\n\n### Setup\na) **Meta credential** \u2014 Configure an HTTP Header Auth credential with a long-lived Meta User Access Token that has `ads_read` permission. \nb) **Ad Account IDs** \u2014 Replace `act_XXXXXXXXXXXXXXXXX` in both HTTP Request nodes. \nc) **Google Sheets** \u2014 Configure a Google Sheets OAuth2 credential and prepare tabs `Account_A`, `Account_B`, `Account_A_Log`, and `Account_B_Log`. \nd) **Historical range** \u2014 Update `start_date` and `end_date` in *Set Date Range* before running the Manual Trigger."
},
"typeVersion": 1
},
{
"id": "e961643f-78b9-4a2a-90fa-33ec5b37aa0a",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
-544,
4928
],
"parameters": {
"color": 3,
"width": 1332,
"height": 604,
"content": "## Ad Account A \u2014 Campaign Level\n\nFetches weekly campaign-level insights from the Meta Ads API.\n\n**Setup:**\n- Replace `act_XXXXXXXXXXXXXXXXX` in the HTTP node URL with your Meta Ad Account ID.\n- Target sheet tab: **Account_A**\n- Granularity: `level=campaign` (one row per campaign per week)."
},
"typeVersion": 1
},
{
"id": "31355294-6709-4e6a-8b1a-8eb48dd9ccf4",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
-544,
5648
],
"parameters": {
"color": 6,
"width": 1332,
"height": 604,
"content": "## Ad Account B \u2014 Ad Level (Daily Breakdown)\n\nFetches weekly ad-level insights with a daily breakdown from the Meta Ads API.\n\n**Setup:**\n- Replace `act_XXXXXXXXXXXXXXXXX` in the HTTP node URL with your Meta Ad Account ID.\n- Target sheet tab: **Account_B**\n- Granularity: `level=ad` + `time_increment=1` (one row per ad per day)."
},
"typeVersion": 1
},
{
"id": "5bbd4115-daba-4bba-84a6-d7439d628b14",
"name": "Split API Response (Account A)",
"type": "n8n-nodes-base.code",
"position": [
256,
5088
],
"parameters": {
"jsCode": "return items.flatMap(item => {\n const rows = item.json.data || [];\n\n return rows.map(row => ({\n json: {\n date_start: row.date_start,\n date_stop: row.date_stop,\n account_id: row.account_id,\n account_name: row.account_name,\n campaign_id: row.campaign_id,\n campaign_name: row.campaign_name,\n adset_id: row.adset_id,\n adset_name: row.adset_name,\n ad_id: row.ad_id,\n ad_name: row.ad_name,\n objective: row.objective,\n buying_type: row.buying_type,\n\n spend: Number(row.spend || 0),\n impressions: Number(row.impressions || 0),\n reach: Number(row.reach || 0),\n frequency: Number(row.frequency || 0),\n clicks: Number(row.clicks || 0),\n unique_clicks: Number(row.unique_clicks || 0),\n ctr: Number(row.ctr || 0),\n cpc: Number(row.cpc || 0),\n cpm: Number(row.cpm || 0),\n\n actions: row.actions || [],\n cost_per_action_type: row.cost_per_action_type || [],\n action_values: row.action_values || [],\n quality_ranking: row.quality_ranking || '',\n engagement_rate_ranking: row.engagement_rate_ranking || '',\n conversion_rate_ranking: row.conversion_rate_ranking || ''\n }\n }));\n});"
},
"typeVersion": 2
},
{
"id": "6956d380-dfdd-4caa-81f2-b1b4b0ef1734",
"name": "Append to Sheet (Account A)",
"type": "n8n-nodes-base.googleSheets",
"position": [
640,
5088
],
"parameters": {
"columns": {
"value": {
"cpc": "={{ $json.cpc }}",
"cpm": "={{ $json.cpm }}",
"ctr": "={{ $json.ctr }}",
"ad_id": "={{ $json.ad_id }}",
"reach": "={{ $json.reach }}",
"spend": "={{ $json.spend }}",
"clicks": "={{ $json.clicks }}",
"actions": "={{ $json.actions }}",
"ad_name": "={{ $json.ad_name }}",
"adset_id": "={{ $json.adset_id }}",
"date_stop": "={{ $json.date_stop }}",
"frequency": "={{ $json.frequency }}",
"objective": "={{ $json.objective }}",
"account_id": "={{ $json.account_id }}",
"adset_name": "={{ $json.adset_name }}",
"date_start": "={{ $json.date_start }}",
"buying_type": "={{ $json.buying_type }}",
"campaign_id": "={{ $json.campaign_id }}",
"impressions": "={{ $json.impressions }}",
"account_name": "={{ $json.account_name }}",
"action_values": "={{ $json.action_values }}",
"campaign_name": "={{ $json.campaign_name }}",
"unique_clicks": "={{ $json.unique_clicks }}",
"quality_ranking": "={{ $json.quality_ranking }}",
"cost_per_action_type": "={{ $json.cost_per_action_type }}",
"conversion_rate_ranking": "={{ $json.conversion_rate_ranking }}",
"engagement_rate_ranking": "={{ $json.engagement_rate_ranking }}"
},
"schema": [
{
"id": "date_start",
"type": "string",
"display": true,
"required": false,
"displayName": "date_start",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "date_stop",
"type": "string",
"display": true,
"required": false,
"displayName": "date_stop",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "account_id",
"type": "string",
"display": true,
"required": false,
"displayName": "account_id",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "account_name",
"type": "string",
"display": true,
"required": false,
"displayName": "account_name",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "campaign_id",
"type": "string",
"display": true,
"required": false,
"displayName": "campaign_id",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "campaign_name",
"type": "string",
"display": true,
"required": false,
"displayName": "campaign_name",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "adset_id",
"type": "string",
"display": true,
"required": false,
"displayName": "adset_id",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "adset_name",
"type": "string",
"display": true,
"required": false,
"displayName": "adset_name",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "ad_id",
"type": "string",
"display": true,
"required": false,
"displayName": "ad_id",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "ad_name",
"type": "string",
"display": true,
"required": false,
"displayName": "ad_name",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "objective",
"type": "string",
"display": true,
"required": false,
"displayName": "objective",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "buying_type",
"type": "string",
"display": true,
"required": false,
"displayName": "buying_type",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "spend",
"type": "string",
"display": true,
"required": false,
"displayName": "spend",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "impressions",
"type": "string",
"display": true,
"required": false,
"displayName": "impressions",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "reach",
"type": "string",
"display": true,
"required": false,
"displayName": "reach",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "frequency",
"type": "string",
"display": true,
"required": false,
"displayName": "frequency",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "clicks",
"type": "string",
"display": true,
"required": false,
"displayName": "clicks",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "unique_clicks",
"type": "string",
"display": true,
"required": false,
"displayName": "unique_clicks",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "ctr",
"type": "string",
"display": true,
"required": false,
"displayName": "ctr",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "cpc",
"type": "string",
"display": true,
"required": false,
"displayName": "cpc",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "cpm",
"type": "string",
"display": true,
"required": false,
"displayName": "cpm",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "actions",
"type": "string",
"display": true,
"required": false,
"displayName": "actions",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "cost_per_action_type",
"type": "string",
"display": true,
"required": false,
"displayName": "cost_per_action_type",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "action_values",
"type": "string",
"display": true,
"required": false,
"displayName": "action_values",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "quality_ranking",
"type": "string",
"display": true,
"required": false,
"displayName": "quality_ranking",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "engagement_rate_ranking",
"type": "string",
"display": true,
"required": false,
"displayName": "engagement_rate_ranking",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "conversion_rate_ranking",
"type": "string",
"display": true,
"required": false,
"displayName": "conversion_rate_ranking",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "list",
"value": "gid=0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_SPREADSHEET_ID/edit#gid=0",
"cachedResultName": "Account_A"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "YOUR_SPREADSHEET_ID",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_SPREADSHEET_ID/edit",
"cachedResultName": "Meta Ads Report"
}
},
"typeVersion": 4.7
},
{
"id": "a7e0dc63-3014-4ba6-b2a3-ebb8231f2560",
"name": "Fetch Meta Insights (Account A)",
"type": "n8n-nodes-base.httpRequest",
"maxTries": 5,
"position": [
-224,
5168
],
"parameters": {
"url": "https://graph.facebook.com/v24.0/act_XXXXXXXXXXXXXXXXX/insights",
"options": {
"response": {
"response": {
"neverError": true
}
},
"pagination": {
"pagination": {
"nextURL": "={{ $response.body.paging.next }}",
"paginationMode": "responseContainsNextURL",
"requestInterval": 3000,
"completeExpression": "={{ !$response.body.paging?.next }}",
"paginationCompleteWhen": "other"
}
}
},
"sendQuery": true,
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"queryParameters": {
"parameters": [
{
"name": "fields",
"value": "date_start,date_stop,account_id,account_name,campaign_id,campaign_name,adset_id,adset_name,ad_id,ad_name,objective,buying_type,spend,impressions,reach,frequency,clicks,unique_clicks,ctr,cpc,cpm,actions,cost_per_action_type,action_values,quality_ranking,engagement_rate_ranking,conversion_rate_ranking"
},
{
"name": "level",
"value": "campaign"
},
{
"name": "time_range[since]",
"value": "={{ $json.since }}"
},
{
"name": "time_range[until]",
"value": "={{ $json.until }}"
}
]
}
},
"retryOnFail": true,
"typeVersion": 4.3,
"continueOnFail": true,
"waitBetweenTries": 3000
},
{
"id": "b511f5f0-2958-4587-83df-8f3def77e9d0",
"name": "Loop Over Periods (Account A)",
"type": "n8n-nodes-base.splitInBatches",
"position": [
-464,
5168
],
"parameters": {
"options": {}
},
"typeVersion": 3,
"alwaysOutputData": false
},
{
"id": "0cc3675f-73a2-42ba-b28b-36eb70862328",
"name": "Valid Response? (Account A)",
"type": "n8n-nodes-base.if",
"position": [
16,
5168
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 1,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "0433ddac-c3db-4463-a06d-c0a4ecb09210",
"operator": {
"type": "boolean",
"operation": "equals"
},
"leftValue": "={{ Array.isArray($json.data) && $json.data.length > 0 }}",
"rightValue": true
}
]
}
},
"typeVersion": 2
},
{
"id": "cf7c2e06-7e5f-42c3-a0e8-ea9e903b2fe7",
"name": "Log Skipped Period (Account A)",
"type": "n8n-nodes-base.set",
"position": [
256,
5296
],
"parameters": {
"mode": "raw",
"options": {},
"jsonOutput": "{\n \"status\": \"skipped\",\n \"reason\": \"Meta API returned no data or an error for this period\",\n \"account\": \"Account A\",\n \"since\": \"={{ $('Loop Over Periods (Account A)').item.json.since }}\",\n \"until\": \"={{ $('Loop Over Periods (Account A)').item.json.until }}\",\n \"execution_id\": \"={{ $execution.id }}\",\n \"timestamp\": \"={{ new Date().toISOString() }}\"\n}"
},
"typeVersion": 3.4
},
{
"id": "db2400d2-3ac1-405b-bdd0-cf7768b0be4a",
"name": "Append to Log Sheet (Account A)",
"type": "n8n-nodes-base.googleSheets",
"position": [
496,
5296
],
"parameters": {
"columns": {
"value": {
"since": "={{ $json.since }}",
"until": "={{ $json.until }}",
"reason": "={{ $json.reason }}",
"status": "={{ $json.status }}",
"account": "={{ $json.account }}",
"timestamp": "={{ $json.timestamp }}",
"execution_id": "={{ $json.execution_id }}"
},
"schema": [
{
"id": "status",
"type": "string",
"display": true,
"required": false,
"displayName": "status",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "reason",
"type": "string",
"display": true,
"required": false,
"displayName": "reason",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "account",
"type": "string",
"display": true,
"required": false,
"displayName": "account",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "since",
"type": "string",
"display": true,
"required": false,
"displayName": "since",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "until",
"type": "string",
"display": true,
"required": false,
"displayName": "until",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "execution_id",
"type": "string",
"display": true,
"required": false,
"displayName": "execution_id",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "timestamp",
"type": "string",
"display": true,
"required": false,
"displayName": "timestamp",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "name",
"value": "Account_A_Log"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "YOUR_SPREADSHEET_ID",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_SPREADSHEET_ID/edit",
"cachedResultName": "Meta Ads Report"
}
},
"typeVersion": 4.7
},
{
"id": "73bb5e27-b475-429b-8cdd-a6db1dae3900",
"name": "Loop Over Periods (Account B)",
"type": "n8n-nodes-base.splitInBatches",
"position": [
-464,
5888
],
"parameters": {
"options": {}
},
"typeVersion": 3,
"alwaysOutputData": false
},
{
"id": "e9473c81-f8b9-4ab6-8fef-2835df2a1f42",
"name": "Fetch Meta Insights (Account B)",
"type": "n8n-nodes-base.httpRequest",
"maxTries": 5,
"position": [
-224,
5888
],
"parameters": {
"url": "https://graph.facebook.com/v24.0/act_XXXXXXXXXXXXXXXXX/insights",
"options": {
"response": {
"response": {
"neverError": true
}
},
"pagination": {
"pagination": {
"nextURL": "={{ $response.body.paging.next }}",
"paginationMode": "responseContainsNextURL",
"requestInterval": 3000,
"completeExpression": "={{ !$response.body.paging?.next }}",
"paginationCompleteWhen": "other"
}
}
},
"sendQuery": true,
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"queryParameters": {
"parameters": [
{
"name": "fields",
"value": "date_start,date_stop,account_id,account_name,campaign_id,campaign_name,adset_id,adset_name,ad_id,ad_name,objective,buying_type,spend,impressions,reach,frequency,clicks,unique_clicks,ctr,cpc,cpm,actions,cost_per_action_type,action_values,quality_ranking,engagement_rate_ranking,conversion_rate_ranking"
},
{
"name": "level",
"value": "ad"
},
{
"name": "time_range[since]",
"value": "={{ $json.since }}"
},
{
"name": "time_increment",
"value": "1"
},
{
"name": "time_range[until]",
"value": "={{ $json.until }}"
}
]
}
},
"retryOnFail": true,
"typeVersion": 4.3,
"continueOnFail": true,
"waitBetweenTries": 3000
},
{
"id": "fa27b4f8-139a-4d31-bcef-204e70e3f7b6",
"name": "Valid Response? (Account B)",
"type": "n8n-nodes-base.if",
"position": [
16,
5888
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 1,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "df38f124-c4f4-4a0b-a375-858436180d5b",
"operator": {
"type": "boolean",
"operation": "equals"
},
"leftValue": "={{ Array.isArray($json.data) && $json.data.length > 0 }}",
"rightValue": true
}
]
}
},
"typeVersion": 2
},
{
"id": "558675fc-af90-4ef3-b567-d835b650d5d2",
"name": "Split API Response (Account B)",
"type": "n8n-nodes-base.code",
"position": [
256,
5808
],
"parameters": {
"jsCode": "return items.flatMap(item => {\n const rows = item.json.data || [];\n\n return rows.map(row => ({\n json: {\n date_start: row.date_start,\n date_stop: row.date_stop,\n account_id: row.account_id,\n account_name: row.account_name,\n campaign_id: row.campaign_id,\n campaign_name: row.campaign_name,\n adset_id: row.adset_id,\n adset_name: row.adset_name,\n ad_id: row.ad_id,\n ad_name: row.ad_name,\n objective: row.objective,\n buying_type: row.buying_type,\n\n spend: Number(row.spend || 0),\n impressions: Number(row.impressions || 0),\n reach: Number(row.reach || 0),\n frequency: Number(row.frequency || 0),\n clicks: Number(row.clicks || 0),\n unique_clicks: Number(row.unique_clicks || 0),\n ctr: Number(row.ctr || 0),\n cpc: Number(row.cpc || 0),\n cpm: Number(row.cpm || 0),\n\n actions: row.actions || [],\n cost_per_action_type: row.cost_per_action_type || [],\n action_values: row.action_values || [],\n quality_ranking: row.quality_ranking || '',\n engagement_rate_ranking: row.engagement_rate_ranking || '',\n conversion_rate_ranking: row.conversion_rate_ranking || ''\n }\n }));\n});"
},
"typeVersion": 2
},
{
"id": "46f44c50-d25d-44bb-9215-5fbeab7165a8",
"name": "Append to Sheet (Account B)",
"type": "n8n-nodes-base.googleSheets",
"position": [
608,
5808
],
"parameters": {
"columns": {
"value": {
"cpc": "={{ $json.cpc }}",
"cpm": "={{ $json.cpm }}",
"ctr": "={{ $json.ctr }}",
"ad_id": "={{ $json.ad_id }}",
"reach": "={{ $json.reach }}",
"spend": "={{ $json.spend }}",
"clicks": "={{ $json.clicks }}",
"actions": "={{ $json.actions }}",
"ad_name": "={{ $json.ad_name }}",
"adset_id": "={{ $json.adset_id }}",
"date_stop": "={{ $json.date_stop }}",
"frequency": "={{ $json.frequency }}",
"objective": "={{ $json.objective }}",
"account_id": "={{ $json.account_id }}",
"adset_name": "={{ $json.adset_name }}",
"date_start": "={{ $json.date_start }}",
"buying_type": "={{ $json.buying_type }}",
"campaign_id": "={{ $json.campaign_id }}",
"impressions": "={{ $json.impressions }}",
"account_name": "={{ $json.account_name }}",
"action_values": "={{ $json.action_values }}",
"campaign_name": "={{ $json.campaign_name }}",
"unique_clicks": "={{ $json.unique_clicks }}",
"quality_ranking": "={{ $json.quality_ranking }}",
"cost_per_action_type": "={{ $json.cost_per_action_type }}",
"conversion_rate_ranking": "={{ $json.conversion_rate_ranking }}",
"engagement_rate_ranking": "={{ $json.engagement_rate_ranking }}"
},
"schema": [
{
"id": "date_start",
"type": "string",
"display": true,
"required": false,
"displayName": "date_start",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "date_stop",
"type": "string",
"display": true,
"required": false,
"displayName": "date_stop",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "account_id",
"type": "string",
"display": true,
"required": false,
"displayName": "account_id",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "account_name",
"type": "string",
"display": true,
"required": false,
"displayName": "account_name",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "campaign_id",
"type": "string",
"display": true,
"required": false,
"displayName": "campaign_id",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "campaign_name",
"type": "string",
"display": true,
"required": false,
"displayName": "campaign_name",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "adset_id",
"type": "string",
"display": true,
"required": false,
"displayName": "adset_id",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "adset_name",
"type": "string",
"display": true,
"required": false,
"displayName": "adset_name",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "ad_id",
"type": "string",
"display": true,
"required": false,
"displayName": "ad_id",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "ad_name",
"type": "string",
"display": true,
"required": false,
"displayName": "ad_name",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "objective",
"type": "string",
"display": true,
"required": false,
"displayName": "objective",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "buying_type",
"type": "string",
"display": true,
"required": false,
"displayName": "buying_type",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "spend",
"type": "string",
"display": true,
"required": false,
"displayName": "spend",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "impressions",
"type": "string",
"display": true,
"required": false,
"displayName": "impressions",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "reach",
"type": "string",
"display": true,
"required": false,
"displayName": "reach",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "frequency",
"type": "string",
"display": true,
"required": false,
"displayName": "frequency",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "clicks",
"type": "string",
"display": true,
"required": false,
"displayName": "clicks",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "unique_clicks",
"type": "string",
"display": true,
"required": false,
"displayName": "unique_clicks",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "ctr",
"type": "string",
"display": true,
"required": false,
"displayName": "ctr",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "cpc",
"type": "string",
"display": true,
"required": false,
"displayName": "cpc",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "cpm",
"type": "string",
"display": true,
"required": false,
"displayName": "cpm",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "actions",
"type": "string",
"display": true,
"required": false,
"displayName": "actions",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "cost_per_action_type",
"type": "string",
"display": true,
"required": false,
"displayName": "cost_per_action_type",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "action_values",
"type": "string",
"display": true,
"required": false,
"displayName": "action_values",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "quality_ranking",
"type": "string",
"display": true,
"required": false,
"displayName": "quality_ranking",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "engagement_rate_ranking",
"type": "string",
"display": true,
"required": false,
"displayName": "engagement_rate_ranking",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "conversion_rate_ranking",
"type": "string",
"display": true,
"required": false,
"displayName": "conversion_rate_ranking",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "list",
"value": "gid=XXXXXXXXXX",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_SPREADSHEET_ID/edit#gid=XXXXXXXXXX",
"cachedResultName": "Account_B"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "YOUR_SPREADSHEET_ID",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_SPREADSHEET_ID/edit",
"cachedResultName": "Meta Ads Report"
}
},
"typeVersion": 4.7
},
{
"id": "2e9f737a-5e02-4b94-ad1b-fa5a3690790e",
"name": "If Spend not 0 (Account A)",
"type": "n8n-nodes-base.if",
"position": [
448,
5088
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "loose"
},
"combinator": "and",
"conditions": [
{
"id": "b51d8946-3d1d-4ec3-8c7d-75cb05824fb7",
"operator": {
"type": "number",
"operation": "notEquals"
},
"leftValue": "={{ $json.spend }}",
"rightValue": 0
}
]
},
"looseTypeValidation": true
},
"typeVersion": 2.2,
"alwaysOutputData": false
},
{
"id": "8cf7699d-cdbf-4895-8d46-8c7ddea3a274",
"name": "If Spend not 0 (Account B)",
"type": "n8n-nodes-base.if",
"position": [
432,
5808
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "loose"
},
"combinator": "and",
"conditions": [
{
"id": "b51d8946-3d1d-4ec3-8c7d-75cb05824fb7",
"operator": {
"type": "number",
"operation": "notEquals"
},
"leftValue": "={{ $json.spend }}",
"rightValue": 0
}
]
},
"looseTypeValidation": true
},
"typeVersion": 2.2,
"alwaysOutputData": false
},
{
"id": "dbe8e070-b975-4ff8-9186-01993d48219a",
"name": "Set Incremental Range (Last 7 Days)",
"type": "n8n-nodes-base.set",
"position": [
-1088,
5168
],
"parameters": {
"mode": "raw",
"options": {},
"jsonOutput": "{\n \"since\": \"={{ $now.minus(7, 'days').toISODate() }}\",\n \"until\": \"={{ $now.toISODate() }}\"\n}"
},
"typeVersion": 3.4
},
{
"id": "f3c9c2f9-626f-42fc-8308-def370158e13",
"name": "Schedule Trigger (Incremental)",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
-1312,
5168
],
"parameters": {
"rule": {
"interval": [
{
"daysInterval": 7
}
]
}
},
"typeVersion": 1.3
},
{
"id": "8509aa01-3574-459a-a965-fcd12804cd3b",
"name": "Generate Weekly Periods",
"type": "n8n-nodes-base.code",
"position": [
-928,
5728
],
"parameters": {
"jsCode": "let start = new Date($input.first().json.start_date);\nconst end = new Date($input.first().json.end_date);\n\nlet output = [];\n\nwhile (start <= end) {\n let until = new Date(start);\n until.setDate(until.getDate() + 6);\n\n // Fix: clamp until so last chunk never exceeds end_date\n if (until > end) until = new Date(end);\n\n output.push({\n since: start.toISOString().split(\"T\")[0],\n until: until.toISOString().split(\"T\")[0]\n });\n\n start.setDate(start.getDate() + 7);\n}\n\nreturn output.map(d => ({ json: d }));\n"
},
"typeVersion": 2
},
{
"id": "bd4e94e1-fba0-439d-b70f-cca3cec34d32",
"name": "Set Date Range (Historical Backfill)",
"type": "n8n-nodes-base.set",
"position": [
-1120,
5728
],
"parameters": {
"mode": "raw",
"options": {},
"jsonOutput": "{\n \"start_date\": \"2024-01-01\",\n \"end_date\": \"2024-12-31\"\n}"
},
"typeVersion": 3.4
},
{
"id": "49204618-70fc-415d-b1cc-5f87510e60d0",
"name": "Log Skipped Period (Account B)",
"type": "n8n-nodes-base.set",
"position": [
256,
6016
],
"parameters": {
"mode": "raw",
"options": {},
"jsonOutput": "{\n \"status\": \"skipped\",\n \"reason\": \"Meta API returned no data or an error for this period\",\n \"account\": \"Account B\",\n \"since\": \"={{ $('Loop Over Periods (Account B)').item.json.since }}\",\n \"until\": \"={{ $('Loop Over Periods (Account B)').item.json.until }}\",\n \"execution_id\": \"={{ $execution.id }}\",\n \"timestamp\": \"={{ new Date().toISOString() }}\"\n}"
},
"typeVersion": 3.4
}
],
"active": false,
"settings": {
"binaryMode": "separate",
"executionOrder": "v1"
},
"versionId": "a282ce38-448e-4fe4-ba6d-66d9d9a53739",
"connections": {
"Generate Weekly Periods": {
"main": [
[
{
"node": "Loop Over Periods (Account A)",
"type": "main",
"index": 0
},
{
"node": "Loop Over Periods (Account B)",
"type": "main",
"index": 0
}
]
]
},
"If Spend not 0 (Account A)": {
"main": [
[
{
"node": "Append to Sheet (Account A)",
"type": "main",
"index": 0
}
]
]
},
"If Spend not 0 (Account B)": {
"main": [
[
{
"node": "Append to Sheet (Account B)",
"type": "main",
"index": 0
}
]
]
},
"Append to Sheet (Account A)": {
"main": [
[
{
"node": "Loop Over Periods (Account A)",
"type": "main",
"index": 0
}
]
]
},
"Append to Sheet (Account B)": {
"main": [
[
{
"node": "Loop Over Periods (Account B)",
"type": "main",
"index": 0
}
]
]
},
"Valid Response? (Account A)": {
"main": [
[
{
"node": "Split API Response (Account A)",
"type": "main",
"index": 0
}
],
[
{
"node": "Log Skipped Period (Account A)",
"type": "main",
"index": 0
}
]
]
},
"Valid Response? (Account B)": {
"main": [
[
{
"node": "Split API Response (Account B)",
"type": "main",
"index": 0
}
],
[
{
"node": "Log Skipped Period (Account B)",
"type": "main",
"index": 0
}
]
]
},
"Loop Over Periods (Account A)": {
"main": [
[],
[
{
"node": "Fetch Meta Insights (Account A)",
"type": "main",
"index": 0
}
]
]
},
"Loop Over Periods (Account B)": {
"main": [
[],
[
{
"node": "Fetch Meta Insights (Account B)",
"type": "main",
"index": 0
}
]
]
},
"Log Skipped Period (Account A)": {
"main": [
[
{
"node": "Append to Log Sheet (Account A)",
"type": "main",
"index": 0
}
]
]
},
"Log Skipped Period (Account B)": {
"main": [
[
{
"node": "Append to Log Sheet (Account B)",
"type": "main",
"index": 0
}
]
]
},
"Schedule Trigger (Incremental)": {
"main": [
[
{
"node": "Set Incremental Range (Last 7 Days)",
"type": "main",
"index": 0
}
]
]
},
"Split API Response (Account A)": {
"main": [
[
{
"node": "If Spend not 0 (Account A)",
"type": "main",
"index": 0
}
]
]
},
"Split API Response (Account B)": {
"main": [
[
{
"node": "If Spend not 0 (Account B)",
"type": "main",
"index": 0
}
]
]
},
"Append to Log Sheet (Account A)": {
"main": [
[
{
"node": "Loop Over Periods (Account A)",
"type": "main",
"index": 0
}
]
]
},
"Append to Log Sheet (Account B)": {
"main": [
[
{
"node": "Loop Over Periods (Account B)",
"type": "main",
"index": 0
}
]
]
},
"Fetch Meta Insights (Account A)": {
"main": [
[
{
"node": "Valid Response? (Account A)",
"type": "main",
"index": 0
}
]
]
},
"Fetch Meta Insights (Account B)": {
"main": [
[
{
"node": "Valid Response? (Account B)",
"type": "main",
"index": 0
}
]
]
},
"Set Incremental Range (Last 7 Days)": {
"main": [
[
{
"node": "Loop Over Periods (Account A)",
"type": "main",
"index": 0
},
{
"node": "Loop Over Periods (Account B)",
"type": "main",
"index": 0
}
]
]
},
"Manual Trigger (Historical Backfill)": {
"main": [
[
{
"node": "Set Date Range (Historical Backfill)",
"type": "main",
"index": 0
}
]
]
},
"Set Date Range (Historical Backfill)": {
"main": [
[
{
"node": "Generate Weekly Periods",
"type": "main",
"index": 0
}
]
]
}
}
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This workflow provides a structured way to extract Meta Ads performance data and store it in Google Sheets for reporting, dashboarding, or further analysis.
Source: https://n8n.io/workflows/14721/ — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
This workflow acts as a junior finance research analyst for a UK boutique M&A or corporate finance team. It listens for Slack messages, classifies the request, gathers company or market data, and prod
This workflow syncs Toggl Track time entries to Google Sheets and creates monthly tabs automatically.
This template demonstrates how to build a low-code, AI-powered data analysis workflow in n8n. It enables you to connect to various data sources (such as MySQL, Google Sheets, or local files), process
AI Money Tracker Chatbot. Uses telegramTrigger, postgres, googleSheets, telegram. Event-driven trigger; 24 nodes.
This n8n workflow retrieves AI agent chat memory logs stored in Postgres and pushes them to Google Sheets, creating one sheet per session. It’s useful for teams building chat-based products or agents