This workflow corresponds to n8n.io template #17055 — we link there as the canonical source.
This workflow follows the Agent → Error Trigger 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 →
{
"id": "FpauF9jfmoRaFe8q",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "Automated Client Ad Reporting",
"tags": [],
"nodes": [
{
"id": "67e27c4e-8a15-4951-9e58-491375e963f7",
"name": "Main Overview",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2720,
1248
],
"parameters": {
"color": 7,
"width": 560,
"height": 1444,
"content": "## \ud83d\udcca Automated Client Ad Reporting\n\nEvery Monday at 8am, this workflow fetches spend and performance metrics from Meta and Google Ads APIs, blends them with GA4 conversion data, generates an AI-powered summary of key insights, and automatically delivers a branded HTML report to the client via email and posts a summary to your internal Slack channel.\n\n**Perfect for:** Agency media buyers, account managers, and client success teams automating weekly performance reports.\n\n---\n\n## How it works\n\n1. **Every Monday 8am** \u2014 Triggers the workflow on a weekly schedule.\n2. **Fetch Meta Ads Insights** \u2014 Queries the Meta Ads API for spend, impressions, clicks, and actions from the past 7 days.\n3. **Fetch Google Ads Report** \u2014 Queries the Google Ads API for campaign names, cost, clicks, and conversions from the past 7 days.\n4. **Fetch GA4 Conversions** \u2014 Queries the GA4 Reporting API for conversion counts and revenue by channel from the past 7 days.\n5. **Blend Data Sources** \u2014 Combines the three data streams into a single merged object.\n6. **Compute Blended Metrics** \u2014 Calculates total spend, total conversions, total revenue, and blended ROAS across all platforms.\n7. **Summarize What Moved (AI Agent)** \u2014 Uses an AI model to analyze the metrics and generate a plain-language summary of key insights.\n8. **OpenAI Chat Model** \u2014 Language model that powers the AI analysis in the previous step.\n9. **Build Report** \u2014 Assembles the computed metrics and AI summary into an HTML report template.\n10. **Email Report to Client** \u2014 Sends the formatted HTML report to the client's email address.\n11. **Post to Agency Channel** \u2014 Posts a brief performance summary to your internal Slack channel.\n12. **Error Trigger** \u2014 *(optional path)* Detects if the main workflow fails at any point.\n13. **Notify Ops** \u2014 *(optional path)* Alerts your ops team in Slack if an error occurs.\n\n---\n\n## Setup (~20 minutes)\n\n1. **Meta Ads API** \u2014 Add your API token in the *Fetch Meta Ads Insights* node. Replace `YOUR_AD_ACCOUNT` with your actual account ID.\n2. **Google Ads API** \u2014 Add your OAuth credentials in the *Fetch Google Ads Report* node. Replace `YOUR_CUSTOMER_ID` with your account ID.\n3. **GA4 API** \u2014 Add your OAuth credentials in the *Fetch GA4 Conversions* node. Replace `YOUR_GA4_PROPERTY_ID` with your property ID.\n4. **OpenAI API** \u2014 Add your API key in the *OpenAI Chat Model* node for the AI summary analysis.\n5. **Gmail** \u2014 Authenticate in the *Email Report to Client* node and set the recipient email address.\n6. **Slack** \u2014 Authenticate in both *Post to Agency Channel* and *Notify Ops* nodes, then set your channel IDs.\n\n> This workflow sends live API calls every Monday. If you need custom date ranges or additional metrics, edit the query parameters in the fetch nodes before activating."
},
"typeVersion": 1
},
{
"id": "7b20be6f-be59-49bc-9472-2950e517b264",
"name": "1\ufe0f\u20e3 Trigger & Data Intake",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2128,
1136
],
"parameters": {
"color": 5,
"width": 696,
"height": 688,
"content": "## 1\ufe0f\u20e3 Trigger & Data Intake\n\nThe **Every Monday 8am** trigger fires the workflow every Monday at 8am UTC. Three HTTP requests execute in parallel: **Fetch Meta Ads Insights** pulls spend and engagement metrics from your Meta ad account, **Fetch Google Ads Report** retrieves campaign performance and costs from Google Ads, and **Fetch GA4 Conversions** queries your analytics property for conversion counts and revenue data by channel."
},
"typeVersion": 1
},
{
"id": "4bde520c-ef68-4d8f-8e68-4d7ab8d15f7f",
"name": "2\ufe0f\u20e3 Data Processing & AI Analysis",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1392,
1200
],
"parameters": {
"color": 3,
"width": 744,
"height": 636,
"content": "## 2\ufe0f\u20e3 Data Processing & AI Analysis\n\nThe **Blend Data Sources** node merges the three data streams into one unified object. The **Compute Blended Metrics** code node then calculates critical KPIs: total spend across both platforms, combined conversion count, total revenue, and blended ROAS. The **Summarize What Moved (AI Agent)** node passes all computed metrics to the **OpenAI Chat Model**, which generates a concise, plain-language analysis of performance trends, standout metrics, risks, and one actionable recommendation suitable for client consumption."
},
"typeVersion": 1
},
{
"id": "b6c7aede-aae8-4170-845c-5d6da5d7f524",
"name": "3\ufe0f\u20e3 Report Assembly & Delivery",
"type": "n8n-nodes-base.stickyNote",
"position": [
-608,
1200
],
"parameters": {
"color": 6,
"width": 664,
"height": 608,
"content": "## 3\ufe0f\u20e3 Report Assembly & Delivery\n\nThe **Build Report** node takes the computed metrics and AI summary and renders them into a formatted HTML report with client-friendly styling and the week's key numbers prominently displayed. The **Email Report to Client** node then sends this HTML report directly to your client's inbox with a timestamped subject line. Simultaneously, the **Post to Agency Channel** node posts a quick Slack summary to your internal team channel so the account manager and agency leadership stay in the loop."
},
"typeVersion": 1
},
{
"id": "d8af1fc7-2ced-4f7e-805b-eef3b8494352",
"name": "4\ufe0f\u20e3 Error Handling",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2032,
1920
],
"parameters": {
"color": 4,
"width": 712,
"height": 388,
"content": "## 4\ufe0f\u20e3 Error Handling\n\nIf the main workflow fails at any step, the **Error Trigger** catches the failure and passes it to the **Notify Ops** node, which immediately posts an alert to your ops Slack channel with the error message so your team can investigate before the client notices a missing report."
},
"typeVersion": 1
},
{
"id": "fb467fbb-5e04-4f39-8678-7c7e33935f53",
"name": "Every Monday 8am",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
-2080,
1520
],
"parameters": {
"rule": {
"interval": [
{
"field": "weeks",
"triggerAtDay": [
1
],
"triggerAtHour": 8
}
]
}
},
"typeVersion": 1.2
},
{
"id": "315398ac-6023-4363-8cdf-14c4209402c9",
"name": "Fetch Meta Ads Insights",
"type": "n8n-nodes-base.httpRequest",
"maxTries": 3,
"position": [
-1840,
1376
],
"parameters": {
"url": "https://graph.facebook.com/v20.0/act_YOUR_AD_ACCOUNT/insights",
"options": {
"timeout": 15000
},
"sendQuery": true,
"queryParameters": {
"parameters": [
{
"name": "fields",
"value": "spend,impressions,clicks,actions"
},
{
"name": "date_preset",
"value": "last_7d"
}
]
}
},
"retryOnFail": true,
"typeVersion": 4.2
},
{
"id": "4526033b-4ca6-4daa-bb73-b96f903a54f7",
"name": "Fetch Google Ads Report",
"type": "n8n-nodes-base.httpRequest",
"maxTries": 3,
"position": [
-1840,
1520
],
"parameters": {
"url": "https://googleads.googleapis.com/v17/customers/YOUR_CUSTOMER_ID/googleAds:searchStream",
"method": "POST",
"options": {
"timeout": 15000
},
"jsonBody": "={{ { query: \"SELECT campaign.name, metrics.cost_micros, metrics.clicks, metrics.conversions FROM campaign WHERE segments.date DURING LAST_7_DAYS\" } }}",
"sendBody": true,
"specifyBody": "json"
},
"retryOnFail": true,
"typeVersion": 4.2
},
{
"id": "1990fbf0-691a-4f2f-98c5-48df2c0f71e4",
"name": "Fetch GA4 Conversions",
"type": "n8n-nodes-base.httpRequest",
"maxTries": 3,
"position": [
-1840,
1664
],
"parameters": {
"url": "https://analyticsdata.googleapis.com/v1beta/properties/YOUR_GA4_PROPERTY_ID:runReport",
"method": "POST",
"options": {
"timeout": 15000
},
"jsonBody": "={{ { dateRanges: [{ startDate: \"7daysAgo\", endDate: \"today\" }], dimensions: [{ name: \"sessionDefaultChannelGroup\" }], metrics: [{ name: \"conversions\" }, { name: \"totalRevenue\" }] } }}",
"sendBody": true,
"specifyBody": "json"
},
"retryOnFail": true,
"typeVersion": 4.2
},
{
"id": "50369356-08b5-4820-acda-eb1f79dd1907",
"name": "Blend Data Sources",
"type": "n8n-nodes-base.merge",
"position": [
-1600,
1520
],
"parameters": {
"mode": "combine",
"options": {},
"combineBy": "combineAll"
},
"typeVersion": 3.2
},
{
"id": "ea5777be-0f88-4398-9548-c07ed1440d23",
"name": "Compute Blended Metrics",
"type": "n8n-nodes-base.code",
"position": [
-1360,
1520
],
"parameters": {
"jsCode": "const [meta, google, ga4] = [$('Fetch Meta Ads Insights').all(), $('Fetch Google Ads Report').all(), $('Fetch GA4 Conversions').all()];\nconst metaSpend = (meta[0]?.json?.data || []).reduce((s, r) => s + Number(r.spend || 0), 0);\nconst googleSpend = (google[0]?.json?.results || []).reduce((s, r) => s + Number(r.metrics?.costMicros || 0) / 1e6, 0);\nconst totalSpend = metaSpend + googleSpend;\nconst conversions = (ga4[0]?.json?.rows || []).reduce((s, r) => s + Number(r.metricValues?.[0]?.value || 0), 0);\nconst revenue = (ga4[0]?.json?.rows || []).reduce((s, r) => s + Number(r.metricValues?.[1]?.value || 0), 0);\nconst roas = totalSpend > 0 ? (revenue / totalSpend) : 0;\nreturn [{ json: { metaSpend, googleSpend, totalSpend, conversions, revenue, roas: Number(roas.toFixed(2)) } }];"
},
"typeVersion": 2
},
{
"id": "978e3757-f006-46ff-882d-bf4fec2fe5f8",
"name": "Summarize What Moved (AI Agent)",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
-1120,
1520
],
"parameters": {
"text": "=Weekly ad performance data: {{ JSON.stringify($json) }}. Write a 3-4 sentence plain-language summary of what moved and why, suitable for a client email.",
"options": {
"systemMessage": "You are a paid media analyst writing a concise weekly client summary. Highlight the standout metric, one risk, and one recommendation. No jargon."
},
"promptType": "define"
},
"typeVersion": 1.7
},
{
"id": "dc670394-6ed5-4f39-83d6-d9d71b9b6685",
"name": "OpenAI Chat Model",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"position": [
-1120,
1696
],
"parameters": {
"model": {
"__rl": true,
"mode": "list",
"value": "gpt-5-mini"
},
"options": {
"temperature": 0.5
},
"builtInTools": {}
},
"typeVersion": 1.3
},
{
"id": "1422f7ca-7e38-469d-b9c8-d3c2016c1557",
"name": "Build Report",
"type": "n8n-nodes-base.set",
"position": [
-880,
1520
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "rep1",
"name": "reportHtml",
"type": "string",
"value": "=<h2>Weekly Ad Performance Report</h2><p><b>Total Spend:</b> ${{ $('Compute Blended Metrics').item.json.totalSpend.toFixed(2) }}</p><p><b>Conversions:</b> {{ $('Compute Blended Metrics').item.json.conversions }}</p><p><b>ROAS:</b> {{ $('Compute Blended Metrics').item.json.roas }}x</p><p>{{ $json.output }}</p>"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "45dce2e3-efef-4339-aef7-82397c45c799",
"name": "Email Report to Client",
"type": "n8n-nodes-base.gmail",
"maxTries": 2,
"position": [
-384,
1456
],
"parameters": {
"sendTo": "client@REPLACE_WITH_CLIENT_DOMAIN.com",
"message": "={{ $json.reportHtml }}",
"options": {
"appendAttribution": false
},
"subject": "=Your Weekly Ad Performance Report \u2014 {{ $now.toFormat('dd LLL yyyy') }}"
},
"retryOnFail": true,
"typeVersion": 2.1
},
{
"id": "ef34e4b4-0c57-463c-8099-0244661e5a7e",
"name": "Post to Agency Channel",
"type": "n8n-nodes-base.slack",
"position": [
-384,
1648
],
"parameters": {
"text": "=\ud83d\udcca Weekly report sent \u2014 Spend ${{ $('Compute Blended Metrics').item.json.totalSpend.toFixed(2) }}, ROAS {{ $('Compute Blended Metrics').item.json.roas }}x",
"select": "channel",
"channelId": {
"__rl": true,
"mode": "list",
"value": "REPLACE_WITH_CHANNEL_ID",
"cachedResultName": "client-reports"
},
"otherOptions": {}
},
"typeVersion": 2.3
},
{
"id": "28085d80-fa2c-48e1-9fa9-f607b85e426c",
"name": "Error Trigger",
"type": "n8n-nodes-base.errorTrigger",
"position": [
-1936,
2096
],
"parameters": {},
"typeVersion": 1
},
{
"id": "829752d6-94f6-407c-98ea-bd9be2b40060",
"name": "Notify Ops",
"type": "n8n-nodes-base.slack",
"position": [
-1696,
2096
],
"parameters": {
"text": "=\ud83d\udea8 Automated Client Ad Reporting failed: {{ $json.execution.error.message }}",
"select": "channel",
"channelId": {
"__rl": true,
"mode": "list",
"value": "REPLACE_WITH_CHANNEL_ID",
"cachedResultName": "ops-alerts"
},
"otherOptions": {}
},
"typeVersion": 2.3
}
],
"active": false,
"settings": {
"binaryMode": "separate",
"availableInMCP": false,
"executionOrder": "v1"
},
"versionId": "213ec136-d0b3-4b72-a2f1-c351116f6d16",
"nodeGroups": [],
"connections": {
"Build Report": {
"main": [
[
{
"node": "Email Report to Client",
"type": "main",
"index": 0
},
{
"node": "Post to Agency Channel",
"type": "main",
"index": 0
}
]
]
},
"Error Trigger": {
"main": [
[
{
"node": "Notify Ops",
"type": "main",
"index": 0
}
]
]
},
"Every Monday 8am": {
"main": [
[
{
"node": "Fetch Meta Ads Insights",
"type": "main",
"index": 0
},
{
"node": "Fetch Google Ads Report",
"type": "main",
"index": 0
},
{
"node": "Fetch GA4 Conversions",
"type": "main",
"index": 0
}
]
]
},
"OpenAI Chat Model": {
"ai_languageModel": [
[
{
"node": "Summarize What Moved (AI Agent)",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Blend Data Sources": {
"main": [
[
{
"node": "Compute Blended Metrics",
"type": "main",
"index": 0
}
]
]
},
"Compute Blended Metrics": {
"main": [
[
{
"node": "Summarize What Moved (AI Agent)",
"type": "main",
"index": 0
}
]
]
},
"Fetch Google Ads Report": {
"main": [
[
{
"node": "Blend Data Sources",
"type": "main",
"index": 1
}
]
]
},
"Fetch Meta Ads Insights": {
"main": [
[
{
"node": "Blend Data Sources",
"type": "main",
"index": 0
}
]
]
},
"Summarize What Moved (AI Agent)": {
"main": [
[
{
"node": "Build Report",
"type": "main",
"index": 0
}
]
]
}
}
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This workflow runs every Monday at 8am to pull the last 7 days of performance from Meta Ads, Google Ads, and GA4, calculate blended KPIs, generate an OpenAI-powered narrative summary, email an HTML report via Gmail, and post an internal update (and errors) to Slack. Runs every…
Source: https://n8n.io/workflows/17055/ — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
Created by: Peyton Leveillee Last updated: October 2025
The Multi-Model Agency Content Engine is a high-performance editorial system designed for agencies. It solves the "blank page" problem by alternating between real-world social proof and strategic expe
This workflow automates end-to-end sustainability lifecycle management for corporate sustainability teams, ESG governance officers, and circular economy programme leads. It addresses the challenge of
This workflow automates end-to-end ESG (Environmental, Social, and Governance) sustainability reporting for enterprise sustainability teams, compliance officers, and green governance leads. It solves
Support teams, knowledge managers, and ops builders who are drowning in outdated KB articles and repeat tickets. If your team keeps answering the same questions because your knowledge base has gaps no