A review request that asks once, and the three bugs that would have made it ask again
A standalone n8n template that texts each customer your Google review link after the job, never twice in 90 days and never at night. No database: it reads the Twilio message log before it asks. What the live runs found.
- build log
- automation
- n8n
- twilio
- sms
- reviews
- testing
Most small service businesses I talk to know reviews matter. Almost none of them ask. The owner finishes a job, drives to the next one, and the moment is gone.
So the fifth standalone template is the simplest one yet on paper. When a job is done, something posts the customer’s phone, name and the job to a webhook. A couple of hours later the customer gets one text with the business’s Google review link. That is it.
The hard part is the word “once”.
Never twice
Texting the same customer for a review every time you visit them is how a business number ends up reported as spam. So the template will not ask anyone twice inside 90 days.
There is no database. Before it sends, it pulls every text the business number has sent that customer in the last 90 days from Twilio’s message log, and looks for the review link. If it finds one, it skips the ask and tells the owner when the last one went out. Twilio already keeps that record, so the template does not keep a second copy.
Never at night
A job that finishes at 7pm with a two hour delay would land at 9pm. Quiet hours are worked out the moment the job comes in, and an ask that would land at night waits until the morning. The webhook answers straight away with the exact time the text will go out.
Everyone gets the same link
A lot of review tools send a “how did we do, 1 to 5” text first and only send the Google link to people who say 4 or 5. That is review gating, and Google does not allow it. This template sends everyone the same link. If an owner wants to catch unhappy customers, the better fix is to call them.
What the live runs found
I ran it against a real Twilio number with my own cell standing in as the customer. Ten runs. Three of them found bugs, and all three would have made it ask someone again or leave the owner guessing.
The memory never forgot. Two “job done” posts for the same customer a few seconds apart (a double tap, a retry) would both be waiting when the first text went out, so neither would see the other in the log. The template remembers waiting asks to stop that. The first version cleared that memory after the text went out. n8n did not keep the change, because it was made after a Wait. That customer would have stayed “waiting” forever. Now each entry simply expires two minutes after its planned send time, and from then on the Twilio log is the record.
A failed text counted as an ask. I sent to a number Twilio refuses, then tried again. The second run skipped the customer as “already asked”. Twilio logs failed attempts as outbound messages, and the check was counting them. A customer whose text never arrived would have been locked out for 90 days. Failed, undelivered and canceled texts are now ignored.
The failure text said nothing. When a send failed, the owner got “Twilio said: Bad request - please check your parameters”. n8n’s Twilio node throws away Twilio’s actual error. The customer text now goes straight to Twilio’s API, so the owner gets Twilio’s own reason and code. If the customer has replied STOP to the business before, it says that in plain words.
What is not covered
I did not have a number that had replied STOP, so that message is written but was not triggered. The default two hour delay and an overnight hold were not run end to end: I checked the planned resume time, which came out exactly on the minute, but did not wait for it. And every customer text went to the same phone.
The template, its test notes and the full list of runs are on GitHub.