Skip to content

Every 30 minutes

Create Facebook ads from rows in a sheet

Each ad you describe in a sheet row, with copy, image, audience and budget, is created in Ads Manager as a paused ad, with its ids written back.

Runs
Every 30 minutes
Apps
Facebook Pages, Google Sheets
AI
Not needed
Access
ads_management; Sheet edit

Send this to your assistant

Create a ClickRuntime automation: every 15 minutes, check my Ad Builder sheet for rows marked Ready. Create each one in my Meta ad account as a paused campaign, ad set and ad using the row's copy, image, audience and budget, and write the ad id back to the row.

Paste it into your assistant. It tells you what it will send or change before it runs live.

First time? Adding ClickRuntime to your assistant takes about two minutes.

Why use it

Why teams use this automation

A marketer tests lots of ad variations for an online course: different headlines, images and audiences. Building each one by clicking through Ads Manager takes ten minutes and invites mistakes in budgets and targeting.

Variations are now written as rows in a sheet, which is quicker to plan and easy to review with a colleague. Rows marked ready are built in Ads Manager as paused ads, so nothing spends money until the marketer checks and switches them on.

What you get out of it

  • Plan many variations quickly

    Writing rows in a sheet is much faster than clicking through Ads Manager for each version.

  • Fewer setup mistakes

    Budgets, audiences and copy are copied exactly from the row, the same way every time.

  • Nothing spends until you say so

    Every ad is created paused, so you review it in Ads Manager before turning it on.

  • Ids written back for tracking

    The sheet records which ad each row became, which makes reporting later straightforward.

How it works

What happens, step by step

  1. Every 15 minutes, ClickRuntime checks your ad sheet for rows marked Ready.

  2. It uploads each row's image to your ad account.

  3. It creates a paused campaign, ad set and ad with the row's copy, audience and budget.

  4. The new ad id is written to the row and the status changes to Created, so it's never built twice.

Before it runs live

  • Connect Facebook Pages
  • Connect your Google Sheets account and pick the spreadsheets it may use

What you get

RunsEvery 30 minutes
Create Facebook ads from rows in a sheettoday, 9:00Succeeded
Google Sheets · Ad BuilderRow 7: 'Learn Excel in a weekend' · UK · 25+ · £15/day → Created, ad 120210000000000

Build your own

Need it to work differently?

This template is a starting point. Copy the prompt and change it, or describe a different automation from scratch, with your own conditions, more apps or an AI step. Your assistant writes it, tests it and runs it on ClickRuntime.
  • Your own rules

    Conditions, thresholds, filters and exceptions, written the way you'd explain them to a colleague.

  • Any number of apps

    One automation can read from one app and update several others. Over 248 apps are ready, and anything with an API works too.

  • AI where it helps

    Summaries, classification, extraction and drafts use ClickRuntime's built-in AI, with no extra key.

  • On a schedule or on each event

    Runs as often as every 5 minutes, or the moment an app sends an event, and keeps track of what it already handled.

Changes you can ask for

  • Act only on the items that match your own rules, and skip the rest
  • Add an AI step, for example to summarize, sort or draft a reply
  • Add another app, for example also send it to Slack
  • Combine it with other Facebook Pages and Google Sheets steps into one automation

Under the hood

The code that runs this automation

This is the Python script that runs each time the automation starts. Your AI assistant writes it for you when you send the prompt, and you allow each step in your assistant. To change how the automation works, describe the change to your assistant and it updates the script for you. For every function it can use, see the script reference.
create_facebook_ads_from_a_sheet.pyexample
from google.oauth2.credentials import Credentials
from googleapiclient.discovery import build
from clickruntime import on_trigger, credentials, http, report_fetched

ACT, PAGE_ID, SHEET_ID = "act_1234567890", "1234567890", "your-spreadsheet-id"
G = f"https://graph.facebook.com/v21.0/{ACT}"

@on_trigger
def run(event):
    values = build("sheets", "v4", credentials=Credentials(credentials.connection("google", "work")), cache_discovery=False).spreadsheets().values()
    rows = values.get(spreadsheetId=SHEET_ID, range="Ads!A2:I").execute().get("values", [])
    ready = [(i + 2, r) for i, r in enumerate(rows) if len(r) >= 9 and r[8] == "Ready"]
    report_fetched(len(ready))
    if not ready:
        return {"summary": "No ready rows"}
    t = {"access_token": credentials.connection("facebook", "work")}
    for n, (name, headline, text, image, link, budget, country, age, _) in ready:
        img = http.post(f"{G}/adimages", data={**t, "url": image}).json()["images"]
        camp = http.post(f"{G}/campaigns", data={**t, "name": name, "objective": "OUTCOME_TRAFFIC", "status": "PAUSED", "special_ad_categories": "[]"}).json()["id"]
        adset = http.post(f"{G}/adsets", data={**t, "name": name, "campaign_id": camp, "daily_budget": int(float(budget) * 100), "billing_event": "IMPRESSIONS",
                          "optimization_goal": "LINK_CLICKS", "status": "PAUSED", "targeting": f'{{"geo_locations":{{"countries":["{country}"]}},"age_min":{age}}}'}).json()["id"]
        story = {"page_id": PAGE_ID, "link_data": {"link": link, "message": text, "name": headline, "image_hash": next(iter(img.values()))["hash"]}}
        creative = http.post(f"{G}/adcreatives", json={**t, "object_story_spec": story}).json()["id"]
        ad = http.post(f"{G}/ads", data={**t, "name": name, "adset_id": adset, "creative": f'{{"creative_id":"{creative}"}}', "status": "PAUSED"}).json()["id"]
        values.update(spreadsheetId=SHEET_ID, range=f"Ads!I{n}:J{n}", valueInputOption="RAW", body={"values": [["Created", ad]]}).execute()
    return {"created": len(ready)}

FAQ

Common questions

What does each row need?
A campaign name, headline, primary text, image URL, link, daily budget and an audience such as country and age range.
Why are ads created paused?
So nothing spends money until you've reviewed it. Turn each one on in Ads Manager when you're happy.
What happens if Meta rejects something?
The error is written to the row, such as a budget below the minimum, and the row stays unprocessed until you fix it.
What permissions does it need?
ads_management; Sheet edit. Nothing else in your accounts is used.
Does it need AI?
No. It runs without AI, so it doesn't use your plan's AI allowance.
How many runs does it use?
One run each time it checks. Checks that find nothing new and stop right away aren't counted.
Can I change how it works?
Yes. Describe the change to your AI assistant, for example a different schedule, channel or filter. It updates the automation, tests it and tells you what changed.

Set up “Create Facebook ads from rows in a sheet” from your assistant

Copy the prompt above, or connect your assistant first. Free plan, no credit card.