Meta Ads Library to Google Sheets, track rivals fast
You check the Meta Ads Library, spot something interesting, and then… you lose it. Or you forget which ads you already logged. Or you “save it for later” and later never happens.
Meta ads tracking hits performance marketers the hardest, honestly. But agency owners building swipe files and founders watching bigger rivals feel the same drag in their week. This workflow gives you a clean Google Sheet that stays updated, plus a quick Telegram ping when something new shows up.
Below you’ll see how the automation works, what it logs, what you’ll need to run it, and what kind of “time back” you can expect once it’s on a schedule.
How This Automation Works
The full n8n workflow, from trigger to final output:
n8n Workflow Template: Meta Ads Library to Google Sheets, track rivals fast
flowchart LR
subgraph sg0["Schedule Flow"]
direction LR
n0@{ icon: "mdi:play-circle", form: "rounded", label: "Schedule Trigger", pos: "b", h: 48 }
n1["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/httprequest.dark.svg' width='40' height='40' /></div><br/>Facebook Ads API by page"]
n2["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/httprequest.dark.svg' width='40' height='40' /></div><br/>Facebook Ads API by keywords"]
n3@{ icon: "mdi:swap-horizontal", form: "rounded", label: "Page or keywords", pos: "b", h: 48 }
n4@{ icon: "mdi:swap-horizontal", form: "rounded", label: "If", pos: "b", h: 48 }
n5["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/code.svg' width='40' height='40' /></div><br/>Check the pagination"]
n6["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/httprequest.dark.svg' width='40' height='40' /></div><br/>Facebook Ads API pagination"]
n7@{ icon: "mdi:swap-vertical", form: "rounded", label: "Set Next URL", pos: "b", h: 48 }
n8["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/telegram.svg' width='40' height='40' /></div><br/>Send a text message"]
n9["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/code.svg' width='40' height='40' /></div><br/>Collect ID list"]
n10@{ icon: "mdi:database", form: "rounded", label: "Read existing IDs", pos: "b", h: 48 }
n11["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/merge.svg' width='40' height='40' /></div><br/>Attach existing ids"]
n12["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/code.svg' width='40' height='40' /></div><br/>Filter new creatives"]
n13["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/code.svg' width='40' height='40' /></div><br/>Count new ads"]
n14@{ icon: "mdi:swap-horizontal", form: "rounded", label: "Any new ads?", pos: "b", h: 48 }
n15@{ icon: "mdi:swap-vertical", form: "rounded", label: "Add parameters", pos: "b", h: 48 }
n16@{ icon: "mdi:database", form: "rounded", label: "Add to sheet", pos: "b", h: 48 }
n17@{ icon: "mdi:swap-vertical", form: "rounded", label: "Split Out", pos: "b", h: 48 }
n18["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/slack.svg' width='40' height='40' /></div><br/>Send a message"]
n4 --> n7
n17 --> n16
n17 --> n13
n14 --> n8
n14 --> n18
n7 --> n6
n13 --> n14
n15 --> n10
n15 --> n3
n9 --> n11
n3 --> n1
n3 --> n2
n0 --> n15
n10 --> n9
n11 --> n12
n5 --> n4
n5 --> n11
n12 --> n17
n1 --> n5
n6 --> n5
n2 --> n5
end
%% Styling
classDef trigger fill:#e8f5e9,stroke:#388e3c,stroke-width:2px
classDef ai fill:#e3f2fd,stroke:#1976d2,stroke-width:2px
classDef aiModel fill:#e8eaf6,stroke:#3f51b5,stroke-width:2px
classDef decision fill:#fff8e1,stroke:#f9a825,stroke-width:2px
classDef database fill:#fce4ec,stroke:#c2185b,stroke-width:2px
classDef api fill:#fff3e0,stroke:#e65100,stroke-width:2px
classDef code fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px
classDef disabled stroke-dasharray: 5 5,opacity: 0.5
class n0 trigger
class n3,n4,n14 decision
class n10,n16 database
class n1,n2,n6 api
class n5,n9,n12,n13 code
classDef customIcon fill:none,stroke:none
class n1,n2,n5,n6,n8,n9,n11,n12,n13,n18 customIcon
The Problem: Competitor ad tracking turns into busywork
Checking the Meta Ads Library is deceptively expensive. It starts as “just a quick look,” then turns into tabs, screenshots, notes, and a half-baked spreadsheet you never trust. You also can’t tell what’s actually new, so you waste time re-reviewing the same creatives and still miss fresh tests that launched yesterday. And once you’re tracking more than one competitor page, it gets messy fast. People stop doing it consistently, which makes the whole practice kind of pointless.
The friction compounds. Here’s where it breaks down.
- You end up re-checking the same ads because nothing marks what you’ve already captured.
- Manual logging invites errors, like pasting the wrong snapshot URL or missing the ad creation time.
- Competitor monitoring becomes “whenever I remember,” so you miss early signals on new angles and offers.
- Even if you do log ads, duplicates slowly poison the sheet and make it hard to search later.
The Solution: Auto-log new Meta creatives and alert you
This n8n workflow runs on a schedule and pulls the latest creatives from the Meta Ads Library for a specific competitor page (or, optionally, a keyword-based search). It fetches all results, including multiple pages of data, so you’re not stuck with whatever the first API response returns. Then it compares each ad’s unique id against the IDs already stored in your Google Sheet, which means it only logs ads you haven’t seen before. New items are appended (or updated safely using the id as the matching key), and you get a simple Telegram notification telling you how many new ads appeared. No spammy list of ads. Just a heads-up and a link back to your sheet.
The workflow starts with a scheduled trigger. It calls the Ads Library API, follows pagination until there’s no “next” link, and normalizes the response into a clean list. Finally, it writes only fresh creatives to Google Sheets and sends Telegram (and Slack, if you want that channel too) when there’s something worth looking at.
What You Get: Automation vs. Results
| What This Workflow Automates | Results You’ll Get |
|---|---|
|
|
Example: What This Looks Like
Say you track 3 competitors and you check each one every weekday. If each check takes about 10 minutes (open Ads Library, scan, click into ads, copy links), that’s roughly 30 minutes a day, or about 2.5 hours a week. With this workflow, you set a daily schedule and spend maybe 5 minutes reviewing only the new rows that landed in Google Sheets. So you get about 2 hours back weekly, and the tracking actually stays consistent.
What You’ll Need
- n8n instance (try n8n Cloud free)
- Self-hosting option if you prefer (Hostinger works well)
- Google Sheets for the running creative log.
- Meta Ads Library API access to fetch competitor creatives.
- Telegram to receive “new ads found” notifications.
- Meta access token (get it from Meta for Developers / Graph API tools).
Skill level: Intermediate. You’ll paste an API token, edit a few fields like page IDs and sheet names, and test one full run.
Don’t want to set this up yourself? Talk to an automation expert (free 15-minute consultation).
How It Works
A schedule kicks things off. n8n runs this on whatever cadence you choose (daily is common), then loads your input settings like competitor page IDs, target countries, and access token.
Meta Ads Library is queried and fully collected. The workflow hits the Meta endpoint via HTTP Request and keeps following the “next page” link until there are no more pages. That’s the part most manual processes miss, so your tracking quietly becomes incomplete.
Your sheet becomes the “memory.” It reads the existing ad IDs from Google Sheets, merges that list with the fresh Ads Library response, and filters out anything you’ve already logged. It even guards against duplicates inside the same batch.
Only new creatives get written and summarized. New ads are appended (or updated) into Google Sheets with fields like creation time, page name, creative text, snapshot URL, languages, platforms, and link fields. Then a counter totals how many new items were added so Telegram (and Slack) can notify you only when it matters.
You can easily modify the tracked fields to match your swipe-file style (for example, add a “hook” column or a “notes” column) based on your needs. See the full implementation guide below for customization options.
Step-by-Step Implementation Guide
Step 1: Configure the Schedule Trigger
Set the workflow to run on a schedule so it can periodically check the Facebook Ads Library.
- Add or open Scheduled Starter.
- Configure the schedule rule to match your desired interval (for example, daily). The current rule is set with an empty interval, so define a specific cadence.
- Confirm Scheduled Starter connects to Define Input Fields as the first processing step.
Step 2: Connect Google Sheets and Define Input Variables
This step prepares input parameters and loads existing ad IDs for de-duplication.
- Open Define Input Fields and set the assignments: ad_active_status to
active, search_page_ids to[YOUR_ID], ad_reached_countries toUS,AU,NZ,CA, keywords to an empty string, and access_token to[CONFIGURE_YOUR_TOKEN]. - Note the parallel split: Define Input Fields outputs to both Retrieve Stored IDs and Route Pages or Terms in parallel.
- Open Retrieve Stored IDs and select the target spreadsheet: documentId
[YOUR_ID]and sheetNamegid=0, with range set toJ:J. - Credential Required: Connect your googleSheetsOAuth2Api credentials in Retrieve Stored IDs.
- Ensure Retrieve Stored IDs connects to Compile ID Registry.
⚠️ Common Pitfall: The placeholders [YOUR_ID] and [CONFIGURE_YOUR_TOKEN] must be replaced with real values, or the workflow will fetch no ads.
Step 3: Configure Ad Fetching and Pagination Logic
Set up the routing and API calls to pull ads by page or keyword and handle pagination.
- In Route Pages or Terms, confirm the rule that checks
{{$json.search_page_ids}}and routes to the “pages” output when not empty. - Open Fetch Ads by Page and set the url to
=https://graph.facebook.com/v22.0/ads_archive?ad_active_status={{ $json.ad_active_status }}&search_page_ids={{ $json.search_page_ids }}&ad_reached_countries={{ $json.ad_reached_countries }}&fields=ad_creation_time,ad_creative_bodies,ad_creative_link_captions, ad_creative_link_descriptions,ad_creative_link_titles,ad_delivery_start_time, ad_snapshot_url, languages, page_name,publisher_platforms&limit=50&access_token={{ $json.access_token }}. - Credential Required: Connect your httpHeaderAuth credentials in Fetch Ads by Page.
- Open Fetch Ads by Keyword and set the url to
=https://graph.facebook.com/v22.0/ads_archive?ad_active_status={{ $json.ad_active_status }}&search_page_ids={{ $json.search_page_ids }}&ad_reached_countries=US,CA&fields=ad_creation_time,ad_creative_bodies,ad_creative_link_captions, ad_creative_link_descriptions,ad_creative_link_titles,ad_delivery_start_time, ad_snapshot_url, languages, page_name,publisher_platforms&access_token={{ $json.access_token }}. - Credential Required: Connect your httpHeaderAuth credentials in Fetch Ads by Keyword.
- Confirm Normalize & Pagination Check runs after both fetch nodes and that it outputs to Next Page? and Combine Existing IDs in parallel.
- In Next Page?, ensure the condition checks
{{$json.next_url}}for not empty. If true, it flows to Prepare Next Link, which sets url to{{$json.next_url}}and then triggers Paginated Ads Request. - In Paginated Ads Request, keep the url value as
{{$json.url}}to retrieve subsequent pages.
Keep the pagination flow intact: Normalize & Pagination Check → Next Page? → Prepare Next Link → Paginated Ads Request → back to Normalize & Pagination Check.
Step 4: Deduplicate Ads and Append to Google Sheets
This stage merges stored IDs with new results, isolates fresh creatives, and writes them to your sheet.
- Verify Compile ID Registry receives data from Retrieve Stored IDs and outputs to Combine Existing IDs.
- Ensure Combine Existing IDs uses mode
combineand combineBycombineAll. - Check Isolate Fresh Creatives follows Combine Existing IDs and retains only ads whose IDs are not in
existingIds. - Confirm Expand Items splits fieldToSplitOut to
dataand includes include set toallOtherFields. - Expand Items outputs to both Append to Sheet and Count New Records in parallel.
- Open Append to Sheet, set operation to
appendOrUpdate, and map columns using the existing expressions like{{$json.data.id}},{{$json.data.page_name}}, and{{$json.data.ad_snapshot_url}}. - Credential Required: Connect your googleSheetsOAuth2Api credentials in Append to Sheet.
Step 5: Configure Notifications for New Ads
When new ads are found, the workflow sends alerts to Telegram and Slack.
- Open Count New Records to ensure it returns newCount based on
items.length. - In Check for New Ads, confirm the condition is
{{$json.newCount}}gt0. - Validate the parallel branch: Check for New Ads outputs to both Telegram Notification and Slack Channel Alert in parallel.
- In Telegram Notification, set text to
=Hello! {{$json.newCount}} of ads were found today! You can see full list here — [YOUR_ID]and chatId to[YOUR_ID]. - Credential Required: Connect your telegramApi credentials in Telegram Notification.
- In Slack Channel Alert, set text to
=Hello! {{$json.newCount}} of ads were found today! You can see full list here — [YOUR_ID]and choose the target channel.
⚠️ Common Pitfall: Replace all [YOUR_ID] placeholders in notifications with real channel IDs or URLs to avoid sending broken links.
Step 6: Test and Activate Your Workflow
Run a manual test and then enable the workflow to monitor ads on schedule.
- Click Execute Workflow to run from Scheduled Starter and watch data flow into Append to Sheet and notification nodes.
- Confirm successful execution by checking that new rows appear in the Google Sheet and that Telegram Notification or Slack Channel Alert fires when newCount is greater than
0. - Once validated, toggle the workflow to Active so it runs on the configured schedule.
Common Gotchas
- Meta Ads (HTTP Header Auth) credentials can expire or lack the right access. If things break, check your long-lived access token and Meta app permissions first.
- If you’re using Wait nodes or external rendering, processing times vary. Bump up the wait duration if downstream nodes fail on empty responses.
- Google Sheets “appendOrUpdate” only stays clean if your matching column is correct. Confirm the id field is included in matchingColumns, or you’ll accidentally create duplicates.
Frequently Asked Questions
About 30 minutes if your token and sheet are ready.
No coding required. You’ll mostly edit the Set node values (page IDs, countries, and the sheet destination) and run a test.
Yes. n8n has a free self-hosted option and a free trial on n8n Cloud. Cloud plans start at $20/month for higher volume. You’ll also need to factor in Meta API usage (usually minimal for scheduled checks) and any optional AI costs if you extend the workflow with OpenAI.
Two options: n8n Cloud (managed, easiest setup) or self-hosting on a VPS. For self-hosting, Hostinger VPS is affordable and handles n8n well. Self-hosting gives you unlimited executions but requires basic server management.
Yes, but you’ll want to do it intentionally. The simplest approach is to turn search_page_ids into a list and loop over it so each competitor is fetched, normalized, and checked against your existing ID registry. Many teams also add a “competitor” column in Google Sheets so filtering is painless later. If you’d rather avoid looping, you can also run separate scheduled workflows per competitor page and write to the same sheet.
Most often it’s an expired Google authorization or the spreadsheet was moved to a different account. Reconnect the Google Sheets credential in n8n, then double-check the documentId and sheetName in both “Retrieve Stored IDs” and “Append to Sheet.” If the workflow runs but writes nothing, your column mapping may not match your sheet headers, especially the id column used for matching.
Practically speaking, hundreds to thousands per run is fine for most setups, because pagination is built in and Google Sheets writes one row per new ad. On n8n Cloud Starter, you’re mainly limited by monthly executions; on self-hosted n8n, there’s no execution cap and it mostly depends on your server and Google API limits. If you expect big spikes (like a competitor launching a huge campaign), consider running it more often and logging smaller batches. That keeps each run snappy.
For this use case, n8n is usually the better fit because you need pagination, de-duplication logic, and conditional alerts without paying extra for every branch. Zapier or Make can work, but multi-step loops get expensive and fiddly. n8n also gives you a clean path to self-hosting if you want unlimited runs. If you’re not sure, Talk to an automation expert and we’ll map it to your volume and tools.
Once this is running, competitor monitoring stops being a chore you “try to do.” It becomes a quiet system that shows you what changed, and leaves you alone when nothing did.
Need Help Setting This Up?
Our automation experts can build and customize this workflow for your specific needs. Free 15-minute consultation—no commitment required.