Create a Weekly Sales Report That Emails You Every Monday
Quick win: Automate your weekly sales report in 20 minutes. Get emailed every Monday at 8am with last week’s key metrics.
No more manual spreadsheets.
What You’ll Build
Automated report includes:
- Total revenue (last 7 days)
- Number of orders
- Average order value
- Top 5 products
- New vs returning customers
- Week-over-week comparison
Delivered: Monday 8am to your inbox
n8n Workflow Structure
Schedule (Monday 8am)
→ Get orders (last 7 days)
→ Calculate metrics
→ Get previous week data
→ Calculate comparisons
→ Format HTML email
→ Send via SendGrid
Step-by-Step Setup
Node 1: Schedule Trigger
Cron: 0 8 * * 1
(Every Monday at 8am)
Node 2: Get Last Week’s Orders
For DashNex:
HTTP Request
Method: GET
URL: https://your-store.com/api/orders
Parameters:
- start_date: `{{$now.minus({days: 7}).toISO()}}`
- end_date: \{\{$now.toISO()\}\}
Headers:
- Authorization: Bearer YOUR_API_KEY
For Shopify:
Shopify node
Operation: Get All Orders
Filters:
- created_at_min: (7 days ago)
Node 3: Calculate Metrics (Function Node)
const orders = $input.all().map(item => item.json);
// Basic metrics
const totalRevenue = orders.reduce((sum, order) => sum + parseFloat(order.total_price), 0);
const orderCount = orders.length;
const avgOrderValue = totalRevenue / orderCount;
// Customer analysis
const newCustomers = orders.filter(o => o.customer.orders_count === 1).length;
const returningCustomers = orderCount - newCustomers;
// Top products
const productSales = {};
orders.forEach(order => {
order.line_items.forEach(item => {
if (!productSales[item.name]) {
productSales[item.name] = { quantity: 0, revenue: 0 };
}
productSales[item.name].quantity += item.quantity;
productSales[item.name].revenue += item.price * item.quantity;
});
});
const topProducts = Object.entries(productSales)
.sort((a, b) => b[1].revenue - a[1].revenue)
.slice(0, 5)
.map(([name, data]) => ({ name, ...data }));
return [{
json: {
period: 'Last 7 Days',
totalRevenue: totalRevenue.toFixed(2),
orderCount,
avgOrderValue: avgOrderValue.toFixed(2),
newCustomers,
returningCustomers,
topProducts
}
}];
Node 4: Get Previous Week Data
Duplicate Node 2, change dates to 8-14 days ago.
Node 5: Calculate Week-over-Week Change
const thisWeek = $('Calculate This Week').first().json;
const lastWeek = $('Calculate Last Week').first().json;
const revenueChange = ((thisWeek.totalRevenue - lastWeek.totalRevenue) / lastWeek.totalRevenue * 100).toFixed(1);
const orderChange = ((thisWeek.orderCount - lastWeek.orderCount) / lastWeek.orderCount * 100).toFixed(1);
return [{
json: {
...thisWeek,
revenueChange,
orderChange,
revenueDirection: revenueChange > 0 ? '📈' : '📉',
orderDirection: orderChange > 0 ? '📈' : '📉'
}
}];
Node 6: Format HTML Email
const data = $json;
const html = `
<!DOCTYPE html>
<html>
<head>
<style>
body { font-family: Arial, sans-serif; }
.metric { background: #f5f5f5; padding: 20px; margin: 10px 0; border-radius: 8px; }
.metric h2 { margin: 0 0 5px 0; font-size: 32px; }
.metric p { margin: 0; color: #666; }
.change { font-size: 14px; font-weight: bold; }
.positive { color: #22c55e; }
.negative { color: #ef4444; }
table { width: 100%; border-collapse: collapse; margin: 20px 0; }
th, td { text-align: left; padding: 12px; border-bottom: 1px solid #ddd; }
th { background: #f5f5f5; }
</style>
</head>
<body>
<h1>Weekly Sales Report</h1>
<p>${data.period}</p>
<div class="metric">
<h2>$${data.totalRevenue}</h2>
<p>Total Revenue</p>
<p class="change ${data.revenueChange > 0 ? 'positive' : 'negative'}">
${data.revenueDirection} ${Math.abs(data.revenueChange)}% vs last week
</p>
</div>
<div class="metric">
<h2>${data.orderCount}</h2>
<p>Orders</p>
<p class="change ${data.orderChange > 0 ? 'positive' : 'negative'}">
${data.orderDirection} ${Math.abs(data.orderChange)}% vs last week
</p>
</div>
<div class="metric">
<h2>$${data.avgOrderValue}</h2>
<p>Average Order Value</p>
</div>
<h3>Customer Breakdown</h3>
<table>
<tr>
<th>Type</th>
<th>Count</th>
<th>Percentage</th>
</tr>
<tr>
<td>New Customers</td>
<td>${data.newCustomers}</td>
<td>${(data.newCustomers / data.orderCount * 100).toFixed(1)}%</td>
</tr>
<tr>
<td>Returning Customers</td>
<td>${data.returningCustomers}</td>
<td>${(data.returningCustomers / data.orderCount * 100).toFixed(1)}%</td>
</tr>
</table>
<h3>Top Products</h3>
<table>
<tr>
<th>Product</th>
<th>Units Sold</th>
<th>Revenue</th>
</tr>
${data.topProducts.map(p => `
<tr>
<td>${p.name}</td>
<td>${p.quantity}</td>
<td>$${p.revenue.toFixed(2)}</td>
</tr>
`).join('')}
</table>
</body>
</html>
`;
return [{ json: { html, subject: `Weekly Sales Report - $${data.totalRevenue}` } }];
Node 7: Send Email (SendGrid)
To: [email protected]
Subject: \{\{$json.subject\}\}
Content Type: HTML
Message: \{\{$json.html\}\}
Example Report Output
Weekly Sales Report
Last 7 Days
$4,287.50
Total Revenue
📈 +12.3% vs last week
35
Orders
📈 +8.6% vs last week
$122.50
Average Order Value
Customer Breakdown
New Customers: 18 (51.4%)
Returning Customers: 17 (48.6%)
Top Products
1. Premium Course - 12 units - $1,188.00
2. Starter Bundle - 8 units - $632.00
3. Consulting Session - 5 units - $975.00
4. E-book Pack - 15 units - $447.00
5. Membership - 3 units - $297.00
Advanced Enhancements
Add Charts
Use Chart.js or Google Charts API to generate revenue trend chart.
Multi-Store Support
Clone workflow for each store, combine reports into one email.
Slack Integration
Also post summary to #sales Slack channel.
Google Sheets Logging
Log metrics to sheet for historical tracking.
Alert Thresholds
Send urgent Slack message if revenue drops >20% week-over-week.
Troubleshooting
No data in report:
- Check API credentials
- Verify date calculations
- Ensure orders exist in date range
Email not sending:
- Verify SendGrid API key
- Check sender email is verified
- Look for errors in execution log
Wrong timezone:
- n8n uses UTC by default
- Adjust cron or set VPS timezone
FAQ
Q: Can I customize metrics?
Yes! Modify the Function node to calculate any metrics you want.
Q: Can this work with WooCommerce/Magento?
Yes! Just change the API call to match your platform.
Q: Can I send to multiple recipients?
Yes! Add multiple emails in “To” field (comma-separated).
Q: How do I change the day/time?
Modify the cron in Schedule node. Use crontab.guru to create expression.
Related:
About: I’m Mike Holownych. I automate business reporting with n8n. Learn more →
More Posts You'll Love
Based on your interests and activity