AutomationFlowsSocial Media › Create Facebook Ad Sets and Ads From Google Sheets Rows

Create Facebook Ad Sets and Ads From Google Sheets Rows

ByDr. Firas @drfiras on n8n.io

This workflow watches a Google Sheets queue and, when a row is flagged, uses the Meta (Facebook) Graph API to create an ad set, upload an image from a URL, build an ad creative, and create a paused ad, then writes the result or errors back to the sheet. Polls Google Sheets every…

Event trigger★★★★☆ complexity16 nodesGoogle Sheets TriggerFacebook Graph ApiGoogle Sheets
Social Media Trigger: Event Nodes: 16 Complexity: ★★★★☆ Added:

This workflow corresponds to n8n.io template #17897 — we link there as the canonical source.

This workflow follows the Facebookgraphapi → Google Sheets 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": "rYAWl7zx5rK3nUzt",
  "meta": {
    "builderVariant": "mcp",
    "aiBuilderAssisted": true
  },
  "name": "Generate Facebook ad sets and ads from Google Sheets rows",
  "tags": [],
  "nodes": [
    {
      "id": "b8294a2c-1f40-4b3c-8d20-2d1f41646924",
      "name": "Watch Ad Rows in Google Sheets",
      "type": "n8n-nodes-base.googleSheetsTrigger",
      "position": [
        16,
        432
      ],
      "parameters": {
        "event": "rowUpdate",
        "options": {},
        "pollTimes": {
          "item": [
            {
              "mode": "everyX",
              "unit": "minutes",
              "value": 5
            }
          ]
        },
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultName": "Facebook Ads Queue"
        }
      },
      "credentials": {
        "googleSheetsTriggerOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "898faa4e-add2-4536-b681-32252030b9f5",
      "name": "Check Row Marked For Generation",
      "type": "n8n-nodes-base.if",
      "position": [
        320,
        432
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 1,
            "leftValue": "",
            "caseSensitive": false,
            "typeValidation": "loose"
          },
          "combinator": "and",
          "conditions": [
            {
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $('Watch Ad Rows in Google Sheets').item.json['Generate Ad'] }}",
              "rightValue": "generate"
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "c4c5588d-1859-43fa-ae32-762ce80b488a",
      "name": "Configuration",
      "type": "n8n-nodes-base.set",
      "position": [
        752,
        416
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "hooks",
              "name": "hooks",
              "type": "string",
              "value": "={{ $('Watch Ad Rows in Google Sheets').item.json['Hooks'] }}"
            },
            {
              "id": "render_url",
              "name": "render_url",
              "type": "string",
              "value": "={{ $('Watch Ad Rows in Google Sheets').item.json['Render URL'] }}"
            },
            {
              "id": "row_number",
              "name": "row_number",
              "type": "number",
              "value": "={{ $('Watch Ad Rows in Google Sheets').item.json.row_number }}"
            },
            {
              "id": "facebook_ad_account_id",
              "name": "facebook_ad_account_id",
              "type": "string",
              "value": "<__PLACEHOLDER_VALUE__Your Facebook Ad Account ID, including the act_ prefix (e.g. act_1234567890)__>"
            },
            {
              "id": "facebook_page_id",
              "name": "facebook_page_id",
              "type": "string",
              "value": "<__PLACEHOLDER_VALUE__Your Facebook Page ID__>"
            },
            {
              "id": "campaign_id",
              "name": "campaign_id",
              "type": "string",
              "value": "<__PLACEHOLDER_VALUE__Existing Facebook campaign ID this ad set will belong to__>"
            },
            {
              "id": "pixel_id",
              "name": "pixel_id",
              "type": "string",
              "value": "<__PLACEHOLDER_VALUE__Optional: Meta Pixel ID for conversion tracking (leave blank if unused)__>"
            },
            {
              "id": "custom_event_type",
              "name": "custom_event_type",
              "type": "string",
              "value": "PURCHASE"
            },
            {
              "id": "graph_api_version",
              "name": "graph_api_version",
              "type": "string",
              "value": "v21.0"
            },
            {
              "id": "daily_budget_cents",
              "name": "daily_budget_cents",
              "type": "number",
              "value": 1000
            },
            {
              "id": "age_min",
              "name": "age_min",
              "type": "number",
              "value": 18
            },
            {
              "id": "age_max",
              "name": "age_max",
              "type": "number",
              "value": 65
            },
            {
              "id": "target_genders",
              "name": "target_genders",
              "type": "array",
              "value": "={{ [1, 2] }}"
            },
            {
              "id": "target_countries",
              "name": "target_countries",
              "type": "array",
              "value": "={{ [\"US\"] }}"
            },
            {
              "id": "optimization_goal",
              "name": "optimization_goal",
              "type": "string",
              "value": "LINK_CLICKS"
            },
            {
              "id": "billing_event",
              "name": "billing_event",
              "type": "string",
              "value": "IMPRESSIONS"
            },
            {
              "id": "bid_strategy",
              "name": "bid_strategy",
              "type": "string",
              "value": "LOWEST_COST_WITHOUT_CAP"
            },
            {
              "id": "destination_url",
              "name": "destination_url",
              "type": "string",
              "value": "<__PLACEHOLDER_VALUE__https://yourwebsite.com/landing-page__>"
            },
            {
              "id": "cta_type",
              "name": "cta_type",
              "type": "string",
              "value": "LEARN_MORE"
            },
            {
              "id": "ad_set_name_prefix",
              "name": "ad_set_name_prefix",
              "type": "string",
              "value": "AI Generated Ad Set"
            },
            {
              "id": "ad_status",
              "name": "ad_status",
              "type": "string",
              "value": "PAUSED"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "0e058c90-1b04-471c-bc08-77a35168c26c",
      "name": "Create Facebook Ad Set",
      "type": "n8n-nodes-base.facebookGraphApi",
      "onError": "continueErrorOutput",
      "maxTries": 3,
      "position": [
        944,
        352
      ],
      "parameters": {
        "edge": "adsets",
        "node": "={{ $('Configuration').item.json.facebook_ad_account_id }}",
        "options": {
          "queryParametersJson": "={{\n  // Build the ad set payload from the Configuration node.\n  (() => {\n    const cfg = $(\"Configuration\").item.json;\n    const targeting = {\n      age_min: cfg.age_min,\n      age_max: cfg.age_max,\n      genders: cfg.target_genders,\n      geo_locations: { countries: cfg.target_countries }\n    };\n    const payload = {\n      name: cfg.ad_set_name_prefix + \" - \" + String(cfg.hooks).slice(0, 40),\n      campaign_id: cfg.campaign_id,\n      daily_budget: cfg.daily_budget_cents,\n      billing_event: cfg.billing_event,\n      optimization_goal: cfg.optimization_goal,\n      bid_strategy: cfg.bid_strategy,\n      targeting: JSON.stringify(targeting),\n      status: cfg.ad_status\n    };\n    if (cfg.pixel_id) {\n      payload.promoted_object = JSON.stringify({ pixel_id: cfg.pixel_id, custom_event_type: cfg.custom_event_type });\n    }\n    return payload;\n  })()\n}}"
        },
        "graphApiVersion": "={{ $('Configuration').item.json.graph_api_version }}",
        "httpRequestMethod": "POST"
      },
      "retryOnFail": true,
      "typeVersion": 1,
      "waitBetweenTries": 5000
    },
    {
      "id": "824f92a9-4e62-4a53-899d-b3ac4c8e9f4f",
      "name": "Upload Ad Image to Facebook",
      "type": "n8n-nodes-base.facebookGraphApi",
      "onError": "continueErrorOutput",
      "maxTries": 3,
      "position": [
        1184,
        336
      ],
      "parameters": {
        "edge": "adimages",
        "node": "={{ $('Configuration').item.json.facebook_ad_account_id }}",
        "options": {
          "queryParameters": {
            "parameter": [
              {
                "name": "url",
                "value": "={{ $('Configuration').item.json.render_url }}"
              }
            ]
          }
        },
        "graphApiVersion": "={{ $('Configuration').item.json.graph_api_version }}",
        "httpRequestMethod": "POST"
      },
      "retryOnFail": true,
      "typeVersion": 1,
      "waitBetweenTries": 5000
    },
    {
      "id": "acef61f2-5ff9-44c7-9945-da3fb8113c55",
      "name": "Create Facebook Ad Creative",
      "type": "n8n-nodes-base.facebookGraphApi",
      "onError": "continueErrorOutput",
      "maxTries": 3,
      "position": [
        1472,
        320
      ],
      "parameters": {
        "edge": "adcreatives",
        "node": "={{ $('Configuration').item.json.facebook_ad_account_id }}",
        "options": {
          "queryParametersJson": "={{\n  // Build the ad creative payload, pulling the uploaded image hash.\n  (() => {\n    const cfg = $(\"Configuration\").item.json;\n    const imagesObj = $(\"Upload Ad Image to Facebook\").item.json.images || {};\n    const firstImage = Object.values(imagesObj)[0];\n    const imageHash = firstImage ? firstImage.hash : \"\";\n    const story = {\n      page_id: cfg.facebook_page_id,\n      link_data: {\n        message: cfg.hooks,\n        link: cfg.destination_url,\n        image_hash: imageHash,\n        call_to_action: { type: cfg.cta_type, value: { link: cfg.destination_url } }\n      }\n    };\n    return {\n      name: \"AI Creative - \" + String(cfg.hooks).slice(0, 40),\n      object_story_spec: JSON.stringify(story)\n    };\n  })()\n}}"
        },
        "graphApiVersion": "={{ $('Configuration').item.json.graph_api_version }}",
        "httpRequestMethod": "POST"
      },
      "retryOnFail": true,
      "typeVersion": 1,
      "waitBetweenTries": 5000
    },
    {
      "id": "9156c0c2-570b-4143-9f8a-2f8134d37143",
      "name": "Create Facebook Ad",
      "type": "n8n-nodes-base.facebookGraphApi",
      "onError": "continueErrorOutput",
      "maxTries": 3,
      "position": [
        1872,
        304
      ],
      "parameters": {
        "edge": "ads",
        "node": "={{ $('Configuration').item.json.facebook_ad_account_id }}",
        "options": {
          "queryParametersJson": "={{\n  (() => {\n    const cfg = $(\"Configuration\").item.json;\n    return {\n      name: \"AI Ad - \" + String(cfg.hooks).slice(0, 40),\n      adset_id: $(\"Create Facebook Ad Set\").item.json.id,\n      creative: JSON.stringify({ creative_id: $(\"Create Facebook Ad Creative\").item.json.id }),\n      status: cfg.ad_status\n    };\n  })()\n}}"
        },
        "graphApiVersion": "={{ $('Configuration').item.json.graph_api_version }}",
        "httpRequestMethod": "POST"
      },
      "retryOnFail": true,
      "typeVersion": 1,
      "waitBetweenTries": 5000
    },
    {
      "id": "80ce5e54-06ac-44e6-8724-bb20f218fefc",
      "name": "Update Sheet - Ad Generated",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        2176,
        368
      ],
      "parameters": {
        "operation": "update",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultName": "Facebook Ads Queue"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "9ea2f084-9d80-41e5-b168-8840089b7881",
      "name": "Combine Ad Creation Errors",
      "type": "n8n-nodes-base.merge",
      "position": [
        1536,
        736
      ],
      "parameters": {
        "numberInputs": 4
      },
      "typeVersion": 3.2
    },
    {
      "id": "ccdeffd2-e7d3-46d2-bf28-d0898d5919d7",
      "name": "Skip - Not Marked For Generation",
      "type": "n8n-nodes-base.noOp",
      "position": [
        560,
        448
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "01eaacd4-4fb0-4164-9df4-408f2d5f3156",
      "name": "Update Sheet - Generation Error",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1776,
        464
      ],
      "parameters": {
        "operation": "update",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultName": "Facebook Ads Queue"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "4d72f201-1ab7-4da5-9d03-817305a38f1a",
      "name": "Overview & Documentation",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -608,
        -144
      ],
      "parameters": {
        "color": 4,
        "width": 460,
        "height": 1572,
        "content": "# Generate Facebook ad sets and ads from Google Sheets rows\n# \ud83d\udce5 [Open full documentation on Notion](https://automatisation.notion.site/Course-Generate-Facebook-ad-sets-and-ads-from-Google-Sheets-rows-3a03d6550fd981ca954febe5dd9e7c49)\n\n## How it works\nUpdate a row in a Google Sheet (Hooks + Render URL + set \"Generate Ad\" to generate) and this workflow automatically creates a Facebook ad set, uploads the creative image, builds an ad creative, and launches a paused ad - then writes the result back into the sheet.\n\n## Setup\n1. Copy the Google Sheet template (columns: Hooks, Render URL, Generate Ad, Ad ID, Error Message).\n2. Connect your Google Sheets credential and pick your sheet on the trigger and both Update nodes.\n3. Create a Facebook Graph API credential (long-lived access token) and select it on the 4 Facebook nodes.\n4. Open the Configuration node and fill in your Ad Account ID, Page ID, Campaign ID and targeting defaults.\n\n## Requirements\n- A configured Facebook Business account, App, Page and Ad Account\n- A Facebook Graph API access token with ads_management permission\n- Real advertising costs apply once ads are unpaused in Ads Manager\n\n## Customization\n- Add interest-based targeting via a flexible_spec array in the Ad Set payload\n- Swap the single-image creative for a carousel or video creative\n- Wire a Telegram or Gmail node on the error branch for real-time alerts\n\nNeed help customizing?\nContact me for consulting and support : [Linkedin](https://www.linkedin.com/in/doctor-firass/)\n\n# MY NEW YOUTUBE CHANNEL\n\ud83d\udc49 [Subscribe to my new YouTube channel](https://www.youtube.com/@DrFiras_AI). Here I'll share videos and Shorts with practical tutorials and FREE templates for n8n.\n\n[![The AI Doctor](https://www.dr-firas.com/the-ai-doctor.png)](https://www.youtube.com/@DrFiras_AI)"
      },
      "typeVersion": 1
    },
    {
      "id": "b39d4f19-0da5-4cf3-b11e-361f08fff8d5",
      "name": "Sticky Note 4fccdb14",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -48,
        256
      ],
      "parameters": {
        "color": 7,
        "width": 556,
        "height": 380,
        "content": "### 1. Watch for rows ready to generate\nPolls the sheet and only continues when \"Generate Ad\" is set to generate."
      },
      "typeVersion": 1
    },
    {
      "id": "df466c2d-38c5-478d-9d16-97125ac188e1",
      "name": "Sticky Note fe06719a",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        608,
        80
      ],
      "parameters": {
        "color": 7,
        "width": 300,
        "height": 232,
        "content": "### 2. Configuration\nEvery adjustable value lives here: Ad Account, Page, Campaign, targeting defaults, budget, CTA and ad status (defaults to PAUSED for safety)."
      },
      "typeVersion": 1
    },
    {
      "id": "b0e4bfc5-1dea-4842-8af6-7ee3470e20f3",
      "name": "Sticky Note 48b8f0e2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        944,
        80
      ],
      "parameters": {
        "color": 7,
        "width": 1044,
        "height": 200,
        "content": "### 3. Build & launch the ad\nCreates the ad set, uploads the image (Facebook fetches it directly from the Render URL), builds the creative, then creates the ad."
      },
      "typeVersion": 1
    },
    {
      "id": "6cb0c3cd-6470-4faa-9033-acf5509aa7f2",
      "name": "Sticky Note 8c358af9",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2048,
        160
      ],
      "parameters": {
        "color": 7,
        "width": 476,
        "height": 480,
        "content": "### 4. Write the result back\nSuccess writes the Ad ID and marks the row generated; any failure marks the row error with the message."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "availableInMCP": true,
    "executionOrder": "v1"
  },
  "versionId": "d0b8653f-99dc-4a49-9071-0137f34d9b3a",
  "nodeGroups": [],
  "connections": {
    "Configuration": {
      "main": [
        [
          {
            "node": "Create Facebook Ad Set",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create Facebook Ad": {
      "main": [
        [
          {
            "node": "Update Sheet - Ad Generated",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Combine Ad Creation Errors",
            "type": "main",
            "index": 3
          }
        ]
      ]
    },
    "Create Facebook Ad Set": {
      "main": [
        [
          {
            "node": "Upload Ad Image to Facebook",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Combine Ad Creation Errors",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Combine Ad Creation Errors": {
      "main": [
        [
          {
            "node": "Update Sheet - Generation Error",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create Facebook Ad Creative": {
      "main": [
        [
          {
            "node": "Create Facebook Ad",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Combine Ad Creation Errors",
            "type": "main",
            "index": 2
          }
        ]
      ]
    },
    "Upload Ad Image to Facebook": {
      "main": [
        [
          {
            "node": "Create Facebook Ad Creative",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Combine Ad Creation Errors",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Watch Ad Rows in Google Sheets": {
      "main": [
        [
          {
            "node": "Check Row Marked For Generation",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check Row Marked For Generation": {
      "main": [
        [
          {
            "node": "Configuration",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Skip - Not Marked For Generation",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}

Credentials you'll need

Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.

Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

This workflow watches a Google Sheets queue and, when a row is flagged, uses the Meta (Facebook) Graph API to create an ad set, upload an image from a URL, build an ad creative, and create a paused ad, then writes the result or errors back to the sheet. Polls Google Sheets every…

Source: https://n8n.io/workflows/17897/ — original creator credit. Request a take-down →

More Social Media workflows → · Browse all categories →

Related workflows

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

Social Media

This workflow is a universal automation for all four Meta Detailed Targeting API endpoints: Search, Suggestions, Browse, and Validation. You use a single Google Sheets tab with an column; a Switch nod

Google Sheets, Facebook Graph Api, Google Sheets Trigger
Social Media

d27-FB-post. Uses googleSheets, googleDrive, googleSheetsTrigger, facebookGraphApi. Event-driven trigger; 8 nodes.

Google Sheets, Google Drive, Google Sheets Trigger +2
Social Media

This template is designed for Marketing Managers, Performance Marketers, and Ad Ops professionals who want to automate Facebook ad creation using structured data in Google Sheets. It’s ideal for teams

HTTP Request, Facebook Graph Api, Google Sheets Trigger +1
Social Media

This n8n workflow template automates the entire process of publishing Instagram Reels from content stored in Google Sheets and Google Drive. It's designed for content creators, social media managers,

Agent, Airtable, Facebook Graph Api +8
Social Media

This n8n workflow automates the process of uploading video and image advertisements to Meta Ads Manager via the Meta Graph API (Facebook Ads) directly from Google Sheets and Google Drive. The workflow

Facebook Graph Api, Google Sheets, HTTP Request +2