WhatsApp offer broadcast from a Google Sheet
Send an approved WhatsApp template to every opted-in contact in your sheet, and mark each one as sent.
How it works
Trigger: Manual — you click Run when the offer is ready
- Read your Contacts sheet (phone, name, opted_in, sent).
- Keep contacts who opted in and haven't received this campaign yet.
- Send each one your approved WhatsApp marketing template.
- Mark the row as sent, so running it again never sends twice.
Diagram
Trigger App Logic
Build it
Pick your tool — same automation, step by step.
Copy and paste straight into an n8n canvas (Ctrl+V), or download and use Import from File. Then connect your own credentials and replace every YOUR_… placeholder.
Show code (208 lines)
{
"name": "WhatsApp offer broadcast from a Google Sheet (Flowngn)",
"nodes": [
{
"parameters": {
"content": "## WhatsApp offer broadcast from a Google Sheet\nSend an approved WhatsApp template to every opted-in contact in your sheet, and mark each one as sent.\n\n**Setup**\n1. Open each node and connect your own credentials.\n2. Replace every YOUR_… placeholder.\n3. Test once, then activate.\n\nFree template from Flowngn",
"height": 260,
"width": 340
},
"id": "3f36c28d-dcaa-4fe7-afb0-dde2cffcb7d1",
"name": "Setup notes",
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
-420,
-60
]
},
{
"parameters": {},
"id": "3f36c28d-dcaa-4fe7-afb0-dde2cffcb7d1",
"name": "Run campaign",
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [
0,
0
]
},
{
"parameters": {
"operation": "read",
"documentId": {
"__rl": true,
"value": "YOUR_SPREADSHEET_ID",
"mode": "id"
},
"sheetName": {
"__rl": true,
"value": "Contacts",
"mode": "name"
},
"options": {}
},
"id": "3f36c28d-dcaa-4fe7-afb0-dde2cffcb7d1",
"name": "Read contacts",
"type": "n8n-nodes-base.googleSheets",
"typeVersion": 4.5,
"position": [
300,
0
]
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "loose"
},
"conditions": [
{
"id": "c1",
"leftValue": "={{ String($json.opted_in).toLowerCase() === 'yes' && String($json.sent).toLowerCase() !== 'yes' && $json.phone !== '' }}",
"rightValue": "",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
}
}
],
"combinator": "and"
},
"options": {}
},
"id": "3f36c28d-dcaa-4fe7-afb0-dde2cffcb7d1",
"name": "Opted in, not sent?",
"type": "n8n-nodes-base.if",
"typeVersion": 2.2,
"position": [
600,
0
]
},
{
"parameters": {
"operation": "sendTemplate",
"phoneNumberId": "YOUR_PHONE_NUMBER_ID",
"recipientPhoneNumber": "={{ String($json.phone).replace(/[^0-9]/g, '') }}",
"template": "YOUR_OFFER_TEMPLATE|ar",
"components": {
"component": [
{
"type": "body",
"bodyParameters": {
"parameter": [
{
"type": "text",
"text": "={{ $json.name || 'عميلنا العزيز' }}"
}
]
}
}
]
}
},
"id": "3f36c28d-dcaa-4fe7-afb0-dde2cffcb7d1",
"name": "Send offer",
"type": "n8n-nodes-base.whatsApp",
"typeVersion": 1,
"position": [
900,
0
],
"onError": "continueRegularOutput"
},
{
"parameters": {
"operation": "update",
"documentId": {
"__rl": true,
"value": "YOUR_SPREADSHEET_ID",
"mode": "id"
},
"sheetName": {
"__rl": true,
"value": "Contacts",
"mode": "name"
},
"columns": {
"mappingMode": "defineBelow",
"value": {
"phone": "={{ $('Opted in, not sent?').item.json.phone }}",
"sent": "={{ $json.error ? 'failed' : 'yes' }}"
},
"matchingColumns": [
"phone"
]
},
"options": {}
},
"id": "3f36c28d-dcaa-4fe7-afb0-dde2cffcb7d1",
"name": "Mark as sent",
"type": "n8n-nodes-base.googleSheets",
"typeVersion": 4.5,
"position": [
1200,
0
]
}
],
"connections": {
"Run campaign": {
"main": [
[
{
"node": "Read contacts",
"type": "main",
"index": 0
}
]
]
},
"Read contacts": {
"main": [
[
{
"node": "Opted in, not sent?",
"type": "main",
"index": 0
}
]
]
},
"Opted in, not sent?": {
"main": [
[
{
"node": "Send offer",
"type": "main",
"index": 0
}
]
]
},
"Send offer": {
"main": [
[
{
"node": "Mark as sent",
"type": "main",
"index": 0
}
]
]
}
},
"pinData": {},
"settings": {
"executionOrder": "v1"
},
"meta": {
"templateCredsSetupCompleted": false
},
"tags": []
}In Make, create a new scenario and add these modules in order:
- Run the scenario manually (Run once)
- Google Sheets › Search Rows
- Filter on the next route: “Opted in, not sent?”
- If yesWhatsApp Business Cloud › Send a Template Message
- If yesGoogle Sheets › Update a Row
- Every module run uses Make operations — the free plan includes a monthly quota.
- Module and step names can differ slightly as Make and Zapier update their apps.
In Zapier, create a new Zap and add these steps in order:
- Google Sheets — New or Updated Spreadsheet Row (Zapier has no manual trigger)
- Google Sheets — Lookup Spreadsheet Rows (or Code by Zapier)
- Filter by Zapier: “Opted in, not sent?”
- If yesWhatsApp — Send Template Message
- If yesGoogle Sheets — Update Spreadsheet Row
- Zaps with more than two steps need a paid Zapier plan.
- Webhooks, Filters/Paths and Code by Zapier are premium features on some Zapier plans.
- Module and step names can differ slightly as Make and Zapier update their apps.
Tips
- Only message people who agreed to hear from you. Meta can block numbers that get reported.
- Clear the sent column before each new campaign.
Related flows
MarketingAdvanced
Competitor price change monitor
Check public product pages daily and get notified when a price changes.
HTTP Request → Google Sheets → Gmail5h/mo
MarketingEasy
Event signup → automatic calendar invite
People who register for your webinar or event get a Google Calendar invite instantly.
Webhook → Google Calendar → Google Sheets3h/mo
MarketingEasy
Automatic birthday emails
Customers or team members get a warm birthday email on their day.
Google Sheets → Gmail2h/mo