Bridge Sheets to Zapier or Make
Trigger external automations from Northwind Sheets via webhooks — no Apps Script logic needed downstream.
Published Nov 8, 2025
Northwind already runs plenty of automations in Zapier and Make — sending emails, updating a CRM, posting to Slack. The missing piece is a clean way to kick those off from a spreadsheet without rebuilding all that logic in Apps Script. A webhook is the bridge.
This script turns a Google Sheet into a trigger source. When someone edits a
row on a Triggers tab, it packages that row as a JSON object — keyed by the
column headers — and POSTs it to a Zapier or Make webhook. Apps Script does the
catching; Zapier or Make does everything after.
What you’ll need
- A Google Sheet with a tab named exactly
Triggers, with column headers in row 1. Each header becomes a field in the webhook payload. - A catch webhook in Zapier (“Webhooks by Zapier” trigger) or Make (“Custom webhook” module). Copy its URL.
- The script bound to that Sheet — write it from Extensions > Apps Script
inside the spreadsheet so the
onEdittrigger has somewhere to attach.
The script
// The catch-hook URL from Zapier or Make. Paste yours here.
const ZAPIER_HOOK = 'https://hooks.zapier.com/hooks/catch/...';
// The tab whose edits should fire the webhook.
const TRIGGER_SHEET = 'Triggers';
/**
* Simple onEdit trigger. When a row on the Triggers tab is edited,
* POSTs that row to the webhook as a JSON object keyed by header.
*
* @param {Object} e The edit event Apps Script passes in.
*/
function onEdit(e) {
// 1. Ignore manual runs and edits on any other tab.
if (!e || e.range.getSheet().getName() !== TRIGGER_SHEET) return;
const sheet = e.range.getSheet();
const row = e.range.getRow();
// 2. Ignore edits to the header row itself.
if (row === 1) return;
// 3. Read the header row — these become the payload's keys.
const headers = sheet
.getRange(1, 1, 1, sheet.getLastColumn())
.getValues()[0];
// 4. Read the full edited row, then zip headers and values together.
const values = sheet
.getRange(row, 1, 1, headers.length)
.getValues()[0];
const payload = Object.fromEntries(headers.map((h, i) => [h, values[i]]));
// 5. POST the row to the external webhook as JSON.
UrlFetchApp.fetch(ZAPIER_HOOK, {
method: 'post',
contentType: 'application/json',
payload: JSON.stringify(payload),
});
}
How it works
onEditruns automatically on every edit to the spreadsheet. It first checks the event exists and that the edit happened on theTriggerstab — any other tab is ignored.- It ignores edits to row 1, since the header row is not a record to send.
- It reads the header row across the used columns. These labels become the keys of the JSON payload, so the downstream automation gets named fields rather than bare cell values.
- It reads the full edited row and uses
Object.fromEntriesto zip the headers and the row’s values into a single object. - It POSTs that object as JSON to the Zapier or Make webhook, which catches it and runs whatever steps you have configured there.
Example run
The Triggers tab has these headers and one freshly edited row:
| name | plan | |
|---|---|---|
| Dana Reed | [email protected] | Pro |
Editing any cell in that row sends this payload to the webhook:
{ "name": "Dana Reed", "email": "[email protected]", "plan": "Pro" }
Zapier or Make catches it and takes over — adding the contact to a CRM, sending a welcome email, whatever the Zap or scenario does.
Run it
The onEdit function runs automatically once the script is in place — but a
plain onEdit cannot make external requests as a simple trigger. You need an
installable trigger:
- In the bound script’s editor, open Triggers (the clock icon).
- Add a trigger: choose
onEdit, event source From spreadsheet, event type On edit. - Approve the authorisation prompt — the installable trigger is what grants
UrlFetchApppermission to call out.
After that, every edit to a data row on the Triggers tab fires the webhook.
Watch out for
- A simple
onEdit(no installed trigger) runs without the authorisation needed forUrlFetchApp, so the fetch silently fails. The installable trigger above is required. - The function fires on every edit to a row — change three cells and the webhook is hit three times. Add a guard (for example, only fire when a specific “status” column is set) if duplicates would cause problems.
- A pasted block of rows triggers
onEditonce for the whole range, not once per row.e.range.getRow()then points at the first pasted row only. - The webhook URL sits in the script. Anyone with edit access to the script can read it, so treat it as a secret and rotate it if the Sheet is widely shared.
- There is no retry. If Zapier or Make is briefly down, the POST is lost. For important events, log sent rows and reconcile, or queue and retry.
- Webhook triggers in both Zapier and Make count against your task or operations
quota. A busy
Triggerstab can burn through a plan quickly.
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
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
Send SMS notifications with Twilio
Text Northwind alerts straight from your scripts — for production outages or VIP events.
Updated Jul 19, 2025