The Reporting Trap
Every agency knows this pain. Friday afternoon, someone is manually pulling numbers from five different places, pasting them into a spreadsheet, formatting a summary, and emailing it to a list of clients who may or may not read it. Three hours of work that produces a PDF nobody asked for.
We've seen this at every scale โ solo consultants, 10-person agencies, in-house marketing teams. The problem isn't the data. It's the assembly. And assembly is exactly what automation is built for.
The Three Tools
We didn't introduce any new software. The client already had all three tools โ they were just using them in isolation:
- Google Sheets โ the single source of truth for all KPIs, updated by various integrations throughout the week
- n8n โ the orchestration layer that reads the sheet, formats the report, and fires the delivery
- Slack + email โ delivery channels: Slack for internal teams, email for external clients
How the Workflow Runs
Every Monday at 8:00 AM, a cron trigger fires in n8n. It reads the previous week's data range from Google Sheets โ traffic, conversions, revenue, tasks completed, whatever the client tracks. A few JavaScript nodes clean and format the numbers. Then it builds two outputs: a Slack block message for the internal team, and an HTML email for the client.
โ Google Sheets: Read KPI range for last 7 days
โ n8n (JS node): Format numbers, calculate deltas, flag anomalies
โ Slack: Post formatted summary to #weekly-report channel
โ Gmail: Send branded HTML report to client distribution list
โ Google Sheets: Log delivery timestamp + status
The Formatting Layer
This is where most people give up. Raw Sheets data looks awful in an email. The n8n JavaScript node does the heavy lifting: it rounds numbers, adds % deltas vs the prior week, highlights anything that moved more than 15% in either direction, and injects everything into an HTML template string.
The Slack message uses Block Kit โ a structured JSON format that renders as a clean card with bold metrics and colour-coded arrows. The whole formatting step is under 40 lines of JavaScript. No external libraries, no separate templating engine.
Handling Edge Cases
What if the Sheets data is incomplete? What if a metric column is blank? We added a validation node that checks for empty cells before formatting. If anything looks wrong, it pings a Slack alert to the internal ops channel instead of sending a broken report to the client. The delivery is suppressed until someone manually approves it.
This single safeguard has prevented exactly three embarrassing client emails since we deployed it.
The Result
- Reporting time: 3 hours/week โ zero manual effort
- Reports delivered at 8:00 AM every Monday without fail
- Clients receive branded HTML email, team gets Slack card
- Anomaly detection catches data issues before clients do
- ~12 hours/month reclaimed across the team
What It Actually Cost to Build
Seven hours total. Three hours designing the Sheets schema and agreeing on which metrics mattered. Two hours building the n8n workflow. Two hours refining the email template and testing delivery. The tools are all free or already in the client's stack โ the only cost was the build time.
If you want this running before your next client call, get in touch. It's one of our most common fixed-price builds.