Create a WhatsApp group from a Google Sheets row
Create a WhatsApp group from each row of a Google Sheet, with the group name and the members read from the row and the group id written back into it. An Apps Script function posts each row to Wapito: no add-on, no third party holding your data, and a re-run skips every row that already has an id.
Before you start
- A Google Sheet with one row per group: a name column, a description column and one column of phone numbers separated by commas.
- Edit access to the sheet so you can open Extensions and then Apps Script.
- A connected Wapito channel and its channel token, ready to paste into Script Properties rather than into the code.
Step by step in Google Sheets
Lay the sheet out with a write-back column
Give the sheet four columns in this order: Group name, Description, Members and Group id. Members holds phone numbers in international format separated by commas, and Group id stays empty until the script fills it. Format the Group id column as plain text before the first run, because the id is a numeric string longer than a number cell can hold and Sheets would otherwise round it.
Field map Wapito field Where it comes from descriptionColumn B — Description group_idColumn D — written back by the script, formatted as plain text participantsColumn C — Members, split on commas subjectColumn A — Group name Put the channel token in Script Properties
Open Extensions, then Apps Script, then Project Settings, and add a script property named WAPITO_TOKEN whose value is your channel token. The code reads it with PropertiesService.getScriptProperties().getProperty('WAPITO_TOKEN'), so anyone you share the sheet with can see the groups but never the token, and rotating it is a change to one property rather than to the script.
Field map Wapito field Where it comes from AuthorizationBearer + PropertiesService.getScriptProperties().getProperty('WAPITO_TOKEN') Write createGroupsFromSheet()
In the script editor write a function that reads getDataRange().getValues(), skips the header row and every row whose Group id cell is already filled, and for each remaining row builds the payload: the name as the subject, the description, and the Members cell split on commas with each entry trimmed. Keep the function small; the sheet is the queue and the id column is the record of what has been done.
Field map Wapito field Where it comes from descriptionrow[1] — sent only when the cell is not empty participantsrow[2].split(',').map(s => s.trim()).filter(Boolean) subjectrow[0] — trimmed Call UrlFetchApp.fetch with muteHttpExceptions
Post the payload to https://api.wapito.com/v1/groups with method post, contentType application/json, the Authorization header from Script Properties, payload set to JSON.stringify of the object, and muteHttpExceptions set to true. Without that last option a refused request throws before you can read the error body, and the error body is where Wapito tells you which number was not dialable.
Field map Wapito field Where it comes from contentTypeapplication/json headers.Authorization'Bearer ' + token methodpost muteHttpExceptionstrue payloadJSON.stringify({ subject, description, participants }) Write the group id back into the row
Read response.getResponseCode(); on 201 parse the body and write the id into the Group id cell of that row with setValue, prefixed with nothing and as a string. On any other code write the error code from the body into the same cell, prefixed with ERROR, so the row is visibly failed and the next run does not try it again until someone clears the cell.
Field map Wapito field Where it comes from error.codeJSON.parse(response.getContentText()).error.code → column D, prefixed with ERROR group_idJSON.parse(response.getContentText()).id → column D of the same row Add a time-driven trigger with a small batch
In Triggers add a time-driven trigger that runs the function every hour, and cap each run at a handful of rows with a counter, breaking out of the loop once it is reached. That keeps each execution well inside the Apps Script time limit, and it keeps group creation at a pace a person could plausibly manage, which matters more for the number's health than for the quota.
Field map Wapito field Where it comes from batch_sizeA constant in the script, for example 5 groups per run
Test it
Add one row whose Members cell holds only your own second phone, run createGroupsFromSheet from the editor, and authorise the script when prompted. Column D of that row should fill with an id ending in @g.us, the phone should show the new group, and running the function again should leave the row untouched.
Errors you may hit
- invalid_recipient 400Recipient is not valid
- invalid_request 400Request failed validation
- channel_not_connected 409Channel not connected
- unauthorized 401Missing or invalid token
- rate_limited 429Too many requests
Frequently asked questions
Is it safe to keep the token in Script Properties?
Safer than in the code, which is the alternative on this platform. Script Properties are visible only to people who can edit the script project, not to everyone who can view or edit the sheet, and they are not copied when someone duplicates the spreadsheet. If a collaborator with editor access leaves, rotate the token from the Wapito dashboard and update the property.
Why did the group id turn into a number with E+ in it?
The cell was formatted as a number, and Sheets converted the long digit string into scientific notation, losing the trailing digits. The id in that cell no longer names any group. Format the Group id column as plain text, clear the cell, and run the function again for that row; the script writes the id as a string, but a cell format wins over the value's type.
Will a large sheet hit Apps Script quotas?
Each row is one UrlFetchApp call, and Apps Script allows tens of thousands of those per day on an ordinary account, so the quota is not the constraint. The constraint is WhatsApp: creating groups in bulk from one number is the clearest automation signal there is. The batch cap in the last step is there for the number, and it makes a big sheet take days rather than minutes on purpose.
Can the sheet also send a first message to each new group?
Yes. After writing the id back, post to the text endpoint with that id as the recipient, in the same run or in a second function that processes rows whose id is set and whose Sent cell is empty. Keep it to one message per group and give it a typing time, so the welcome arrives a few seconds after the group appears instead of the same instant.
Related
Endpoints this recipe calls
Try it on your own number
Create a channel, link a WhatsApp number by QR or pairing code, and call the API in a couple of minutes. The Sandbox plan is free and needs no card.