Send Slack Notifications from Google Sheets Using Apps Script

Slack is where teams communicate, and Google Sheets is where data lives. Connecting the two means you can fire off alerts, summaries, and notifications automatically — no manual copy-pasting required.

Set up a Slack Incoming Webhook

  1. Go to your Slack workspace's App Directory and search for "Incoming WebHooks".
  2. Click Add to Slack, choose a channel, and click Add Incoming WebHooks integration.
  3. Copy the Webhook URL — it looks like https://hooks.slack.com/services/T.../B.../....

Store it in PropertiesService rather than hardcoding it:

function storeWebhookUrl() { PropertiesService.getScriptProperties().setProperty( 'SLACK_WEBHOOK_URL', 'https://hooks.slack.com/services/YOUR/WEBHOOK/URL' ); }

Send a basic Slack message

function sendSlackMessage(text) { const webhookUrl = PropertiesService.getScriptProperties().getProperty('SLACK_WEBHOOK_URL'); const payload = JSON.stringify({ text }); UrlFetchApp.fetch(webhookUrl, { method: 'POST', contentType: 'application/json', payload, muteHttpExceptions: true, }); }

Alert when a cell value exceeds a threshold

function checkAndAlert() { const sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet(); const value = sheet.getRange('B2').getValue(); const threshold = 1000; if (value > threshold) { sendSlackMessage(`⚠️ Alert: Cell B2 is *${value}*, which exceeds the threshold of ${threshold}.`); } }

Send a daily summary from a Sheet

function sendDailySummary() { const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Summary'); const data = sheet.getDataRange().getValues(); let message = '*Daily Report Summary*\n'; data.forEach(row => { message += `${row[0]}: *${row[1]}*\n`; }); sendSlackMessage(message); }

Send a rich message with Block Kit

Slack's Block Kit lets you send structured, formatted messages:

function sendRichMessage() { const webhookUrl = PropertiesService.getScriptProperties().getProperty('SLACK_WEBHOOK_URL'); const payload = JSON.stringify({ blocks: [ { type: 'header', text: { type: 'plain_text', text: '📊 Weekly Sales Report' } }, { type: 'section', fields: [ { type: 'mrkdwn', text: '*Total Sales:*\n$24,500' }, { type: 'mrkdwn', text: '*New Leads:*\n38' } ] }, { type: 'context', elements: [{ type: 'mrkdwn', text: `Generated on ${new Date().toDateString()}` }] } ] }); UrlFetchApp.fetch(webhookUrl, { method: 'POST', contentType: 'application/json', payload, muteHttpExceptions: true, }); }

Automate with a daily trigger

function createMorningTrigger() { ScriptApp.newTrigger('sendDailySummary') .timeBased() .everyDays(1) .atHour(8) .create(); }

Tips

  • Slack rate-limits Incoming Webhooks to 1 message per second. If you're sending bulk messages, add Utilities.sleep(1000) between calls.
  • Use *bold*, _italic_, and `code` in message text for basic formatting.
  • To send to different channels dynamically, create multiple webhooks — one per channel — and store them as separate script properties.