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.

Medium Saves ~6 hours/month MarketingBy Flowngn team

Works with n8n · Make · Zapier

How it works

Trigger: Manual — you click Run when the offer is ready
  1. Read your Contacts sheet (phone, name, opted_in, sent).
  2. Keep contacts who opted in and haven't received this campaign yet.
  3. Send each one your approved WhatsApp marketing template.
  4. Mark the row as sent, so running it again never sends twice.

Diagram

true▶Run campaignManual TriggerGRead contactsGoogle Sheets⑂Opted in, not sent?IfWSend offerWhatsApp Business CloudGMark as sentGoogle Sheets
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.

Workflow JSON
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": []
}

Open in the playground to edit →

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