
Automate lead follow-up for free: instant alerts and call-back reminders
Automate lead follow-up for free with Google Forms, Sheets and Apps Script: an instant email alert, a shared lead list and a reminder when nobody calls back.
To automate lead follow-up for free, link a Google Form to a Google Sheet and add a short Google Apps Script. It emails you an alert with the prospect’s name and phone number as soon as the form is sent, logs the enquiry in a Leads tab and reminds you if it is still marked New an hour later. It runs on a free Google account, within its limit of 100 email recipients a day.
The enquiry that waits until tomorrow is often the one a competitor answers today. To automate lead follow-up for free, you need three things: an alert the moment an enquiry arrives, one list where every enquiry has a status, and a reminder when nobody has called back. A Google Form, a Google Sheet and one short Google Apps Script do all three, on a free Google account.
I bring one of my clients, Pilotech, about ten prospects a day. At one point there were more than the team could handle, and the founder asked me for an app to see everything clearly and never forget to call a prospect back. That app is custom-coded and does far more than follow-up. You do not need one to start: the setup below covers the two things that matter most, the alert and the reminder.
This tutorial takes you from an empty form to working alerts in six steps, with code you can copy as it is. It is part of my guide to AI for small businesses.
What you need to automate lead follow-up for free
Everything happens in one Google spreadsheet, in three parts:
| Part | What it does | When |
|---|---|---|
| Instant alert | Emails you the prospect’s name and phone number in the subject line, with every answer in the body | As soon as the form is sent |
| Follow-up list | Keeps one row per enquiry in a Leads tab, with a status: New, Called, Quote sent or Not interested | Filled in by the script, updated by you |
| Call-back reminder | Emails you the leads still marked New after an hour | Checked every 15 minutes, during your working hours |
You need a Google account (a free Gmail account works), a computer for the setup, and a phone with your email app and the Google Sheets app for daily use.
Google Forms can already email you when a response arrives: in the Responses tab, the three-dot menu offers Get email notifications for new responses. Each collaborator has to switch it on for themselves, though, and it keeps no follow-up list and reminds nobody. The script adds those two parts.
Why speed matters, and why missed calls count too
An enquiry is at its most valuable in the first hour. A study published in Harvard Business Review in 2011, based on 1.25 million leads received by US companies, found that firms that tried to reach a lead within an hour were nearly seven times as likely to qualify it as firms that tried even an hour later (HBR). In the same article, 23% of the companies audited never responded at all.
With cold emailing, the first answers come quickly. I do everything for my clients except replying: replies and calls go to the client, and the first results arrive within the first 36 hours. So the follow-up has to be ready before the first email goes out.
Many of those prospects do not reply: they call. I put a phone number in the email and invite them to. A call is faster than a reply that gets buried among other emails, it feels like ticking an item off a to-do list, and people like talking to a real person. I go into the reasons in cold calling vs cold emailing. For your follow-up, it means that missed calls belong in the same list as the forms, or they get forgotten. Step 6 shows how.
Step 1: create the enquiry form
In Google Forms (forms.google.com), create a blank form and add four questions. Keep these titles, or note yours: the script finds each answer by its exact title.
| Question title | Type | Required |
|---|---|---|
| Name | Short answer | Yes |
| Phone number | Short answer | Yes |
| Short answer | No | |
| What do you need? | Paragraph | Yes |
Make the phone number required: if a prospect prefers to talk, you need a number to call back. In the form description, add one sentence on how you use the details, with a link to your privacy notice.
Then click Publish (top right): an unpublished form accepts no responses. To put it on your website, open the three-dot menu, choose Embed HTML (on some accounts, Send then the < > icon) and paste the code into a page, or put the link from Copy responder link behind a button.
Step 2: link the form to a Google Sheet
- In the form, open the Responses tab and click Link to Sheets.
- Choose to create a new spreadsheet, and confirm.
- In the spreadsheet that opens, go to File > Settings and check the time zone (London for the UK): the reminders follow it.
The first tab holds the raw responses, one row per enquiry. Leave it as it is: the script keeps its own list in a separate tab.
Step 3: paste the script
In the spreadsheet, click Extensions > Apps Script. The editor opens in a new tab with an empty function called myFunction. Delete it, paste the code below and change the settings at the top:
ALERT_TO: who receives the alerts and reminders. Separate several addresses with commas.QUESTIONS: the titles of your questions, if they differ from the table above.OPEN_HOURandCLOSE_HOUR: your working hours, on the 24-hour clock. Reminders go out only between these hours, seven days a week; alerts go out at any time.
/** @OnlyCurrentDoc */
// Lead follow-up: instant alert, Leads list and call-back reminder.
// Settings: change these lines only
const ALERT_TO = 'you@example.co.uk'; // several addresses: separate them with commas
const LEADS_TAB = 'Leads';
const REMIND_AFTER_MINUTES = 60; // remind when a lead is still New after this delay
const OPEN_HOUR = 8; // reminders only between these hours (24-hour clock)
const CLOSE_HOUR = 19;
const QUESTIONS = { // the exact titles of your form questions
name: 'Name',
phone: 'Phone number',
email: 'Email',
message: 'What do you need?',
};
// Run once: creates the Leads tab and the two triggers
function setup() {
const ss = SpreadsheetApp.getActive();
let sheet = ss.getSheetByName(LEADS_TAB);
if (!sheet) {
sheet = ss.insertSheet(LEADS_TAB);
sheet.appendRow(['Received', 'Name', 'Phone', 'Email', 'Message', 'Status', 'Reminder sent']);
}
const statuses = SpreadsheetApp.newDataValidation()
.requireValueInList(['New', 'Called', 'Quote sent', 'Not interested']).build();
sheet.getRange('F2:F').setDataValidation(statuses);
ScriptApp.getProjectTriggers().forEach((t) => ScriptApp.deleteTrigger(t));
ScriptApp.newTrigger('onNewEnquiry').forSpreadsheet(ss).onFormSubmit().create();
ScriptApp.newTrigger('remindUncalledLeads').timeBased().everyMinutes(15).create();
}
// Runs by itself each time the form is sent
function onNewEnquiry(e) {
const ss = SpreadsheetApp.getActive();
const answer = (title) => (e.namedValues[title] || [''])[0];
const name = answer(QUESTIONS.name);
const phone = answer(QUESTIONS.phone);
const details = Object.keys(e.namedValues)
.map((title) => title + ': ' + e.namedValues[title].join(', ')).join('\n');
MailApp.sendEmail(ALERT_TO, 'New enquiry: ' + name + ', ' + phone,
details + '\n\nFollow-up list: ' + ss.getUrl());
// The ' keeps answers as text: a leading 0 stays and no formula can run
ss.getSheetByName(LEADS_TAB).appendRow([new Date(), "'" + name, "'" + phone,
"'" + answer(QUESTIONS.email), "'" + answer(QUESTIONS.message), 'New', '']);
}
// Runs every 15 minutes: one reminder per lead still New after the delay
function remindUncalledLeads() {
const ss = SpreadsheetApp.getActive();
const zone = ss.getSpreadsheetTimeZone();
const hour = Number(Utilities.formatDate(new Date(), zone, 'H'));
if (hour < OPEN_HOUR || hour >= CLOSE_HOUR) return;
const sheet = ss.getSheetByName(LEADS_TAB);
const rows = sheet.getDataRange().getValues();
const waiting = [];
for (let i = 1; i < rows.length; i++) {
const [received, name, phone, email, message, status, reminded] = rows[i];
if (status !== 'New' || reminded) continue;
if (!(received instanceof Date)) { // row typed by hand: the clock starts now
sheet.getRange(i + 1, 1).setValue(new Date());
continue;
}
if (Date.now() - received.getTime() < REMIND_AFTER_MINUTES * 60000) continue;
waiting.push(name + ', ' + phone + ', received ' + Utilities.formatDate(received, zone, "dd/MM 'at' HH:mm"));
sheet.getRange(i + 1, 7).setValue(new Date());
}
if (waiting.length > 0) {
MailApp.sendEmail(ALERT_TO, 'Call back: ' + waiting.length + ' lead(s) still waiting',
waiting.join('\n') + '\n\nFollow-up list: ' + ss.getUrl());
}
}
Save with Ctrl+S (Cmd+S on a Mac), then click the project’s name at the top to rename it, for example Lead follow-up.
What the script does
setupcreates the Leads tab, its status dropdown and two triggers, which tell Google to run a function by itself: one on each form submission, one every 15 minutes. It deletes the old triggers first, so running it twice never doubles the alerts.onNewEnquirysends the alert and adds the enquiry to the Leads tab as New.remindUncalledLeadssends one email for the leads still marked New after the delay and writes the time in the Reminder sent column, so each lead is reminded only once.
The first line, @OnlyCurrentDoc, restricts the script to this spreadsheet: it cannot open your other files. It sends through MailApp, a service that can send email but cannot read your inbox.
Step 4: run the setup and authorise the script
- In the toolbar, pick
setupin the list of functions and click Run. - Google asks for your permission: click Review permissions and choose your account.
- On a free Gmail account, Google will probably warn that it hasn’t verified the app. That is expected for a script you created and Google has not reviewed: click Advanced, then Go to Lead follow-up (unsafe).
- Allow every permission listed: editing this spreadsheet, sending email as you and running when you are not there. If Google shows checkboxes, tick them all, or the script stops with a permission error.
The execution log at the bottom of the editor shows the run complete. Back in the spreadsheet, a Leads tab has appeared, with a dropdown in the Status column. In the editor’s left sidebar, click the clock icon (Triggers): two triggers are listed, one for form submissions and one time-driven.
Step 5: test the alert and the reminder
- Open the form as a visitor would, with the link from Copy responder link, and send a test enquiry with your own name and phone number.
- The alert should reach your inbox within moments, with the name and number in the subject line. If it does not, check your spam folder.
- In the Leads tab, the enquiry appears with the status New.
- To test the reminder without waiting an hour, set
REMIND_AFTER_MINUTESto 0, save, pickremindUncalledLeadsin the list of functions and click Run, during your working hours. A reminder arrives, and the Reminder sent column shows the time. - Set
REMIND_AFTER_MINUTESback to 60, save, and set the test lead to Not interested.
Step 6: use it every day, missed calls included
From now on, the only manual step is the status. Whoever calls a prospect back changes New to Called, then to Quote sent or Not interested. The Google Sheets app on a phone is enough for that, between appointments.
- Missed calls: when you miss a call and cannot return it straight away, add a row to the Leads tab with the name, the phone number (start it with an apostrophe, as in
'07700900123, or Sheets may drop the leading 0), “Missed call” in Message and New in Status. Leave Received empty: the script fills in the time at its next check, and the reminder works as it does for a form. - The team: share the spreadsheet with the people who call prospects back (Share, top right) and add their addresses to
ALERT_TOif they should get the alerts. - The columns: do not rename, move or delete the seven columns of the Leads tab, because the script reads them by position. Add your own from column H onwards.
Keep the list lean
The Leads tab and the alert emails hold personal data: names, phone numbers, sometimes the details of a project. Decide how long you keep leads who never became clients. The ICO’s guidance on storage limitation says the law sets no fixed period: you choose one you can justify, and you cannot keep data just in case. Once a month, delete the rows and the alert emails you no longer need.
Google Apps Script limits on a free account
Google sets daily quotas for each account. These are the ones that matter here, at the time of writing (October 2026):
| Free Gmail account | Google Workspace | |
|---|---|---|
| Email recipients a day, all scripts together | 100 | 1,500 |
| Time per run | 6 minutes | 6 minutes |
| Total trigger time a day | 90 minutes | 6 hours |
Each alert counts one recipient per address in ALERT_TO. With ten enquiries a day sent to two people, the alerts use 20 recipients and the reminders a few more: well within the free limit. A run of this script takes seconds, so its 96 checks a day stay far below the trigger limit.
Google resets the quotas 24 hours after the first request and can change them without notice: check the Apps Script quotas page if your volume grows.
Troubleshooting
The Executions page, in the editor’s left sidebar, lists every run with its status and any error message.
| Symptom | Likely cause | Fix |
|---|---|---|
| No alert after a test | A typo in ALERT_TO, or the email went to spam | Check the address and the spam folder, then the Executions page |
Error Cannot read properties of undefined (reading 'namedValues') | onNewEnquiry was started with Run, but it needs a form submission | Test by sending the form |
| Two alerts per enquiry | A second form trigger, for example one added by hand | Run setup again: it deletes the old triggers first |
| Name or phone empty in the Leads tab | A title in QUESTIONS differs from the form | Copy the titles from the form, character for character |
| No reminder | Status not exactly New, outside working hours, or the wrong time zone | Check the Status cell, the hour settings and File > Settings |
Error Service invoked too many times for one day: email | The daily email quota is used up | Fewer addresses in ALERT_TO, or a Workspace account |
When to move on to Zapier, Make or an app of your own
This setup suits one or two people and up to a few dozen enquiries a day, the point where a free account’s 100 email recipients start to run short. Three signs you have outgrown it:
- Your enquiries come from several places (website, booking tool, email, phone) and you want them in one list without copying anything. Connector tools do this without code: at the time of writing, Zapier’s free plan includes 100 tasks a month and Make’s 1,000 credits, and my comparison of Zapier, Make and n8n shows what each costs beyond that.
- Leads turn into jobs, schedules and invoices, and several people need different views. That is where my client needed a custom app: prospects, job sites, messages to the team, the calendar and accounting analytics in one place, with AI and phone integrations. My guide to a bespoke CRM helps you decide whether you are there.
- You want help sorting or answering enquiries. An AI step can label each one (quote request, question, spam) or draft a reply, and my Claude API tutorial shows how to get a key with a spending limit. Keep the call itself human.
If too few enquiries arrive in the first place, the problem is upstream: my guide on why a website gets no enquiries shows where visitors drop off. My tutorial to build a funnel with the tools you already have covers that upstream part.
You do not need me to set this up: the six steps and a test enquiry are enough. Run it for a month, missed calls included, and you will know how quickly you really call back, and what the next tool has to do.
Frequently asked questions
Is Google Apps Script free?
Does the script keep running when my computer is off?
My website form is not a Google Form. Can I still use this?
Can I get a text message instead of an email?
How do I switch the alerts off?
Joana MehouWeb designer, SEO and cold emailing specialist
Joana Mehou has been building websites since the age of eleven and founded MLK Web Studio in 2021, between London and Paris: websites, SEO, cold emailing and automation for small businesses in the UK and France, with honest advice, including when you do not need to hire anyone.
More about the studioInternal tools and automations built around how your business actually works.
Zapier vs Make vs n8n: which automation tool suits a small business?
Zapier vs Make vs n8n for a small business: October 2026 prices, what tasks, credits and executions really cost, AI steps, GDPR and which one to pick.
Bespoke CRM for a small business: the internal app I built when leads piled up
A bespoke CRM pays off when your work does not fit standard software. Five questions to decide, the costs to plan for, and the app I built for a client.
Website not getting enquiries? Where visitors drop off and how to fix it
Website not getting enquiries? Find where visitors drop off with free tools, then fix the usual leaks: a vague offer, a hidden phone number, a long form.