Skip to content

Guide · For businesses

How to send WhatsApp messages from Google Sheets automatically (form rows, daily reminders and batches)

Four ways to turn rows in a Google Sheet into approved WhatsApp template messages, with working Apps Script code, a gym renewal reminder example, phone-number cleaning and the limits of each method.

By Broadchat teamPublished 8 min read

हिन्दी में पढ़ें

In short

To send WhatsApp messages from Google Sheets automatically, have a small Google Apps Script call a Broadchat workflow's Custom Webhook URL with the row's data, and let the workflow send an approved template. Use an On form submit trigger for instant messages on new rows, and a daily time-driven trigger for reminders such as renewals. For one-off sends, download the sheet as CSV and use a bulk campaign instead.

Key takeaways

  • A new or edited row does not start anything by itself; Apps Script triggers (on form submit, time-driven) are what make a sheet 'automatic'.
  • Let the script decide which rows are due and post one row per webhook call; the workflow only has to send the template.
  • Every send must be an approved template to an opted-in number with country code, for example 919876543210.
  • Write a Sent marker back to the sheet so a row is never messaged twice, whichever method you use.
  • Reading the sheet from inside Broadchat works too, but each Google Sheets step uses a paid task and long loops hit run limits.

Send WhatsApp template messages from a Google Sheet automatically

Time needed: 1 h. You will need: A Google Sheet you can edit, Google Apps Script (Extensions → Apps Script), Broadchat panel with Automations.

  1. Prepare the sheet

    Put headers in row 1 (Name, Phone, Plan, Expiry, Status) and phone numbers in one column. Add a Status column the automation will fill so no row is messaged twice.

  2. Create the workflow that sends the template

    In Automations → Workflow, create a workflow with the Custom Webhook trigger, generate the hook, and add Send Template Message (V2) mapping WhatsApp Number and variables from the webhook fields.

  3. Add the Apps Script

    In the sheet open Extensions → Apps Script, paste the script, store the Webhook URL in Script Properties, and run it once to grant permissions.

  4. Add the trigger

    In Apps Script's Triggers page, add an On form submit trigger for instant messages or a Time-driven Day timer for daily reminders.

  5. Capture, test and switch on

    Use Capture Incoming Webhook with one test row addressed to your own number, map the fields, then activate the workflow and check the run history and the Status column.

Which method fits your sheet

You can send WhatsApp messages from Google Sheets in four ways, and the right one depends on when a row should produce a message:

SituationMethodRuns
A Google Form adds a row and the person should get a WhatsApp at onceApps Script On form submit → workflow webhookInstantly, per row
Reminders that depend on a date in the sheet (renewals, fee due, appointments)Apps Script Time-driven trigger selects due rows → webhookOnce a day
You prefer to keep everything inside BroadchatWorkflow with Get Rows Data → Iterator → Send TemplateWhen the workflow is called
A one-off announcement to everyone in the sheetDownload as CSV → CRM → Bulk CampaignOnce, with a report

Whatever you choose, the WhatsApp rules are the same: you can start a conversation only with an approved message template, only to people who agreed to receive WhatsApp messages from you, and each number needs its country code.

The example: FitZone gym's membership renewal reminders

FitZone, a gym in Indore, keeps members in a Google Sheet. Three days before a membership ends, the member should get a WhatsApp reminder, and the front desk should be able to see who was reminded. The sheet looks like this:

NamePhonePlanExpiryStatus
Priya Malviya9826012345Quarterly15/10/2026
Arjun Rathore+91 98930 54321Annual18/10/2026

The utility template, approved in CRM → WhatsApp Templates, is factual and has no offer in it (Meta may recategorise templates that promote):

Step 1: prepare the sheet

Keep headers in row 1 and one row per person. The Status column is the most important: the automation writes Sent 12-10-2026 there, so the same member is never messaged twice, even if the script runs again. Phone numbers can be messy (spaces, +91, missing 91); the workflow below cleans them, but if your customers are outside India, store full international numbers instead.

