This workflow corresponds to n8n.io template #14332 — we link there as the canonical source.
This workflow follows the Gmail → Google Sheets 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 →
{
"name": "Generate AI weekly business performance digest from Google Sheets to Slack and email",
"tags": [],
"nodes": [
{
"id": "b2000001-0000-0000-0000-000000000001",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-480,
-340
],
"parameters": {
"color": 6,
"width": 540,
"height": 480,
"content": "## AI Weekly Business Digest \u2192 Slack & Email\n\nAutomatically generate a weekly performance report from your Google Sheets data and deliver it to Slack and email.\n\n### How it works\n1. **Schedule:** Triggers every Monday at 8am.\n2. **Fetch:** Pulls the last 14 days of metrics from Google Sheets.\n3. **Calculate:** Computes this-week vs. last-week comparisons, conversion rate, and ROAS.\n4. **AI:** OpenAI generates a narrative digest with wins, concerns, and priorities.\n5. **Deliver:** Posts the formatted report to Slack and sends an HTML email simultaneously.\n\n### Setup steps\n1. **Config:** Open the \"Set report config variables\" node \u2014 enter your Sheet ID, sheet name, Slack channel, email recipients, and company name.\n2. **Data:** Prepare your Google Sheet with columns: Date, Revenue, Leads, Conversions, Ad Spend, Support Tickets.\n3. **Credentials:** Connect Google Sheets, OpenAI, Slack, and Gmail in each node.\n4. **Test:** Activate the workflow or trigger it manually to verify."
},
"typeVersion": 1
},
{
"id": "b2000001-0000-0000-0000-000000000002",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
40,
60
],
"parameters": {
"color": 7,
"width": 460,
"height": 200,
"content": "## 1. Schedule & Config\nTriggers every Monday at 8am. The config node holds your Sheet ID, Slack channel, and email recipients."
},
"typeVersion": 1
},
{
"id": "b2000001-0000-0000-0000-000000000003",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
540,
60
],
"parameters": {
"color": 7,
"width": 460,
"height": 200,
"content": "## 2. Data Retrieval & Processing\nPulls the last 14 days of metrics from Sheets, then calculates this-week vs. last-week comparisons."
},
"typeVersion": 1
},
{
"id": "b2000001-0000-0000-0000-000000000004",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
1100,
60
],
"parameters": {
"color": 7,
"width": 620,
"height": 200,
"content": "## 3. AI Analysis & Delivery\nOpenAI generates a narrative digest with trends, wins, concerns, and priorities. Delivered to Slack and email simultaneously."
},
"typeVersion": 1
},
{
"id": "b2000001-1000-0000-0000-000000000001",
"name": "Trigger every Monday at 8am",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
80,
300
],
"parameters": {
"rule": {
"interval": [
{
"field": "weeks",
"triggerAtDay": 1,
"triggerAtHour": 8
}
]
}
},
"typeVersion": 1.2
},
{
"id": "b2000001-1000-0000-0000-000000000002",
"name": "Set report config variables",
"type": "n8n-nodes-base.set",
"position": [
300,
300
],
"parameters": {
"mode": "manual",
"options": {},
"assignments": {
"assignments": [
{
"id": "cfg-1",
"name": "googleSheetId",
"type": "string",
"value": "YOUR_GOOGLE_SHEET_ID_HERE"
},
{
"id": "cfg-2",
"name": "sheetName",
"type": "string",
"value": "Weekly Metrics"
},
{
"id": "cfg-3",
"name": "slackChannel",
"type": "string",
"value": "#business-updates"
},
{
"id": "cfg-4",
"name": "emailRecipients",
"type": "string",
"value": "user@example.com"
},
{
"id": "cfg-5",
"name": "companyName",
"type": "string",
"value": "Your Company"
}
]
},
"duplicateItem": false,
"includeOtherFields": true
},
"typeVersion": 3.4
},
{
"id": "b2000001-1000-0000-0000-000000000003",
"name": "Fetch metrics from Google Sheets",
"type": "n8n-nodes-base.googleSheets",
"position": [
540,
300
],
"parameters": {
"options": {},
"operation": "read",
"sheetName": {
"__rl": true,
"mode": "name",
"value": "={{ $json.sheetName }}"
},
"documentId": {
"__rl": true,
"mode": "id",
"value": "={{ $json.googleSheetId }}"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.5
},
{
"id": "b2000001-1000-0000-0000-000000000004",
"name": "Calculate weekly comparisons",
"type": "n8n-nodes-base.code",
"position": [
780,
300
],
"parameters": {
"jsCode": "// Calculate this week vs last week metrics\nconst items = $input.all().map(i => i.json);\nconst config = $('Set report config variables').first().json;\nconst sorted = items.sort((a, b) => new Date(b.Date || b.date) - new Date(a.Date || a.date));\nconst thisWeek = sorted.slice(0, 7);\nconst lastWeek = sorted.slice(7, 14);\nfunction sumField(arr, field) { return arr.reduce((sum, row) => sum + (parseFloat(row[field]) || 0), 0); }\nfunction pctChange(current, previous) { if (previous === 0) return current > 0 ? 100 : 0; return Math.round(((current - previous) / previous) * 100); }\nconst metrics = { thisWeek: { revenue: sumField(thisWeek, 'Revenue'), leads: sumField(thisWeek, 'Leads'), conversions: sumField(thisWeek, 'Conversions'), adSpend: sumField(thisWeek, 'Ad Spend'), supportTickets: sumField(thisWeek, 'Support Tickets') }, lastWeek: { revenue: sumField(lastWeek, 'Revenue'), leads: sumField(lastWeek, 'Leads'), conversions: sumField(lastWeek, 'Conversions'), adSpend: sumField(lastWeek, 'Ad Spend'), supportTickets: sumField(lastWeek, 'Support Tickets') } };\nmetrics.changes = { revenue: pctChange(metrics.thisWeek.revenue, metrics.lastWeek.revenue), leads: pctChange(metrics.thisWeek.leads, metrics.lastWeek.leads), conversions: pctChange(metrics.thisWeek.conversions, metrics.lastWeek.conversions), adSpend: pctChange(metrics.thisWeek.adSpend, metrics.lastWeek.adSpend), supportTickets: pctChange(metrics.thisWeek.supportTickets, metrics.lastWeek.supportTickets) };\nmetrics.thisWeek.conversionRate = metrics.thisWeek.leads > 0 ? Math.round((metrics.thisWeek.conversions / metrics.thisWeek.leads) * 100) : 0;\nmetrics.thisWeek.roas = metrics.thisWeek.adSpend > 0 ? Math.round((metrics.thisWeek.revenue / metrics.thisWeek.adSpend) * 100) / 100 : 0;\nreturn [{ json: { metrics, rawDataPoints: sorted.length, companyName: config.companyName, slackChannel: config.slackChannel, emailRecipients: config.emailRecipients, reportDate: new Date().toISOString().split('T')[0] } }];"
},
"typeVersion": 2
},
{
"id": "b2000001-1000-0000-0000-000000000005",
"name": "Generate AI performance digest",
"type": "@n8n/n8n-nodes-langchain.openAi",
"position": [
1020,
300
],
"parameters": {
"model": {
"__rl": true,
"mode": "list",
"value": "gpt-4o-mini"
},
"options": {
"maxTokens": 1000,
"temperature": 0.4
},
"messages": {
"values": [
{
"content": "=You are a business analyst writing a weekly performance digest for {{ $json.companyName }}. Write a concise, actionable report based on these metrics:\n\nTHIS WEEK:\n- Revenue: ${{ $json.metrics.thisWeek.revenue }} ({{ $json.metrics.changes.revenue }}% vs last week)\n- Leads: {{ $json.metrics.thisWeek.leads }} ({{ $json.metrics.changes.leads }}% vs last week)\n- Conversions: {{ $json.metrics.thisWeek.conversions }} ({{ $json.metrics.changes.conversions }}% vs last week)\n- Ad Spend: ${{ $json.metrics.thisWeek.adSpend }} ({{ $json.metrics.changes.adSpend }}% vs last week)\n- Support Tickets: {{ $json.metrics.thisWeek.supportTickets }} ({{ $json.metrics.changes.supportTickets }}% vs last week)\n- Conversion Rate: {{ $json.metrics.thisWeek.conversionRate }}%\n- ROAS: {{ $json.metrics.thisWeek.roas }}x\n\nFormat your response with these sections:\n1. HEADLINE: One sentence performance summary with emoji\n2. WINS: 2-3 positive highlights\n3. WATCH: 1-2 areas of concern\n4. PRIORITIES: 3 recommended actions for this week\n5. OUTLOOK: Brief 1-sentence forecast\n\nKeep it under 300 words. Be specific with numbers."
}
]
},
"resource": "chat"
},
"credentials": {
"openAiApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.8
},
{
"id": "b2000001-1000-0000-0000-000000000006",
"name": "Format digest for Slack and email",
"type": "n8n-nodes-base.code",
"position": [
1260,
300
],
"parameters": {
"jsCode": "// Format the AI digest for Slack and email\nconst aiResponse = $input.first().json;\nconst prev = $('Calculate weekly comparisons').first().json;\nconst digest = aiResponse.message?.content || aiResponse.text || aiResponse.content || 'Report generation failed.';\nconst slackMessage = ':bar_chart: *Weekly Performance Digest \u2014 ' + prev.reportDate + '*\\n\\n' + digest;\nconst emailHtml = '<div style=\"font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto;\"><h2>Weekly Performance Digest \u2014 ' + prev.reportDate + '</h2><div style=\"background: #f5f5f5; padding: 20px; border-radius: 8px; margin: 20px 0;\"><h3>Key Metrics</h3><p>Revenue: $' + prev.metrics.thisWeek.revenue + ' (' + (prev.metrics.changes.revenue > 0 ? '+' : '') + prev.metrics.changes.revenue + '%)<br>Leads: ' + prev.metrics.thisWeek.leads + '<br>Conversions: ' + prev.metrics.thisWeek.conversions + '<br>ROAS: ' + prev.metrics.thisWeek.roas + 'x</p></div><div style=\"white-space: pre-wrap;\">' + digest + '</div></div>';\nreturn [{ json: { slackMessage, emailHtml, emailSubject: 'Weekly Performance Digest \u2014 ' + prev.reportDate, slackChannel: prev.slackChannel, emailRecipients: prev.emailRecipients, reportDate: prev.reportDate } }];"
},
"typeVersion": 2
},
{
"id": "b2000001-1000-0000-0000-000000000007",
"name": "Post digest to Slack channel",
"type": "n8n-nodes-base.slack",
"position": [
1520,
200
],
"parameters": {
"text": "={{ $json.slackMessage }}",
"channel": {
"__rl": true,
"mode": "name",
"value": "={{ $json.slackChannel }}"
},
"resource": "message",
"otherOptions": {}
},
"credentials": {
"slackApi": {
"name": "<your credential>"
}
},
"typeVersion": 2.2
},
{
"id": "b2000001-1000-0000-0000-000000000008",
"name": "Email digest to team",
"type": "n8n-nodes-base.gmail",
"position": [
1520,
420
],
"parameters": {
"sendTo": "={{ $json.emailRecipients }}",
"message": "={{ $json.emailHtml }}",
"options": {},
"subject": "={{ $json.emailSubject }}",
"emailType": "html"
},
"credentials": {
"gmailOAuth2": {
"name": "<your credential>"
}
},
"typeVersion": 2.1
}
],
"settings": {
"executionOrder": "v1"
},
"staticData": null,
"connections": {
"Set report config variables": {
"main": [
[
{
"node": "Fetch metrics from Google Sheets",
"type": "main",
"index": 0
}
]
]
},
"Trigger every Monday at 8am": {
"main": [
[
{
"node": "Set report config variables",
"type": "main",
"index": 0
}
]
]
},
"Calculate weekly comparisons": {
"main": [
[
{
"node": "Generate AI performance digest",
"type": "main",
"index": 0
}
]
]
},
"Generate AI performance digest": {
"main": [
[
{
"node": "Format digest for Slack and email",
"type": "main",
"index": 0
}
]
]
},
"Fetch metrics from Google Sheets": {
"main": [
[
{
"node": "Calculate weekly comparisons",
"type": "main",
"index": 0
}
]
]
},
"Format digest for Slack and email": {
"main": [
[
{
"node": "Post digest to Slack channel",
"type": "main",
"index": 0
},
{
"node": "Email digest to team",
"type": "main",
"index": 0
}
]
]
}
}
}
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.
gmailOAuth2googleSheetsOAuth2ApiopenAiApislackApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Founders, marketing managers, and ops teams who track weekly business metrics in Google Sheets and want an automated AI-generated performance report delivered to Slack and email every Monday. Perfect for agencies, e-commerce businesses, and SaaS teams who need a quick pulse…
Source: https://n8n.io/workflows/14332/ — 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.
Imagine a dedicated financial expert tirelessly working behind the scenes, sifting through every transaction, every investment move, and every accounting entry. That's exactly what this automated syst
Property management companies, building managers, and inspection teams who want to automate recurring property inspections, improve issue tracking, and streamline reporting.
Business owners and service providers who want to reduce no-show rates for appointments booked via Google Calendar.
This workflow runs on a daily schedule to analyze all Closed–Lost deals from your CRM and uncover the true reason behind each loss. It uses AI to classify the primary loss category, generate a confide
Personalized Outreach & Follow-Up - Phase 2. Uses googleSheets, openAi, gmail, gmailTrigger. Scheduled trigger; 59 nodes.