This workflow corresponds to n8n.io template #12288 — we link there as the canonical source.
This workflow follows the Agent → Gmail 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": "S6ktnkumGhuEMiqp",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "AI-Powered Google Ads Weekly Analyst",
"tags": [],
"nodes": [
{
"id": "3cf9b325-77cf-47a5-b768-5f3acd6e72c7",
"name": "OpenAI Chat Model",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"position": [
-1072,
832
],
"parameters": {
"model": {
"__rl": true,
"mode": "list",
"value": "gpt-5.1",
"cachedResultName": "gpt-5.1"
},
"options": {}
},
"credentials": {
"openAiApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.2
},
{
"id": "30a448e4-85c1-471f-ab28-aee3e35d41f2",
"name": "AI Analyst",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
-1072,
672
],
"parameters": {
"text": "=You are a senior Google Ads performance analyst responsible for weekly account health reviews, budget efficiency, and optimization decisions.\n\nYour role is NOT to summarize data.\nYour role is to diagnose performance changes, identify root causes, quantify impact, and prioritize actions that protect or grow conversions.\n\nYou are analyzing campaign performance data comparing two consecutive weeks and must produce a comprehensive WEEKLY PERFORMANCE REVIEW formatted as a complete HTML document with inline CSS.\n\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\nANALYST BEHAVIOR RULES (CRITICAL)\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n- Do NOT restate metrics unless comparing or interpreting them\n- Always explain WHY a change matters, not just WHAT changed\n- Prioritize insights by business impact (conversions, wasted spend, efficiency)\n- Explicitly call out uncertainty or low sample sizes\n- Assume the reader is a performance marketer or executive\n- Make tradeoffs \u2014 not everything can be \u201chigh priority\u201d\n\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\ud83d\udcca LAST WEEK DATA (Most Recent)\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n- Total Campaigns: {{ $json.last_week_data[0].total_campaigns }}\n- Total Spend: ${{ $json.last_week_data[0].total_spend }}\n- Total Clicks: {{ $json.last_week_data[0].total_clicks }}\n- Total Impressions: {{ $json.last_week_data[0].total_impressions }}\n- Total Conversions: {{ $json.last_week_data[0].total_conversions }}\n- Top Campaigns: {{ JSON.stringify($json.last_week_data[0].top_campaigns, null, 2) }}\n- Problem Campaigns: {{ JSON.stringify($json.last_week_data[0].zero_conversions_high_spend, null, 2) }}\n- Low CTR Campaigns: {{ JSON.stringify($json.last_week_data[0].low_ctr_campaigns, null, 2) }}\n- High Converters: {{ JSON.stringify($json.last_week_data[0].high_conversion_campaigns, null, 2) }}\n\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\ud83d\udcca PREVIOUS WEEK DATA (2 Weeks Ago)\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n- Total Campaigns: {{ $json.last_2_weeks_data[0].total_campaigns }}\n- Total Spend: ${{ $json.last_2_weeks_data[0].total_spend }}\n- Total Clicks: {{ $json.last_2_weeks_data[0].total_clicks }}\n- Total Impressions: {{ $json.last_2_weeks_data[0].total_impressions }}\n- Total Conversions: {{ $json.last_2_weeks_data[0].total_conversions }}\n- Top Campaigns: {{ JSON.stringify($json.last_2_weeks_data[0].top_campaigns, null, 2) }}\n- Problem Campaigns: {{ JSON.stringify($json.last_2_weeks_data[0].zero_conversions_high_spend, null, 2) }}\n- Low CTR Campaigns: {{ JSON.stringify($json.last_2_weeks_data[0].low_ctr_campaigns, null, 2) }}\n- High Converters: {{ JSON.stringify($json.last_2_weeks_data[0].high_conversion_campaigns, null, 2) }}\n\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\nOUTPUT REQUIREMENTS\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\nFormat your entire response as a COMPLETE HTML document with inline CSS.\nOutput ONLY HTML \u2014 no markdown, no explanations, no preamble.\nStart with <!DOCTYPE html> and end with </html>.\n\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\nREQUIRED SECTIONS (IN ORDER)\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\n\ud83d\udcc8 EXECUTIVE SUMMARY\n- One-paragraph high-level verdict on week-over-week performance\n- % changes in spend, clicks, impressions, and conversions\n- Overall account trend: improving / declining / stable but inefficient\n- Key wins (maximum 3)\n- Major risks or red flags (maximum 3)\n- Focus on impact, not volume\n\n\ud83d\udcca WEEK-OVER-WEEK COMPARISON\n- Use an HTML comparison table with columns:\n Metric | Last Week | Previous Week | Change (%) | Trend\n- Include:\n - Total Spend\n - Total Clicks\n - Total Impressions\n - Total Conversions\n - Average CTR (calculated)\n - Average CPA (calculated)\n- Apply green/red color coding and arrows based on direction\n\n\ud83c\udfc6 TOP PERFORMERS ANALYSIS (LAST WEEK)\n- Use an HTML table:\n Campaign | Impressions | Clicks | CTR | Conversions | Cost | CPA\n- Compare against previous week when applicable\n- Explain WHY these campaigns performed well (intent, efficiency, scale)\n- Avoid generic praise\n\n\u26a0\ufe0f ISSUES & PERFORMANCE RISKS\n- Use an HTML table:\n Campaign | Issue Type | Week-over-Week Trend | Analyst Diagnosis | Recommended Action\n- Flag:\n - High spend with zero conversions\n - CTR or CPA deterioration\n - New issues that did not exist last week\n\n\ud83d\udcc9 CAMPAIGNS WITH DECLINING PERFORMANCE\n- Only include campaigns that got WORSE week-over-week\n- Table columns:\n Campaign | Metric Declining | Last Week | Previous Week | % Change | Severity\n\n\ud83d\udcb0 BUDGET EFFICIENCY & REALLOCATION\n- Use an HTML table:\n Campaign | Last Week Spend | Previous Week Spend | Efficiency Trend | Recommendation\n- Identify wasted spend\n- Suggest budget shifts toward stronger performers\n- Be decisive\n\n\ud83d\udca1 ACTIONABLE RECOMMENDATIONS (PRIORITIZED)\nGroup recommendations into:\n\ud83d\udd34 HIGH PRIORITY (This Week)\n\ud83d\udfe1 MEDIUM PRIORITY (Next 1\u20132 Weeks)\n\ud83d\udfe2 LOW PRIORITY (Strategic / Long-Term)\n\nFor EACH recommendation, include:\n- Campaign(s) affected\n- Triggering metric(s)\n- Expected impact (cost savings or conversion lift)\n- Risk level (Low / Medium / High)\n\n\ud83d\udcd0 DATA CONFIDENCE & LIMITATIONS\n- Comment on sample size adequacy\n- Flag volatile metrics or low-confidence conclusions\n- Note any anomalies or missing data\n- If both weeks show zero data, recommend checking the API connection\n\n\ud83d\udccc ANALYST VERDICT\n- One sentence starting with:\n \u201cOverall, this account is\u2026\u201d\n- Be decisive and opinionated\n\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\nSTYLING REQUIREMENTS\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\nKeep all existing styling rules exactly as before.\n\nComparison table styling:\n.comparison-table td.positive { color: #0f9d58; font-weight: 600; }\n.comparison-table td.negative { color: #d93025; font-weight: 600; }\n.comparison-table .arrow-up::after { content: \" \u2191\"; }\n.comparison-table .arrow-down::after { content: \" \u2193\"; }\n\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\nFINAL IMPORTANT RULES\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n- Focus heavily on TRENDS, NOT static metrics\n- Highlight the biggest positive and negative movers\n- Do NOT exceed 5 high-priority recommendations\n- If insights conflict, explain the tradeoff\n- Think like an analyst who is accountable for results",
"options": {},
"promptType": "define"
},
"typeVersion": 2.1
},
{
"id": "13bae948-02b1-429b-a868-ceeeca26ccee",
"name": "Email Report to User",
"type": "n8n-nodes-base.gmail",
"position": [
-512,
720
],
"parameters": {
"sendTo": "user@example.com",
"message": "={{ $json.output }}",
"options": {},
"subject": "Weekly Report"
},
"credentials": {
"gmailOAuth2": {
"name": "<your credential>"
}
},
"typeVersion": 2.1
},
{
"id": "3b00c8ab-0773-4f05-a3b3-88b039eba148",
"name": "Calculator",
"type": "@n8n/n8n-nodes-langchain.toolCalculator",
"position": [
-880,
832
],
"parameters": {},
"typeVersion": 1
},
{
"id": "9a76a5d8-a299-4894-8f4f-3c024b2b937c",
"name": "Weekly Trigger",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
-1232,
320
],
"parameters": {
"rule": {
"interval": [
{
"field": "weeks",
"triggerAtDay": [
1
]
}
]
}
},
"typeVersion": 1.2
},
{
"id": "353f5a6e-84ae-4f96-9404-ce99dfb2a96e",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1344,
112
],
"parameters": {
"color": 7,
"width": 352,
"height": 448,
"content": "## Scheduling\n- Currently triggers every monday midnight\n- Can be modified"
},
"typeVersion": 1
},
{
"id": "e956a3c1-8c2f-4212-925a-64903f7278fd",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
-976,
112
],
"parameters": {
"color": 7,
"width": 1008,
"height": 448,
"content": "## Data Collection"
},
"typeVersion": 1
},
{
"id": "90e0ffe4-dbaa-47da-8df0-28c036cbba68",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1344,
576
],
"parameters": {
"color": 7,
"width": 704,
"height": 384,
"content": "## AI Analysis"
},
"typeVersion": 1
},
{
"id": "a13d4878-87f3-410e-8300-7232054e61bf",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
-624,
576
],
"parameters": {
"color": 7,
"width": 320,
"height": 384,
"content": "## Delivery"
},
"typeVersion": 1
},
{
"id": "6f61e82d-5658-4e18-bd28-3462ad9bd7ec",
"name": "Get Previous Week Data",
"type": "n8n-nodes-base.httpRequest",
"position": [
-864,
400
],
"parameters": {
"url": "=https://googleads.googleapis.com/v20/customers/[Customer ID]/googleAds:search ",
"method": "POST",
"options": {},
"jsonBody": "={\n \"query\": \"SELECT campaign.id, campaign.name, campaign.status, metrics.impressions, metrics.clicks, metrics.cost_micros, metrics.average_cpc, metrics.conversions, metrics.conversions_value, metrics.all_conversions, metrics.search_impression_share, metrics.search_budget_lost_impression_share FROM campaign WHERE segments.date BETWEEN '{{ $now.minus(14, 'days').format('yyyy-MM-dd') }}' AND '{{ $now.format('yyyy-MM-dd') }}' AND campaign.status = 'ENABLED' ORDER BY metrics.cost_micros DESC\"\n}",
"sendBody": true,
"sendHeaders": true,
"specifyBody": "json",
"authentication": "predefinedCredentialType",
"headerParameters": {
"parameters": [
{
"name": "Content-Type",
"value": "application/json"
},
{
"name": "developer-token"
}
]
},
"nodeCredentialType": "googleAdsOAuth2Api"
},
"credentials": {
"googleAdsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.2
},
{
"id": "372a2981-2511-4f57-9baa-df3acc3976df",
"name": "Get Last Week Data",
"type": "n8n-nodes-base.httpRequest",
"position": [
-864,
208
],
"parameters": {
"url": "=https://googleads.googleapis.com/v20/customers/[Customer ID]/googleAds:search",
"method": "POST",
"options": {},
"jsonBody": "={\n \"query\": \"SELECT campaign.id, campaign.name, campaign.status, metrics.impressions, metrics.clicks, metrics.cost_micros, metrics.average_cpc, metrics.conversions, metrics.conversions_value, metrics.all_conversions, metrics.search_impression_share, metrics.search_budget_lost_impression_share FROM campaign WHERE segments.date BETWEEN '{{ $now.minus(7, 'days').format('yyyy-MM-dd') }}' AND '{{ $now.format('yyyy-MM-dd') }}' AND campaign.status = 'ENABLED' ORDER BY metrics.cost_micros DESC\"\n}",
"sendBody": true,
"sendHeaders": true,
"specifyBody": "json",
"authentication": "predefinedCredentialType",
"headerParameters": {
"parameters": [
{
"name": "Content-Type",
"value": "application/json"
},
{
"name": "developer-token"
}
]
},
"nodeCredentialType": "googleAdsOAuth2Api"
},
"credentials": {
"googleAdsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.2
},
{
"id": "e1ca5b52-b109-44d8-aab8-66d005a6e078",
"name": "Extract Last Week Results",
"type": "n8n-nodes-base.splitOut",
"position": [
-656,
208
],
"parameters": {
"options": {},
"fieldToSplitOut": "results"
},
"typeVersion": 1
},
{
"id": "1754f82d-f3d8-4ecc-a791-ca41431de1e0",
"name": "Calculate & Summarize Last Week",
"type": "n8n-nodes-base.code",
"position": [
-448,
208
],
"parameters": {
"jsCode": "// Get all campaign data\nconst campaigns = $input.all();\n\n// Filter out zero-activity campaigns\nconst activeCampaigns = campaigns\n .map(item => ({\n id: item.json.campaign.id,\n name: item.json.campaign.name,\n status: item.json.campaign.status,\n impressions: parseInt(item.json.metrics.impressions) || 0,\n clicks: parseInt(item.json.metrics.clicks) || 0,\n cost: parseFloat(item.json.metrics.costMicros || 0) / 1000000,\n conversions: parseFloat(item.json.metrics.conversions) || 0,\n avg_cpc: parseFloat(item.json.metrics.averageCpc || 0) / 1000000\n }))\n .filter(c => c.cost > 0 || c.impressions > 0);\n\n// Calculate CTR and CPA\nconst enrichedCampaigns = activeCampaigns.map(c => ({\n ...c,\n ctr: c.impressions > 0 ? ((c.clicks / c.impressions) * 100).toFixed(2) : '0',\n cpa: c.conversions > 0 ? (c.cost / c.conversions).toFixed(2) : 'N/A'\n}));\n\n// Sort by spend\nenrichedCampaigns.sort((a, b) => b.cost - a.cost);\n\n// Create summary\nconst summary = {\n total_campaigns: enrichedCampaigns.length,\n total_spend: enrichedCampaigns.reduce((sum, c) => sum + c.cost, 0).toFixed(2),\n total_clicks: enrichedCampaigns.reduce((sum, c) => sum + c.clicks, 0),\n total_impressions: enrichedCampaigns.reduce((sum, c) => sum + c.impressions, 0),\n total_conversions: enrichedCampaigns.reduce((sum, c) => sum + c.conversions, 0),\n\n top_campaigns: enrichedCampaigns.slice(0, 10),\n\n zero_conversions_high_spend: enrichedCampaigns\n .filter(c => c.conversions === 0 && c.cost > 50)\n .slice(0, 5),\n\n low_ctr_campaigns: enrichedCampaigns\n .filter(c => parseFloat(c.ctr) < 1 && c.impressions > 100)\n .slice(0, 5),\n\n high_conversion_campaigns: enrichedCampaigns\n .filter(c => c.conversions > 0)\n .sort((a, b) => b.conversions - a.conversions)\n .slice(0, 5)\n};\n\n// \u2705 Wrap in parent array\nreturn [{\n json: {\n last_week_data: summary\n }\n}];"
},
"typeVersion": 2
},
{
"id": "cbc09939-6389-47a3-ac04-3f026b081a42",
"name": "Extract Previous Week Results",
"type": "n8n-nodes-base.splitOut",
"position": [
-656,
400
],
"parameters": {
"options": {},
"fieldToSplitOut": "results"
},
"typeVersion": 1
},
{
"id": "d6afc88d-dc01-4949-9b09-9f4b2731cfce",
"name": "Merge Week Comparison Data",
"type": "n8n-nodes-base.merge",
"position": [
-112,
384
],
"parameters": {},
"typeVersion": 3.2
},
{
"id": "bddd3c9b-4bef-4ea8-8160-ab61eda91407",
"name": "Aggregate",
"type": "n8n-nodes-base.aggregate",
"position": [
-1296,
672
],
"parameters": {
"options": {},
"fieldsToAggregate": {
"fieldToAggregate": [
{
"fieldToAggregate": "last_week_data"
},
{
"fieldToAggregate": "last_2_weeks_data"
}
]
}
},
"typeVersion": 1
},
{
"id": "3010cd72-7c89-4c4e-84c5-f951c59cfee4",
"name": "Calculate & Summarize Last 2 Weeks",
"type": "n8n-nodes-base.code",
"position": [
-448,
400
],
"parameters": {
"jsCode": "// Get all campaign data\nconst campaigns = $input.all();\n\n// Filter out zero-activity campaigns\nconst activeCampaigns = campaigns\n .map(item => ({\n id: item.json.campaign.id,\n name: item.json.campaign.name,\n status: item.json.campaign.status,\n impressions: parseInt(item.json.metrics.impressions) || 0,\n clicks: parseInt(item.json.metrics.clicks) || 0,\n cost: parseFloat(item.json.metrics.costMicros || 0) / 1000000,\n conversions: parseFloat(item.json.metrics.conversions) || 0,\n avg_cpc: parseFloat(item.json.metrics.averageCpc || 0) / 1000000\n }))\n .filter(c => c.cost > 0 || c.impressions > 0);\n\n// Calculate CTR and CPA\nconst enrichedCampaigns = activeCampaigns.map(c => ({\n ...c,\n ctr: c.impressions > 0 ? ((c.clicks / c.impressions) * 100).toFixed(2) : '0',\n cpa: c.conversions > 0 ? (c.cost / c.conversions).toFixed(2) : 'N/A'\n}));\n\n// Sort by spend\nenrichedCampaigns.sort((a, b) => b.cost - a.cost);\n\n// Create summary\nconst summary = {\n total_campaigns: enrichedCampaigns.length,\n total_spend: enrichedCampaigns.reduce((sum, c) => sum + c.cost, 0).toFixed(2),\n total_clicks: enrichedCampaigns.reduce((sum, c) => sum + c.clicks, 0),\n total_impressions: enrichedCampaigns.reduce((sum, c) => sum + c.impressions, 0),\n total_conversions: enrichedCampaigns.reduce((sum, c) => sum + c.conversions, 0),\n\n top_campaigns: enrichedCampaigns.slice(0, 10),\n\n zero_conversions_high_spend: enrichedCampaigns\n .filter(c => c.conversions === 0 && c.cost > 50)\n .slice(0, 5),\n\n low_ctr_campaigns: enrichedCampaigns\n .filter(c => parseFloat(c.ctr) < 1 && c.impressions > 100)\n .slice(0, 5),\n\n high_conversion_campaigns: enrichedCampaigns\n .filter(c => c.conversions > 0)\n .sort((a, b) => b.conversions - a.conversions)\n .slice(0, 5)\n};\n\n// \u2705 Wrap in parent array\nreturn [{\n json: {\n last_2_weeks_data: summary\n }\n}];\n"
},
"typeVersion": 2
},
{
"id": "772d8e1b-c33d-4f2f-8f0b-4199bf705e10",
"name": "Sticky Note5",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2080,
112
],
"parameters": {
"width": 720,
"height": 848,
"content": "# \ud83d\udcca AI-Powered Google Ads Weekly Analyst\n\nAutomatically analyzes your Google Ads performance every Monday and sends a comprehensive report to your inbox.\n\n## What it does\n- Pulls campaign data from the last 2 weeks via Google Ads API\n- Compares week-over-week performance metrics\n- Identifies top performers and problem campaigns\n- Calculates key metrics: CTR, CPA, spend efficiency, conversion trends\n- Generates AI-powered insights and prioritized recommendations using GPT-5.1\n- Emails a professional HTML report with executive summary and action items\n\n## Setup Required\n1. **Google Ads Customer ID**: Replace `[Customer ID]` in both HTTP Request node URLs\n - Format: XXX-XXX-XXXX (found in your Google Ads dashboard top-right)\n2. **Developer Token**: Add your Google Ads Developer Token in the header parameters of both HTTP Request nodes\n3. **Google Ads OAuth2**: Connect your Google Ads credentials\n4. **Gmail OAuth2**: Connect your Gmail credentials for email delivery\n5. **Email Recipient**: Update the recipient email in the \"Email Report to User\" node\n6. **(Optional)** Adjust the schedule trigger timing\n\n## Configuration\n- **Runs:** Every Monday at midnight (configurable in Weekly Trigger node)\n- **Analysis Period:** Last 7 days vs. previous 7 days\n- **Report Format:** HTML email with tables, metrics, and color-coded insights"
},
"typeVersion": 1
}
],
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "ac5e5f39-fa9a-44ce-b1aa-0e7f985af2ae",
"connections": {
"Aggregate": {
"main": [
[
{
"node": "AI Analyst",
"type": "main",
"index": 0
}
]
]
},
"AI Analyst": {
"main": [
[
{
"node": "Email Report to User",
"type": "main",
"index": 0
}
]
]
},
"Calculator": {
"ai_tool": [
[
{
"node": "AI Analyst",
"type": "ai_tool",
"index": 0
}
]
]
},
"Weekly Trigger": {
"main": [
[
{
"node": "Get Last Week Data",
"type": "main",
"index": 0
},
{
"node": "Get Previous Week Data",
"type": "main",
"index": 0
}
]
]
},
"OpenAI Chat Model": {
"ai_languageModel": [
[
{
"node": "AI Analyst",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Get Last Week Data": {
"main": [
[
{
"node": "Extract Last Week Results",
"type": "main",
"index": 0
}
]
]
},
"Email Report to User": {
"main": [
[]
]
},
"Get Previous Week Data": {
"main": [
[
{
"node": "Extract Previous Week Results",
"type": "main",
"index": 0
}
]
]
},
"Extract Last Week Results": {
"main": [
[
{
"node": "Calculate & Summarize Last Week",
"type": "main",
"index": 0
}
]
]
},
"Merge Week Comparison Data": {
"main": [
[
{
"node": "Aggregate",
"type": "main",
"index": 0
}
]
]
},
"Extract Previous Week Results": {
"main": [
[
{
"node": "Calculate & Summarize Last 2 Weeks",
"type": "main",
"index": 0
}
]
]
},
"Calculate & Summarize Last Week": {
"main": [
[
{
"node": "Merge Week Comparison Data",
"type": "main",
"index": 0
}
]
]
},
"Calculate & Summarize Last 2 Weeks": {
"main": [
[
{
"node": "Merge Week Comparison Data",
"type": "main",
"index": 1
}
]
]
}
}
}
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.
gmailOAuth2googleAdsOAuth2ApiopenAiApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Automatically analyzes your Google Ads performance every Monday and sends a comprehensive report to your inbox with AI-powered insights, week-over-week comparisons, and prioritized recommendations to optimize your campaigns.
Source: https://n8n.io/workflows/12288/ — 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.
This workflow automates comprehensive real estate investment analysis by orchestrating specialized AI agents to evaluate property data, market trends, and financial metrics. Designed for real estate i
kisisel asistan. Uses toolWorkflow, toolHttpRequest, toolCalculator, toolThink. Scheduled trigger; 43 nodes.
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
This workflow automates end-to-end financial transaction processing for finance teams managing high-volume bank data. It eliminates manual reconciliation by intelligently classifying transactions, det