Step 2: create the workflow that sends the template

  1. In Automations → Workflow, click Create Workflow and rename it "FitZone renewal reminder".
  2. Add the Webhook app's Custom Webhook trigger, enter a Webhook Title, click + Generate Hook and copy the Webhook URL.
  3. Add CRM → Send Template Message (V2): Select Channel, Select Template membership_expiry_reminder, WhatsApp Number 91slice(parseNumber({{1.phone}});-10), variable 1 {{1.name}}, variable 2 {{1.plan}}, variable 3 {{1.expiry}}.
  4. Optionally add CRM → Assign Tags to Contact (Creates Tag if Tag not exist) with renewal-due, so the front desk can filter these members in the inbox and a segment.

The number formula strips everything except digits, keeps the last ten and puts 91 in front, so 9826012345, 09826012345 and +91 98930 54321 all become valid Indian WhatsApp numbers. The step needs the country code; a number shorter than eight digits fails.

Step 3: add the Apps Script

In the sheet, open Extensions → Apps Script. In Project Settings, add a Script Property BROADCHAT_HOOK with the Webhook URL (keeping it out of the code means a shared sheet does not expose it). Then paste:

// FitZone: send WhatsApp renewal reminders 3 days before expiry
const SHEET_NAME = 'Members';
const DAYS_BEFORE = 3;

function sendRenewalReminders() {
  const hook = PropertiesService.getScriptProperties().getProperty('BROADCHAT_HOOK');
  const sheet = SpreadsheetApp.getActive().getSheetByName(SHEET_NAME);
  const rows = sheet.getDataRange().getValues();
  const head = rows[0];
  const col = (name) => head.indexOf(name);
  const tz = Session.getScriptTimeZone();
  const target = new Date();
  target.setDate(target.getDate() + DAYS_BEFORE);
  const targetText = Utilities.formatDate(target, tz, 'dd/MM/yyyy');

  for (let r = 1; r < rows.length; r++) {
    const row = rows[r];
    if (row[col('Status')]) continue; // already handled
    const expiry = row[col('Expiry')] instanceof Date
      ? Utilities.formatDate(row[col('Expiry')], tz, 'dd/MM/yyyy')
      : String(row[col('Expiry')]);
    if (expiry !== targetText) continue; // not due today

    const res = UrlFetchApp.fetch(hook, {
      method: 'post',
      contentType: 'application/json',
      payload: JSON.stringify({
        name: String(row[col('Name')]).split(' ')[0],
        phone: String(row[col('Phone')]),
        plan: row[col('Plan')],
        expiry: expiry
      }),
      muteHttpExceptions: true
    });
    const ok = res.getResponseCode() === 200;
    sheet.getRange(r + 1, col('Status') + 1)
      .setValue((ok ? 'Sent ' : 'Error ' + res.getResponseCode() + ' ') +
        Utilities.formatDate(new Date(), tz, 'dd-MM-yyyy'));
  }
}

Click Run once and approve the permissions Google asks for (access to this spreadsheet and to external URLs). A 200 response means Broadchat accepted the request and started the workflow; the WhatsApp delivery itself shows in the workflow's run history.

For the Google Form version, use the form's submission instead of a loop:

function onFormSubmit(e) {
  const v = e.namedValues; // e.g. { 'Name': ['Priya'], 'WhatsApp number': ['9826012345'] }
  const hook = PropertiesService.getScriptProperties().getProperty('BROADCHAT_HOOK');
  UrlFetchApp.fetch(hook, {
    method: 'post',
    contentType: 'application/json',
    payload: JSON.stringify({ name: v['Name'][0], phone: v['WhatsApp number'][0] }),
    muteHttpExceptions: true
  });
}

Add a consent question to the form ("Send me updates on WhatsApp: Yes") and only post when it is Yes.

Step 4: add the trigger

In the Apps Script editor, open Triggers (the clock icon) and click Add Trigger:

  • Daily reminders: function sendRenewalReminders, event source Time-driven, type Day timer, time of day such as 9 am to 10 am.
  • Form rows: function onFormSubmit, event source From spreadsheet, event type On form submit.

This is how the sheet becomes automatic: Broadchat workflows have no scheduled trigger and no Google Sheets trigger, so the schedule lives in Google and the sending lives in Broadchat.

