// Sheets · Slack

Slack a notification when a cell flips to "ready" in Google Sheets.

Watch the status column. The moment any row flips to "ready", post a Slack message naming the row. Single onEdit trigger; no Zapier, no per-task billing.

When my team marks an item ready in the tracker, I want Slack to ping us — not me checking the sheet every hour.

The script

copy · paste · trigger
notifySlackOnReady.gs
Apps Script
// Installable onEdit trigger. Watches the status column (D) and
// posts to Slack whenever any cell in it flips to "ready".
const SLACK_WEBHOOK = 'https://hooks.slack.com/services/...';
const STATUS_COLUMN = 4;  // column D

function onEdit(e) {
  if (e.range.getColumn() !== STATUS_COLUMN) return;
  if (e.value !== 'ready') return;

  const row = e.range.getRow();
  const sheet = e.source.getActiveSheet();
  const itemName = sheet.getRange(row, 1).getValue();  // column A

  UrlFetchApp.fetch(SLACK_WEBHOOK, {
    method: 'post',
    contentType: 'application/json',
    payload: JSON.stringify({
      text: `*${itemName}* is ready (row ${row}).`,
    }),
  });
}

Need a variant? Gnaw writes a custom version from one sentence — fields, triggers, edge cases handled.

Walkthrough

How it works

An installable onEdit trigger fires every time any cell in the sheet is edited. The first two guards drop edits we don't care about: cells outside the status column, and changes that aren't to "ready".

When both guards pass, the script reads the row's identifier from column A and POSTs a JSON payload to the Slack incoming webhook URL.

The simple onEdit trigger (just a function named onEdit, no install step) won't work here — simple triggers can't make external HTTP calls. The installable variant is required for UrlFetchApp.fetch.

How to set it up

In Slack: create an incoming webhook (slack.com/apps/A0F7XDUAZ-incoming-webhooks) for the channel you want pings to land in. Copy the webhook URL into SLACK_WEBHOOK.

In Apps Script: paste the function, then go to Triggers and add an installable trigger — event source: from spreadsheet, event type: on edit. Apps Script will prompt for the URL-fetch scope on first run.

Test it by editing the status cell of any row; the Slack message should arrive within a second.

Why not a Slack bot or Zapier

Zapier charges per task. At 1,000 status changes/month you're on a paid tier; at 10,000 you're on a serious tier.

A Slack bot needs hosting + auth + maintenance. Apps Script runs in Google's trust boundary with no extra surface to maintain. The webhook URL is the only credential.

Apps Script also has read access to the rest of the sheet, so you can include any context in the message — the assignee, the due date, the priority — without a second integration.

Want a custom version?

Describe your sheet and the rule you want. Gnaw writes the Apps Script — fields, triggers, edge cases — in one shot.

FAQ

4 questions
How do I notify a different channel per status?
Maintain a map: `const CHANNELS = { ready: 'WEBHOOK_A', blocked: 'WEBHOOK_B' };`. Look up by `e.value` and post to the matching webhook.
Can I include the editor's name in the message?
Yes — installable triggers see Session.getActiveUser().getEmail(). Add it to the JSON payload.
What if the Slack webhook is down?
UrlFetchApp.fetch throws on non-2xx responses. Wrap in try/catch and write the error into a spillover column for review. The script-failure event also surfaces in Apps Script's Executions panel.
How do I make the message richer (buttons, formatting)?
Slack accepts Block Kit JSON. Replace the simple `text` payload with a `blocks` array — Slack's Block Kit Builder generates the JSON for you.