Home / Blog / Report to Slack
Google Sheets · How-to · 2026

How to Send a Weekly KPI Report to Slack

A spreadsheet nobody opens is not a report. Here is how to get the numbers into the channel your team already reads — a working Apps Script, the no-code alternatives, and the message format that actually gets acted on.

By the Quiriz Team · Published August 5, 2026 · 7 min read

Short version: create a Slack incoming webhook, then have Apps Script read your summary cells and UrlFetchApp.fetch them into the channel on a weekly trigger. Ten minutes of setup, no add-on, no subscription. The code below works as written.

Why the channel beats the attachment

A small-business owner on Reddit described the loop exactly: pull the numbers from Shopify, Google Ads and Facebook, build the charts, assemble the slides, then send it round the team — every week. The assembling is annoying. The part that hurts is that most of it goes unread, because opening a file is a decision and reading a message is not.

Posting into the channel your team already has open removes that step, and it puts the number where the conversation about it happens.

1. Create the Slack webhook

Go to api.slack.com/apps → Create New App → From scratch, pick your workspace, then open Incoming Webhooks and turn it on. Click Add New Webhook to Workspace, choose the channel, and copy the URL it gives you. It looks like https://hooks.slack.com/services/T000/B000/xxxx.

Treat that URL as a secret — anyone holding it can post to the channel. If other people can edit the sheet, store it in Apps Script's Script Properties rather than in the code.

2. Give the script something small to read

Do not make the script compute your KPIs. Build a small Summary tab — one row per metric, with the current value and the prior period beside it — using formulas you already trust:

=SUMIFS(Data!D:D, Data!A:A, ">="&B1, Data!A:A, "<"&B2)

The script then reads finished numbers. When a metric definition changes you edit a formula, not code, and the message keeps working.

3. The Apps Script

Open Extensions → Apps Script, delete the placeholder, and paste this. It reads a three-column summary range (metric, this period, last period), formats a message, and posts it:

const WEBHOOK = 'https://hooks.slack.com/services/XXX/YYY/ZZZ';

function postWeeklyReport() {
  const sheet = SpreadsheetApp.getActive().getSheetByName('Summary');
  const rows = sheet.getRange('A2:C6').getValues();

  const lines = rows
    .filter(function (r) { return r[0] !== ''; })
    .map(function (r) {
      const metric = r[0], now = r[1], prev = r[2];
      const delta = prev ? (now - prev) / prev : 0;
      const arrow = delta >= 0 ? '▲' : '▼';
      const pct = (Math.abs(delta) * 100).toFixed(1);
      return '• *' + metric + ':* ' + now.toLocaleString() +
             '  ' + arrow + ' ' + pct + '% vs last week';
    });

  const stamp = Utilities.formatDate(new Date(), Session.getScriptTimeZone(), 'd MMM');
  const text = '*Weekly numbers — ' + stamp + '*\n' + lines.join('\n');

  UrlFetchApp.fetch(WEBHOOK, {
    method: 'post',
    contentType: 'application/json',
    payload: JSON.stringify({ text: text }),
  });
}

Run it once from the editor. Apps Script asks for authorization the first time — it needs permission to read the sheet and to call an external URL. Check the message lands in the right channel before you schedule it.

4. Schedule it

In the Apps Script editor, open Triggers (the clock icon) → Add Trigger. Choose postWeeklyReport, event source Time-driven, type Week timer, then the day and the hour block. Google runs time-driven triggers within about an hour of the slot, so pick a window rather than a minute — the 8–9am Monday block for a 9:30 standup, not the 9am one.

The no-code alternatives

If you would rather not own a script, Zapier and Make both have Sheets-to-Slack templates and take a few minutes to configure. At weekly cadence the task cost is trivial; the reason to think twice is one more subscription and one more place the logic lives. If your data sits in Excel rather than Sheets, Power Automate has a Slack connector and the same Recurrence trigger described in emailing an Excel report on a schedule.

What to put in the message

The plumbing is the easy half. Most automated Slack reports get ignored because they dump twenty metrics with no interpretation. A format that survives:

Three or four lines. If it needs scrolling on a phone, it is a document, not a report.

The follow-up problem

Here is what happens next in every channel that gets an automated report: someone replies "why is that down?" The script cannot answer, so the question routes to whoever owns the spreadsheet — and the manual work you automated comes back in a different shape.

That is the gap the Quiriz Slack bot is meant to close. The scheduled report posts as usual, and because the bot sits in the channel scoped to that project, anyone can @mention it and ask a follow-up against the same data — "break that down by channel", "which SKU dropped" — and get the answer in the thread rather than sending you a task. In the sheet, the same question works as =QUIRIZ("revenue by channel this week vs last", "table").

To be straight about it: the Slack bot and scheduled reports are on the paid tier, and the Apps Script above costs nothing. If your report is three numbers nobody ever questions, keep the script — it is the right answer.

Post to a test channel first, and keep the webhook URL in Script Properties rather than in the code if anyone else can edit the sheet.
💬 Skip the formula: the script posts numbers; it can't answer "why". With the Quiriz Slack bot in the channel, anyone can @mention it for a follow-up against the same data, or ask in the sheet with =QUIRIZ("revenue by channel this week vs last", "table").

Let the channel ask its own follow-ups

Schedule the report, then let your team @mention Quiriz in Slack to ask their own questions about the same data. Free to start.

Try Quiriz free →

Frequently asked questions

How do I post to Slack from Google Sheets?
Create a Slack incoming webhook for the target channel, then in Extensions > Apps Script call UrlFetchApp.fetch(webhookUrl, {method: "post", contentType: "application/json", payload: JSON.stringify({text: message})}). Add a time-driven trigger to run it on a schedule.
Do I need a paid add-on to send Sheets data to Slack?
No. Apps Script and Slack incoming webhooks are both free and take about ten minutes to wire up. Paid connectors like Zapier or Make are worth it mainly when you want the same flow across many tools without maintaining code.
How do I schedule the Slack message weekly?
In the Apps Script editor open Triggers, add a trigger for your function, choose Time-driven, then Week timer, and set the day and hour. Google runs it within roughly an hour of the slot you pick, so choose a window rather than an exact minute.
Should I post the numbers or a link to the spreadsheet?
Post the numbers. A link asks the reader to switch context, open a file, and find the cell — most will not. Put the headline figure, the change since last period, and one line of explanation in the message, and link the sheet underneath for whoever wants the detail.