Step 5: capture, test and switch on

  1. Put a test row with your own number and an expiry three days from today.
  2. In the workflow, click Capture Incoming Webhook, then run sendRenewalReminders from Apps Script. Click Show Received Data to confirm the fields name, phone, plan and expiry.
  3. Clear the test row's Status, save the workflow and switch it to Active. Run the script again: you should receive the reminder and see Sent … in the Status column.
  4. If nothing arrives, open the workflow's History: a failed step shows the error, such as a number without country code or a low channel wallet balance.

Doing it all inside Broadchat

If you prefer not to write any script, a workflow can read the sheet itself. Connect Google once in Automations → App Authentications (Add Connection, then Google (Sheets, Drive, Meet)), then build: a Custom Webhook trigger, Google Sheet → Get Rows Data (Spreadsheet ID and Sheet Name), an Iterator with Array {{2.rows}}, a filter on the next connection such as {{3.element.data.Status}} Not Exist, Send Template Message (V2) with {{3.element.data.Phone}}, and Google Sheet → Update Row with Row Number {{3.element.row_number}} and Status = Sent.

Two limits make this best for small lists: every Google Sheets step uses one paid task from your plan, and a single run stops after 400 steps, so a loop with two steps per row handles fewer than 200 rows per call. You still need something to call the webhook each day, which brings you back to an Apps Script trigger. The Google Sheets integration page covers the app's other actions, such as lookups.

One-off sends: use a campaign

For a single announcement ("the gym is closed on Diwali"), automation is overkill. Download the sheet as CSV, open CRM → Bulk Campaign, create a campaign with the Quick audience, upload the CSV and map its columns to the template variables. You get delivery and read reports per number. A Quick audience does not skip contacts marked as unsubscribed, so clean the list first, or import it into contacts and send to a segment. The guide to sending bulk WhatsApp messages without getting blocked covers pacing and quality.

Costs and good practice

  • Utility templates such as reminders are charged per delivered message: ₹0.115 per utility message to India (Meta rate card effective 1 Oct 2026, excl. GST), from the channel's messaging wallet. See WhatsApp API pricing.
  • Each workflow step counts as a task; the webhook method above uses two or three free tasks per member and no paid tasks.
  • Send reminders in daytime hours and keep them factual. A reminder that turns into an offer is a marketing template, priced and limited differently.

For how triggers, workflows and webhooks fit together, read the WhatsApp automation workflows guide; for the basics, what the WhatsApp Business API is. Agencies that build sheet-based reminders for gyms, clinics and coaching centres can sell them under their own brand with the white-label platform.

Sources

  1. Installable triggers — Google for Developers, checked 12 October 2026
  2. Class UrlFetchApp — Google for Developers, checked 12 October 2026
  3. Send message templates — Meta for Developers, checked 12 October 2026
  4. Pricing on the WhatsApp Business Platform — Meta for Developers, checked 12 October 2026

Broadchat team · Product and partner success team

The people who build and support Broadchat, the white-label WhatsApp Business API platform. We write from what we see while onboarding partners and their clients on the official WhatsApp Cloud API, and we check every article against Meta's current documentation.

Last updated:

Frequently asked questions

Can a new row in Google Sheets send a WhatsApp message by itself?

Not without a trigger. Use a Google Apps Script with an On form submit or time-driven trigger to call a Broadchat workflow's Custom Webhook URL, and send an approved template from that workflow.

Do I need the Google Sheets app connected in Broadchat for this?

Not for the Apps Script method, where the script reads the sheet and posts each row to the webhook. You need the Google connection only if the workflow itself reads or updates the sheet with Google Sheet steps.

How do I stop the same person getting the message twice?

Write a marker to a Status column when a row is sent, and skip rows that already have one. The script in this guide does that automatically, including writing the HTTP error code when a call fails.

What phone number format does WhatsApp need?

Digits with the country code and no plus sign or spaces, such as 919826012345 for an Indian mobile. The workflow formula 91slice(parseNumber(...);-10) converts common Indian formats; do not use it for international numbers.

See Broadchat on a real WhatsApp number

A short walkthrough of campaigns, chatbots, the team inbox and the partner panel, built around your use case.