AutomationFlowsData & Sheets › Sync Meta Ads Insights to Google Sheets

Sync Meta Ads Insights to Google Sheets

Original n8n title: Sync Meta Ads Insights to Google Sheets with Backfill and Weekly ETL

ByMuh Resky Adiansyah @adiardian on n8n.io

This workflow provides a structured way to extract Meta Ads performance data and store it in Google Sheets for reporting, dashboarding, or further analysis.

Event trigger★★★★☆ complexity24 nodesGoogle SheetsHTTP Request
Data & Sheets Trigger: Event Nodes: 24 Complexity: ★★★★☆ Added:
Sync Meta Ads Insights to Google Sheets — n8n workflow card showing Google Sheets, HTTP Request integration

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 →

Download .json
{
  "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
          }
        ]
      ]
    }
  }
}
Pro

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 →

More Data & Sheets workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

Data & Sheets

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

HTTP Request, Google Drive, Google Docs +5
Data & Sheets

This workflow syncs Toggl Track time entries to Google Sheets and creates monthly tabs automatically.

HTTP Request, Google Sheets
Data & Sheets

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

MySQL, Google Sheets, Read Write File +2
Data & Sheets

AI Money Tracker Chatbot. Uses telegramTrigger, postgres, googleSheets, telegram. Event-driven trigger; 24 nodes.

Telegram Trigger, Postgres, Google Sheets +2
Data & Sheets

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

Postgres, HTTP Request, Google Sheets