How to Use n8n with ._Template 80 Sales Leaderboard Slack
Your sales team's motivation dies in the gap between closing a deal and anyone noticing. A rep books $40k on a Tuesday afternoon, and it lands silently in your CRM — no fanfare, no visibility, no comp
Your sales team's motivation dies in the gap between closing a deal and anyone noticing. A rep books $40k on a Tuesday afternoon, and it lands silently in your CRM — no fanfare, no visibility, no competitive spark. By the time it surfaces in a Monday pipeline review, the moment is gone. Meanwhile your ops team burns an hour every morning exporting CRM data into a spreadsheet, ranking reps, and pasting a screenshot into Slack that's stale before anyone reads it. This is the problem Template 80 solves: an automated sales leaderboard that posts to Slack on a schedule, ranks your reps in real time, and turns invisible wins into public momentum — with zero manual work.
Why manual leaderboards fail
Every founder eventually tries the manual leaderboard. It works for two weeks. Then someone forgets to update it, the numbers drift out of sync with the CRM, a rep disputes their ranking, and trust in the whole thing collapses. The failure isn't discipline — it's architecture. A leaderboard that depends on a human running a report is a leaderboard that will be wrong, late, or absent exactly when it matters most.
The three recurring failures are always the same. Latency: data is hours or days old, so the leaderboard rewards last week's effort, not today's. Inconsistency: whoever builds it uses slightly different filters each time, so rankings jump for reasons nobody can explain. Cost: the person doing it is usually your most expensive ops hire, spending 20+ hours a month on copy-paste work. An automated pipeline removes all three at once — the data is pulled fresh, the logic is fixed in code, and the human cost drops to zero after setup.
The n8n solution in one workflow
Template 80 is a single n8n workflow that runs on a schedule, queries your CRM for closed-won deals in a defined window, aggregates revenue per rep, sorts the results, formats them into a clean Slack message with medals and totals, and posts it to your #sales channel. The entire flow is five nodes and runs in under two seconds. Because n8n self-hosts, your revenue data never touches a third-party SaaS dashboard — it moves straight from your CRM to your Slack workspace.
The core node chain is: Schedule Trigger → HTTP Request (or CRM node) → Code (aggregate & rank) → Set (format Slack blocks) → Slack. That's the whole engine. Everything else is configuration. The Code node is where the actual leaderboard logic lives, and it's deliberately simple so you can adapt it to any CRM that returns deal data as JSON.
Step-by-step setup in n8n
1. Schedule Trigger. Add a Schedule Trigger node. Set it to a Cron expression like 0 9 * * 1-5 to post at 9:00 AM every weekday. If you want an end-of-day recap too, add a second interval at 0 17 * * 1-5. Avoid running it more than 3–4 times a day — a leaderboard that pings constantly becomes noise reps learn to ignore.
2. Pull the deals. Add an HTTP Request node (or your native CRM node — HubSpot, Pipedrive, Salesforce all have dedicated n8n nodes). Query for deals with stage closed_won and a close date within your window. For a Pipedrive example, GET /v1/deals?status=won&start_date={{ $today.minus({days: 30}).toFormat('yyyy-MM-dd') }}. Store credentials in n8n's credential vault — never hardcode API keys in the node. Enable pagination if your deal volume exceeds the API's page size, or you'll silently rank on a partial dataset.
3. Aggregate and rank. Add a Code node (JavaScript). Reduce the deals into a per-rep total, then sort descending:
const deals = $input.all().map(i => i.json);
const totals = {};
for (const d of deals) {
const rep = d.owner_name || 'Unassigned';
totals[rep] = (totals[rep] || 0) + Number(d.value || 0);
}
const ranked = Object.entries(totals)
.map(([name, revenue]) => ({ name, revenue }))
.sort((a, b) => b.revenue - a.revenue);
return [{ json: { ranked, total: ranked.reduce((s, r) => s + r.revenue, 0) } }];
4. Format the Slack message. Add a Set or a second Code node to build the message text. Use medals for the top three and a monospace-friendly layout so numbers align. A simple builder:
const medals = ['🥇','🥈','🥉'];
const lines = $json.ranked.map((r, i) =>
`${medals[i] || `${i+1}.`} *${r.name}* — $${r.revenue.toLocaleString()}`);
const text = `*🏆 Sales Leaderboard — Last 30 Days*\n\n${lines.join('\n')}\n\n_Team total: $${$json.total.toLocaleString()}_`;
return [{ json: { text } }];
5. Post to Slack. Add the Slack node, operation Send Message. Authenticate with a Slack Bot token (create an app at api.slack.com, add the chat:write scope, and invite the bot to your channel). Set the channel to #sales and map the message field to {{ $json.text }}. For richer formatting, switch the node to Blocks mode and pass a Block Kit JSON payload instead of plain text — this lets you add dividers, header blocks, and a footer with the timestamp. Run the workflow manually once to confirm the message lands, then activate it.
The benefits compound faster than you expect
The obvious win is time: you reclaim the 20+ hours a month someone spent building this by hand. But the real return is behavioral. When wins become public and instant, reps start competing on the metric you chose to surface — and you control that metric. Rank by revenue and they chase revenue; rank by new logos and they chase logos. The leaderboard becomes a steering wheel, not just a scoreboard.
Because the pipeline is deterministic, the numbers are trusted. There's no "the report looks wrong" argument because everyone knows it's pulled straight from the CRM by the same code every time. And because it's self-hosted in n8n, you can extend it endlessly — add a weekly winner callout, DM the top rep a bonus notification, pipe the same ranked data into a Notion page or a Google Sheet, or trigger a celebratory GIF when someone crosses a threshold. The five-node core stays; you bolt features onto it.
Common pitfalls to avoid
Ranking on stale or partial data. The most common mistake is forgetting pagination on the CRM query, so you rank on the first 100 deals and the leaderboard is quietly wrong. Always confirm your total deal count matches the CRM before trusting the output. Test with a 90-day window first where the numbers are big enough to sanity-check.
Timezone drift in the Schedule Trigger. n8n runs in the server's timezone, not yours. If your instance runs UTC and your team is in US Central, a 0 9 * * * cron fires at 3 AM local. Set the timezone explicitly in the Schedule Trigger node or in your n8n environment config.
Over-posting. A leaderboard that appears six times a day trains people to mute the channel. Once in the morning and once at close of day is the ceiling. Frequency destroys the signal that makes it work.
Hardcoded credentials and exposed tokens. Never paste your Slack bot token or CRM key directly into an HTTP node's headers — use n8n's credential store so tokens are encrypted and don't leak into workflow exports. When you share or back up the workflow JSON, credentials stay out of it automatically.
No handling for ties or empty windows. If two reps close identical amounts, decide your tiebreaker (deal count, most recent close) in the Code node rather than letting sort order decide arbitrarily. And guard for the empty case — a Monday morning after a dry Friday shouldn't post a blank leaderboard. Add a conditional that posts an encouraging "fresh week, empty board" message instead.
Template 80 turns a fragile weekly ritual into infrastructure that runs itself. Set it up once, and every closed deal becomes a public win the moment it lands — no exports, no screenshots, no stale numbers. Get the ready-to-import workflow, pre-built Slack Block Kit formatting, and CRM query examples for HubSpot, Pipedrive, and Salesforce here: Sales Leaderboard for Slack — n8n Template 80.