Post Sheets alerts to a Slack channel
Bridge Northwind spreadsheet events to Slack — every threshold breach lands in #alerts.
Published Jul 11, 2025
Northwind tracks its sales pipeline in a spreadsheet, but a spreadsheet is passive — a deal can close, or a number can cross a danger line, and nobody notices until someone happens to open the tab. The team lives in Slack, not in Sheets, so the moments that matter need to come to them.
This automation bridges the two. A small slackPost helper sends a line of
text to a Slack channel, and an onEdit trigger watches the Pipeline sheet
so that the instant a deal is marked won, a celebratory note lands in
#alerts. It is a beginner-friendly pattern you can point at any cell change
worth shouting about.
What you’ll need
- A Google Sheet with a tab named
Pipeline, where a status column gets edited to values likewon. - A Slack app with an Incoming Webhook for the channel you want alerts in.
- The webhook URL saved as
SLACK_WEBHOOKin Script Properties — see Store API keys and secrets securely.
The script
// The sheet tab whose edits we watch.
const WATCHED_SHEET = 'Pipeline';
// The status value that should trigger an alert.
const WON_STATUS = 'won';
/**
* Sends a line of text to Slack via an Incoming Webhook.
*
* @param {string} text The message to post.
*/
function slackPost(text) {
const webhook = PropertiesService.getScriptProperties().getProperty('SLACK_WEBHOOK');
// Bail out clearly if the webhook was never configured.
if (!webhook) {
throw new Error('SLACK_WEBHOOK is not set in Script Properties.');
}
UrlFetchApp.fetch(webhook, {
method: 'post',
contentType: 'application/json',
payload: JSON.stringify({ text: text }),
muteHttpExceptions: true,
});
}
/**
* Simple installable/trigger handler. Fires on every edit to the
* spreadsheet; posts to Slack only when a Pipeline row is marked "won".
*
* @param {Object} e The onEdit event object.
*/
function onEdit(e) {
// 1. Ignore edits with no event object, or on any sheet but Pipeline.
if (!e || !e.range) return;
const sheet = e.range.getSheet();
if (sheet.getName() !== WATCHED_SHEET) return;
// 2. Only react when the edited cell now reads "won".
if (e.value !== WON_STATUS) return;
// 3. Read the deal name from column A of the edited row.
const dealName = sheet.getRange(e.range.getRow(), 1).getValue();
// 4. Announce it in Slack.
slackPost(':tada: ' + dealName + ' just closed.');
}
How it works
slackPostreads the Incoming Webhook URL from Script Properties, so the URL — which anyone can post to — never sits in the code. If it is missing, the function throws a clear error rather than failing silently.- It POSTs a small JSON body,
{ text }, to the webhook. Slack renders that as a message in the webhook’s channel. That is the whole helper — it is deliberately tiny so any automation can reuse it. onEditruns on every cell change in the spreadsheet. It first checks the event object exists and that the edit happened on thePipelinetab, returning early otherwise — most edits are not interesting.- It then checks
e.value, the cell’s new contents. Only when that equalswondoes it continue, so editing any other cell costs nothing. - For a real win, it reads column A of the edited row to get the deal name.
- It calls
slackPostwith a:tada:message, and the alert appears in Slack the moment the cell is updated.
Example run
Someone changes the status cell of a Pipeline row:
| Column A (deal) | Status column |
|---|---|
| Acme Rebrand | won |
The onEdit trigger fires, sees the new value is won, reads Acme Rebrand
from column A, and posts to #alerts:
:tada: Acme Rebrand just closed.
Editing any other cell — a note, a date, a status of lost — produces nothing,
because onEdit returns early before reaching slackPost.
Trigger it
onEdit is a special function name, but to call UrlFetchApp it must run as an
installable trigger, not the limited simple trigger:
- In the Apps Script editor, open Triggers (the clock icon).
- Click Add Trigger.
- Choose function
onEdit, event source From spreadsheet, event type On edit. - Save and approve the authorisation prompt.
The simple version of onEdit runs without permission but cannot make external
requests, so the installable trigger is what makes the Slack call work.
Watch out for
- A simple
onEditcannot callUrlFetchApp. If alerts never arrive, you are almost certainly relying on the simple trigger — add the installable one as above. e.valueis only set for single-cell edits. Pasting a block, or using fill-down, leavese.valueundefined, so those edits will not raise an alert. Reade.rangedirectly if you need to cover bulk edits.- The comparison is exact and case-sensitive.
Wonorwonwith a trailing space will not matchWON_STATUS— use a dropdown (data validation) on the status column to keep the values clean. onEditfires on every edit in the whole spreadsheet. The early returns keep it cheap, but avoid adding slow work before those checks.- The webhook posts to one fixed channel, the one it was created for. To alert a different channel, create a separate webhook and store it under its own property.
- Triggers run silently. If a
slackPostfails, no one sees it — check Executions in the editor occasionally, or wrap the call in atry/catchthat logs failures.
Related
Build a two-factor SMS verification step
Add phone verification to a Northwind workflow — code via Twilio, validated by web app.
Updated Dec 18, 2025
Bridge Sheets to Zapier or Make
Trigger external automations from Northwind Sheets via webhooks — no Apps Script logic needed downstream.
Updated Nov 8, 2025
Send rich notifications to Discord
Push Northwind deploy alerts and KPI updates to a Discord channel — embeds, not plain text.
Updated Oct 15, 2025
Build a payment-webhook receiver
Catch Stripe payment events into a Northwind sheet — paid invoices flip status instantly.
Updated Oct 11, 2025
Build a WhatsApp notification sender
Push Northwind updates via the WhatsApp Business API — for client billing milestones.
Updated Jul 23, 2025