Author: By Raj
Part of our Apps Script API Integrations guides. Need this built for your team? Hire a Google Apps Script developer.
Estimated reading time: 10 minutes
Build a Webhook Receiver in Google Apps Script (doPost Guide)
Webhooks turn external events, Stripe payments, Shopify orders, Typeform submissions, into Sheet rows via a deployed Apps Script web app doPost endpoint.
Validate signatures before trusting bodies. Respond within provider timeouts (often 3–5 seconds) by enqueueing heavy work to Script Properties or a Queue sheet for a time-driven processor.
Read /blog/apps-script-doget-dopost-explained for HTTP method nuances and deployment ACLs.
doPost handler skeleton
function doPost(e) { const body = e.postData.contents; const json = JSON.parse(body); ... return ContentService.createTextOutput('ok'); }
Set contentType from e.postData.type when providers send form-encoded payloads.
Signature verification
Stripe: HMAC SHA256 of signed payload. Shopify: X-Shopify-Hmac-Sha256. Compare with Utilities.computeHmacSha256Signature.
Reject mismatches with 401 plain text, do not write bad data.
Queue for slow processing
Append event ID and raw JSON to WebhookQueue sheet in doPost under 2 seconds. Separate processQueue runs every minute.
Mark rows processed to stay idempotent when providers retry webhooks.
Deployment settings
Execute as Me with access Anyone if public internet sends events, understand security tradeoff. IP allowlists are not native; use signature verification.
Use /dev URL only for sandbox; production providers need /exec deployment version.
Example code
function doPost(e) {
const secret = PropertiesService.getScriptProperties().getProperty('WEBHOOK_SECRET');
const sig = e.parameter.signature || (e.postData && e.postData.headers && e.postData.headers['X-Signature']);
const body = e.postData.contents;
const expected = Utilities.base64Encode(Utilities.computeHmacSha256Signature(body, secret));
if (sig !== expected) {
return ContentService.createTextOutput('unauthorized').setMimeType(ContentService.MimeType.TEXT);
}
const json = JSON.parse(body);
SpreadsheetApp.openById('SHEET_ID').getSheetByName('Events').appendRow([new Date(), json.type, JSON.stringify(json)]);
return ContentService.createTextOutput(JSON.stringify({ received: true })).setMimeType(ContentService.MimeType.JSON);
}| Approach | Best for | Tradeoff |
|---|---|---|
| Apps Script native | Google Workspace-centric workflows | 6-min limit, quotas |
| Zapier / Make | No-code, many connectors | Per-task cost, vendor lock-in |
| Python + Cloud | Heavy data / ML | Hosting cost, separate auth |
| API integration services | Production custom logic | Build cost, you own code |
FAQ
Can webhooks call SpreadsheetApp.getActive?
Why duplicate webhook rows?
Providers retry on non-200 or slow responses. Return 200 quickly and dedupe by event ID column unique constraint logic.
CORS issues?
Can I test locally?
Use curl -X POST deployment URL with sample JSON. clasp run cannot emulate doPost with full e object easily.
Stripe vs Shopify receivers?
Each has distinct signature headers, never reuse one verifier function without parameterizing algorithm and secret.
Need this done for you? I handle this as part of my consulting work, fixed-price quote within 24 hours.
Book a call with Raj →Get the full Build a Webhook Receiver in Google Apps Script (doPost Guide) script template
I'll email you a production-ready, commented version you can deploy in 10 minutes.
Continue reading
API Integrations
Connect Shopify API to Google Sheets with Apps Script
API Integrations
Send automated SMS from Google Sheets (Twilio): Production Apps Script Guide
API Integrations
Google Apps Script vs Zapier vs Make: Which Should You Use?
From another topic
How to Automate Google Sheets with Apps Script (Beginner Guide) →Need help with this? I handle this as part of my Apps Script API Integrations service.
Shopify, Stripe, Slack, HubSpot, webhooks, and REST API connections.
See how it works →