Back to blog
Chatmaid DevelopersAug 05, 2026·6 min read

How to Send WhatsApp Messages Directly from Google Sheets

Google Apps Script + Chatmaid gives you a zero-infrastructure WhatsApp sending capability built directly into the tool your team already uses. The setup takes about 15 minutes and requires zero ongoing maintenance. Get started: developers.chatmaid.net/signup — sandbox keys are free, so you can test every row of your sheet before going live.

How to Send WhatsApp Messages Directly from Google Sheets

Google Sheets is where a surprising amount of real business lives — contact lists, customer records, order logs, appointment schedules. For teams that live in spreadsheets, being able to trigger a WhatsApp message directly from a row of data is genuinely useful.

This guide shows you how to do exactly that, using Google Apps Script (Google's built-in scripting environment) and the Chatmaid API. No separate tools, no monthly automation platform fee, no coding experience required beyond copy-pasting.

What You'll Build

By the end of this guide, you'll have a Google Sheet that can:

  1. Send a WhatsApp message to any row — click a button next to a contact and send them a message
  2. Bulk-send to a filtered list — select a range and send a message to everyone in it
  3. Auto-send on trigger — automatically WhatsApp a contact when their row status changes to "Send"

Prerequisites

  • A Google account with Google Sheets access
  • A Chatmaid Developers account (sandbox is free)
  • A WhatsApp number connected to Chatmaid via QR scan

Part 1: Setting Up Your Sheet

Create a Google Sheet with at least these columns:

A: Name

B: Phone

C: Message

D: Status

Ana García

+50761234567

Hi Ana, your appointment is tomorrow at 10am

Pending

Carlos Ruiz

+50762345678

Hi Carlos, your order has shipped

Pending

  • Phone must be in international format: +[country code][number] with no spaces or dashes
  • Message is the text to send (can be personalized per row)
  • Status will update to "Sent" after the message is delivered

Part 2: Opening the Apps Script Editor

In your Google Sheet:

  1. Click Extensions in the menu bar
  2. Click Apps Script
  3. A new tab opens with a code editor

Delete the default myFunction() code. You'll replace it with the scripts below.

Part 3: The Core Script

Paste this into the Apps Script editor:

javascript

// ============================================= // CHATMAID WHATSAPP INTEGRATION // ============================================= const CHATMAID_API_KEY = 'sk_live_xxxxxxxxxxxx'; // Replace with your key const SENDER_PHONE = '+15551234567'; // Replace with your connected number const API_URL = 'https://developers-api.chatmaid.net/v1/messages/send'; // Column positions (1-indexed) const COL_NAME = 1; // Column A const COL_PHONE = 2; // Column B const COL_MESSAGE = 3; // Column C const COL_STATUS = 4; // Column D /** * Send WhatsApp to a single row * Call this from a button or menu */ function sendToSelectedRow() { const sheet = SpreadsheetApp.getActiveSheet(); const row = sheet.getActiveRange().getRow(); if (row <= 1) { SpreadsheetApp.getUi().alert('Please select a data row (not the header).'); return; } const name = sheet.getRange(row, COL_NAME).getValue(); const phone = sheet.getRange(row, COL_PHONE).getValue().toString(); const message = sheet.getRange(row, COL_MESSAGE).getValue(); const status = sheet.getRange(row, COL_STATUS).getValue(); if (status === 'Sent') { SpreadsheetApp.getUi().alert(`Already sent to ${name}.`); return; } const result = sendWhatsApp(phone, message); if (result.success) { sheet.getRange(row, COL_STATUS).setValue('Sent'); sheet.getRange(row, COL_STATUS).setBackground('#d4edda'); // Green SpreadsheetApp.getUi().alert(`✅ Sent to ${name} (${phone})`); } else { sheet.getRange(row, COL_STATUS).setValue('Error: ' + result.error); sheet.getRange(row, COL_STATUS).setBackground('#f8d7da'); // Red } } /** * Send WhatsApp to all rows where Status = "Pending" */ function sendToAllPending() { const sheet = SpreadsheetApp.getActiveSheet(); const lastRow = sheet.getLastRow(); const ui = SpreadsheetApp.getUi(); const confirm = ui.alert( 'Send to all Pending?', `This will send WhatsApp messages to all rows with status "Pending". Continue?`, ui.ButtonSet.YES_NO ); if (confirm !== ui.Button.YES) return; let sent = 0; let errors = 0; for (let row = 2; row <= lastRow; row++) { const status = sheet.getRange(row, COL_STATUS).getValue(); if (status !== 'Pending') continue; const phone = sheet.getRange(row, COL_PHONE).getValue().toString(); const message = sheet.getRange(row, COL_MESSAGE).getValue(); const name = sheet.getRange(row, COL_NAME).getValue(); if (!phone || !message) continue; const result = sendWhatsApp(phone, message); if (result.success) { sheet.getRange(row, COL_STATUS).setValue('Sent'); sheet.getRange(row, COL_STATUS).setBackground('#d4edda'); sent++; } else { sheet.getRange(row, COL_STATUS).setValue('Error'); sheet.getRange(row, COL_STATUS).setBackground('#f8d7da'); errors++; } // Pause 500ms between sends to avoid rate limiting Utilities.sleep(500); } ui.alert(`Done! Sent: ${sent} | Errors: ${errors}`); } /** * Core send function — calls the Chatmaid API */ function sendWhatsApp(to, content) { try { const payload = { fromPhoneId: SENDER_PHONE, to: to.toString().trim(), content: content.toString() }; const options = { method: 'POST', headers: { 'Authorization': 'Bearer ' + CHATMAID_API_KEY, 'Content-Type': 'application/json' }, payload: JSON.stringify(payload), muteHttpExceptions: true }; const response = UrlFetchApp.fetch(API_URL, options); const responseCode = response.getResponseCode(); const responseBody = JSON.parse(response.getContentText()); if (responseCode === 200 || responseCode === 201) { return { success: true, messageId: responseBody.messageId }; } else { console.error('Chatmaid error:', responseBody); return { success: false, error: responseBody.error?.code || 'unknown_error' }; } } catch (e) { console.error('Request failed:', e); return { success: false, error: e.message }; } } /** * Add a custom menu to the sheet */ function onOpen() { SpreadsheetApp.getUi() .createMenu('📱 WhatsApp') .addItem('Send to selected row', 'sendToSelectedRow') .addItem('Send to all Pending', 'sendToAllPending') .addSeparator() .addItem('Reset all to Pending', 'resetAllToPending') .addToUi(); } /** * Reset all statuses to Pending (for re-sending campaigns) */ function resetAllToPending() { const sheet = SpreadsheetApp.getActiveSheet(); const lastRow = sheet.getLastRow(); for (let row = 2; row <= lastRow; row++) { sheet.getRange(row, COL_STATUS).setValue('Pending'); sheet.getRange(row, COL_STATUS).setBackground(null); } }

Save the script (Ctrl+S or Cmd+S).

Part 4: Authorizing the Script

The first time you run any function, Google will ask for permission to:

  • Access your spreadsheet
  • Make external HTTP requests (to call the Chatmaid API)

Click Review Permissions → Advanced → Go to [your script name] → Allow.

This is a one-time step. Once authorized, the script runs without prompting.

Part 5: Using the Sheet

After saving the script, refresh your Google Sheet. A new menu item appears: 📱 WhatsApp.

To send to one person:

  1. Click on any cell in their row
  2. Click 📱 WhatsApp → Send to selected row
  3. The status column updates to "Sent" (green) or "Error" (red)

To send to everyone pending:

  1. Click 📱 WhatsApp → Send to all Pending
  2. Confirm the dialog
  3. Watch each row update in real time

Part 6: Personalizing Messages with Row Data

Instead of a static message column, you can build messages dynamically using data from other columns. Modify the sendToAllPending function to construct the message:

javascript

// Replace the message variable with this: const name = sheet.getRange(row, COL_NAME).getValue(); const appointment = sheet.getRange(row, 5).getValue(); // Column E: Appointment date const message = `Hi ${name}! This is a reminder that your appointment is scheduled for ${appointment}. Reply CONFIRM to confirm or RESCHEDULE to change it.`;

Now every message is personalized with the customer's name and appointment date from the sheet.

Part 7: Auto-Send on Status Change (Advanced)

Want messages to send automatically when you change a cell? Use an onEdit trigger.

javascript

function onEdit(e) { const sheet = e.source.getActiveSheet(); const row = e.range.getRow(); const col = e.range.getColumn(); // Trigger when Status column (D) is changed to "Send" if (col === COL_STATUS && e.value === 'Send') { const phone = sheet.getRange(row, COL_PHONE).getValue().toString(); const message = sheet.getRange(row, COL_MESSAGE).getValue(); const result = sendWhatsApp(phone, message); if (result.success) { e.range.setValue('Sent'); e.range.setBackground('#d4edda'); } else { e.range.setValue('Error'); e.range.setBackground('#f8d7da'); } } }

Now your team can trigger WhatsApp messages from anywhere in the organization just by typing "Send" in the status column — no technical knowledge required.

Use Cases

Appointment reminders — A column per client with their appointment time. Run "Send to all Pending" the day before.

Order notifications — Paste your order export, set the message column to "Your order #X has shipped", blast in one click.

Lead follow-up — Sales team updates a status in the sheet; the WhatsApp fires automatically.

Payment reminders — Filter overdue invoices into the sheet, customize the message, send.

Event invitations — Upload your invite list, write the message once, send to all.

Rate Limiting Note

The script includes a 500ms pause between sends (Utilities.sleep(500)). For large lists (500+ contacts), increase this to 1000ms to stay comfortably within Chatmaid's rate limits.

For very large campaigns (thousands of contacts), consider moving to a proper automation platform (n8n, Make) rather than Apps Script, as Apps Script has a 6-minute execution time limit per run.