Automate Ad Performance Reporting with n8n Workflows
Build n8n ad performance automation that pulls Google and Facebook Ads metrics daily, scores underperformers with AI, and emails alerts. Browse the template.
Most marketing teams lose the first two hours of Monday to the same ritual: open Google Ads, export yesterday's CSV, switch to Facebook Ads Manager, export another one, paste both into a spreadsheet, then finally start the analysis. By the time a budget call gets made, it's already noon.
n8n ad performance automation runs that entire process on a schedule. A workflow pulls campaign metrics from both platforms every morning, normalizes the data, scores campaigns against configurable thresholds, and emails a digest of underperformers with AI-drafted recommendations. No CSV. No manual spreadsheet. No waiting.
The timing difference matters more than it sounds. A campaign that starts burning budget on a Wednesday afternoon won't surface in a Monday-morning manual review until you've lost five days of spend. Automated daily monitoring catches it Thursday morning, when you can still pause, redirect, or refresh the creative.
What You Can Automate With n8n and Paid Ads
- Daily metric pulls from Google Ads and Facebook Ads in a single workflow execution
- Cross-platform normalization (impressions, clicks, spend, and ROAS mapped to comparable field names)
- AI-powered campaign flagging against per-campaign performance thresholds
- Per-campaign recommendation emails with named optimization actions
- Google Sheets logging for 90-day historical trend tracking
- Minimum-spend filtering to suppress false positives from paused or zero-budget campaigns
- Threshold values stored in a Config node so they update without touching the workflow code
The Ad Performance Pipeline
Schedule Trigger → HTTP: Google Ads API → HTTP: Facebook Ads API
→ Merge → Code (normalize + score) → IF (below threshold)
→ OpenAI (recommend) → Email (alert digest) → Google Sheets (log all)
The Merge node combines campaign arrays from both platforms into a single item set. A Code node maps field names (Google uses metrics.cost_micros; Facebook uses spend) to unified keys and calculates derived metrics like cost-per-click and click-through rate. The IF node then routes only underperformers to the OpenAI and email branches. Everything else still gets logged.
This structure keeps the n8n ad performance workflow readable. Two platforms in, one Merge out, one IF split. Don't collapse the normalization and the scoring into the same Code node — when the scoring logic changes, you'll want it isolated.
Step-by-Step Breakdown
1. Collect Campaign Data From Both Platforms
The n8n-nodes-base.scheduleTrigger v1.2 node fires at a configurable time each morning. Two HTTP Request nodes hit the Google Ads API and Facebook Marketing API in parallel, pulling the previous day's campaign metrics.
One thing most tutorials skip: Google Ads OAuth2 access tokens expire after 3,600 seconds. Workflows that don't wire up a token refresh endpoint will silently stop pulling data about an hour after the credential is first set. Configure the OAuth2 credential refresh in the HTTP Request node's credential settings, then verify it with a test run after the credential rotates once.
Personal user tokens for the Facebook Marketing API expire every 60 days. When they expire, the workflow returns empty data rather than an error. The execution log looks clean, but the Sheets log quietly goes blank. System user tokens created in Business Manager don't expire. Wire the credential once and it runs indefinitely. This is the single most common reason n8n Facebook Ads workflows break silently six weeks after setup.
For Facebook, the campaign insights endpoint is graph.facebook.com/v21.0/act_{ad_account_id}/campaigns with fields=insights{impressions,clicks,spend,cpm,ctr} and date_preset=yesterday as query parameters.
2. Normalize and Score Campaigns
The n8n-nodes-base.code v2 node (the jsCode parameter) handles field mapping and performance scoring. Google returns cost in micros — divide metrics.cost_micros by 1,000,000 to get the dollar value. Facebook returns spend already in dollars. Both need mapping to a common spend_usd key before any comparison runs.
Hardcoding ROAS floors and spend weights inside the Code node means changing them requires editing a workflow. Use an n8n-nodes-base.set node at the top of the workflow as a Config block. Label it Config. Every downstream node reads from it with $node.Config.json.roas_floor. Change a value once and it propagates everywhere in the same execution.
3. Filter by Performance Threshold
An IF node routes campaigns below the performance threshold to the alert branch. Campaigns above the threshold go directly to the Google Sheets logging step. You don't want a daily email that says "all good" — that's noise. The workflow should only reach out when something needs attention.
One edge case worth catching: a campaign that's paused or has zero spend can look like a perfect performer because it has no failing metrics. Add a spend_usd > 0 check to the IF condition alongside the performance floor.
4. Generate Recommendations With OpenAI
The @n8n/n8n-nodes-langchain.openAi v2.1 node takes normalized campaign data for each underperformer and generates a one-sentence recommended action. The output lands at $json.output[0].content[0].text. Don't pull from an older n8n-nodes-base.openAi path — that path breaks silently when copied from pre-2024 workflow examples.
The prompt matters. A generic "analyze this campaign" gets a generic answer. Pass the campaign name, the specific metric that failed, the threshold it missed, and your standard response options (pause, cut budget 20%, refresh creative). The model returns something you can act on.
5. Send the Alert Digest and Log
An SMTP Email node batches all underperforming campaigns into one email. One alert at 8 AM is useful. Ten separate emails at 8 AM is a reason to turn off the workflow. Structure the message so each campaign gets a row with the metric, the gap, and the AI recommendation.
A Google Sheets node logs every campaign's daily snapshot regardless of the alert threshold. Three months of daily data makes gradual performance decay visible in ways that single-day thresholds can't catch. Gradual decay is the expensive kind.
Implementation Patterns
Pattern 1: Single ROAS floor across all campaigns
The simplest version. Set one ROAS floor in the Config node as roas_floor: 2.0. The IF node checks whether each campaign's ROAS falls below that value. Change the floor in one place, it applies to every campaign. Good enough for most setups.
Config (roas_floor: 2.0) → IF (roas < Config.roas_floor) → Alert branch
Pattern 2: Per-campaign threshold map
A brand awareness campaign and a direct-response campaign can't share the same ROAS floor. One buys attention; the other buys customers. Read campaign-specific thresholds from a Google Sheet column, join that data in the Code node, and filter against each campaign's individual value.
Worth the setup time. It's one additional Sheets read at the top of the workflow, and it's the difference between a system that works and one you keep overriding by hand.
Pattern 3: Seven-day rolling average
Instead of flagging a campaign on a single bad day, pull the last 7 days from Google Sheets and calculate a rolling average. Alert only when the current day's performance falls more than 15% below the rolling mean. This removes false positives from weekend traffic dips and single-day attribution delays, both of which are common in paid campaigns.
n8n Nodes You'll Use Most
| Node | Purpose |
|---|---|
n8n-nodes-base.scheduleTrigger v1.2 | Daily trigger at a set time |
n8n-nodes-base.httpRequest v4.2 | Fetch Google Ads and Facebook Ads APIs |
n8n-nodes-base.merge | Combine campaign data from both platforms |
n8n-nodes-base.code v2 | Normalize fields, score campaigns, rolling averages |
n8n-nodes-base.if | Route by performance threshold |
@n8n/n8n-nodes-langchain.openAi v2.1 | Generate per-campaign recommendations |
n8n-nodes-base.emailSend | Send the alert digest |
n8n-nodes-base.googleSheets | Log history and read per-campaign thresholds |
n8n-nodes-base.set | Config node for thresholds, weights, and options |
Getting Started
The credential setup is the slowest part. Plan for 60–90 minutes the first time through.
- Create a Google Cloud project, enable the Google Ads API, and generate an OAuth2 client ID. You'll also need a developer token from your Google Ads manager account — without it, the API returns a 403 even with valid OAuth2 credentials.
- In Facebook Business Manager, create a system user with
ads_readandread_insightspermissions. Generate a system user access token. Personal tokens expire every 60 days; system user tokens don't. - Build a Google Sheet with your campaign catalog: campaign ID, platform (google or facebook), minimum daily spend, ROAS floor. This is the configuration layer the workflow reads from.
- Add the Schedule Trigger, two HTTP Request nodes (one per platform), and wire them into a Merge node.
- Build the Code node to normalize field names and calculate scores. Test it with yesterday's data before touching the alert branch.
- Add the IF node with your threshold logic and chain the OpenAI node to the alert branch. Wire the Email node to send one batched digest.
- Run the workflow in test mode before activating the daily schedule. Confirm both API calls return data and the IF routing fires correctly on at least one known underperformer.
The Ad Performance Optimizer template ships this pre-wired — including the Code node normalization logic, the OpenAI scoring prompt, and a step-by-step credential setup guide for both platforms. It cuts the 90-minute setup to about 30.
For more on what n8n can automate across your marketing channels, marketing automation with n8n covers the broader picture. If you're also tracking AI spend from the OpenAI scoring step, tracking LLM costs with n8n shows how to log model usage and alert before the bill surprises you.
The Ad Performance Optimizer template ships pre-wired for both Google Ads and Facebook Ads — with the Code node normalization logic, the OpenAI scoring prompt, and a credential setup guide for both platforms built in. It runs daily, emails a digest of underperforming campaigns with AI-generated recommendations, and logs everything to Google Sheets. It's also part of The Complete n8n Templates Bundle, a one-time license to the full catalog if you're running more than one of these workflows.
Once the daily ad performance workflow is running, the natural next step is connecting it to your analytics layer. n8n analytics automation covers pulling GA4 data into the same Google Sheets log so ad spend and site performance share a single source of truth. The Ad Performance Optimizer already handles the Sheets logging — it's a straightforward extension from there.
Browse marketing automation templates →Common questions
How do I connect Google Ads to n8n?
Can n8n monitor Facebook Ads performance automatically?
How do I stop n8n ad performance alerts from firing every day?
Get the workflow templates this guide is built on
Import-ready n8n JSON, step-by-step setup, and tested end-to-end. One-time payment, own it forever.
Get 3 tested n8n templates, free
The full customer package for three real catalog templates — workflow JSON, step-by-step setup guide, credential checklist. Built through the same live-instance release process as everything we sell. Plus new templates and automation guides in your inbox. No spam, unsubscribe anytime.
- 01Smart To-Do List ManagerPre-built n8n workflow template that automates productivity with OpenAI. Live in about 10 minutes.$14
- 02Email Follow-Up AutomatorPre-built n8n workflow template that automates crm with OpenAI. Live in about 15 minutes.$12
- 03Market Trend AnalyzerPre-built n8n workflow template that automates data processing with OpenAI. Live in about 10 minutes.$14
More automation guides

n8n Calendly Automation: The Full Booking Lifecycle
Someone books a call through your Calendly link. The meeting lands on a calendar, and that's where most automations stop. The rep walks in knowing an email address and nothing else. Nobody updates the…

n8n Google Drive Automation: Process Every New File Once
A client drops a file into a shared folder. You want it processed, filed, and logged without anyone touching it. Simple enough, until the same file gets processed twice, or the trigger that worked in…

n8n Discord Automation: Webhook vs Bot, and the Limits
A new member joins your Discord, and nothing happens. No welcome, no role, no note in the team channel. Meanwhile your n8n instance is sitting right there, perfectly capable of handling all three. The…