Google Sheets + Twilio: qualify leads, follow up fast
Your lead sheet fills up. Then real life happens. And suddenly that “call them today” plan turns into “maybe tomorrow,” with half-finished notes and no clear status.
This is where Sheets Twilio follow-up automation helps. Marketing managers trying to prove pipeline impact feel it first, but business owners and client success leads get burned by the same lag and inconsistency.
This workflow qualifies new leads from Google Sheets with outbound calls, analyzes what happened, updates your sheet, and sends a follow-up email so warm prospects don’t drift away.
How This Automation Works
Here’s the complete workflow you’ll be setting up:
n8n Workflow Template: Google Sheets + Twilio: qualify leads, follow up fast
flowchart LR
subgraph sg0["Message a model Flow"]
direction LR
n3["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/webhook.dark.svg' width='40' height='40' /></div><br/>Webhook1"]
n4["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/code.svg' width='40' height='40' /></div><br/>Code"]
n5@{ icon: "mdi:robot", form: "rounded", label: "Message a model", pos: "b", h: 48 }
n6@{ icon: "mdi:swap-horizontal", form: "rounded", label: "If", pos: "b", h: 48 }
n7@{ icon: "mdi:database", form: "rounded", label: "Get row(s) in sheet1", pos: "b", h: 48 }
n8@{ icon: "mdi:swap-vertical", form: "rounded", label: "Edit Fields", pos: "b", h: 48 }
n9["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/merge.svg' width='40' height='40' /></div><br/>Merge"]
n12@{ icon: "mdi:database", form: "rounded", label: "Update Call Data", pos: "b", h: 48 }
n14@{ icon: "mdi:message-outline", form: "rounded", label: "Send Schedule Request", pos: "b", h: 48 }
n6 --> n9
n4 --> n5
n9 --> n7
n3 --> n4
n8 --> n12
n8 --> n9
n5 --> n6
n5 --> n8
n7 --> n14
end
subgraph sg1["Message a model1 Flow"]
direction LR
n1["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/webhook.dark.svg' width='40' height='40' /></div><br/>Webhook"]
n2["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/webhook.dark.svg' width='40' height='40' /></div><br/>Respond to Webhook"]
n10@{ icon: "mdi:robot", form: "rounded", label: "Message a model1", pos: "b", h: 48 }
n11@{ icon: "mdi:swap-vertical", form: "rounded", label: "Edit Fields1", pos: "b", h: 48 }
n13@{ icon: "mdi:database", form: "rounded", label: "Look up Customer Data", pos: "b", h: 48 }
n1 --> n11
n11 --> n13
n10 --> n2
n13 --> n10
end
subgraph sg2["Google Sheets Flow"]
direction LR
n0@{ icon: "mdi:play-circle", form: "rounded", label: "Google Sheets Trigger", pos: "b", h: 48 }
n15["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/httprequest.dark.svg' width='40' height='40' /></div><br/>Outbound Call"]
n0 --> n15
end
%% Styling
classDef trigger fill:#e8f5e9,stroke:#388e3c,stroke-width:2px
classDef ai fill:#e3f2fd,stroke:#1976d2,stroke-width:2px
classDef aiModel fill:#e8eaf6,stroke:#3f51b5,stroke-width:2px
classDef decision fill:#fff8e1,stroke:#f9a825,stroke-width:2px
classDef database fill:#fce4ec,stroke:#c2185b,stroke-width:2px
classDef api fill:#fff3e0,stroke:#e65100,stroke-width:2px
classDef code fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px
classDef disabled stroke-dasharray: 5 5,opacity: 0.5
class n0 trigger
class n5,n10 ai
class n6 decision
class n7,n12,n13 database
class n3,n1,n2,n15 api
class n4 code
classDef customIcon fill:none,stroke:none
class n3,n4,n9,n1,n2,n15 customIcon
Why This Matters: Slow lead follow-up kills momentum
Lead follow-up is one of those tasks that feels “simple” until you’re doing it at volume. You copy a phone number from Google Sheets, start a call, scribble notes somewhere else, then try to remember what to email and when. One distraction and the thread snaps. And because the “system” is really just a spreadsheet plus someone’s memory, the next person has no context. The cost isn’t only time. It’s missed intent, repeated questions, and leads that cool down while you’re still figuring out what happened.
The friction compounds. Here’s where it breaks down in day-to-day work.
- You end up calling too late because the sheet isn’t actively reminding you, and warm leads turn lukewarm fast.
- Call outcomes live in scattered places, which makes reporting messy and handoffs awkward.
- Follow-up emails get delayed or written inconsistently, so prospects receive mixed messaging.
- Status fields don’t stay accurate because updating them is boring, and boring tasks get skipped.
What You’ll Build: A lead-qualifying call + follow-up engine
This n8n workflow turns a simple “new row in Google Sheets” into a consistent, documented qualification touchpoint. When a lead lands in your sheet, it triggers an outbound call through your telephony provider (Twilio via an HTTP request, with ElevenLabs commonly used for the voice agent). During the call, your agent uses lead context pulled from Google Sheets to sound like it actually knows why it’s calling. After the call ends, a webhook receives the post-call data and transcript. OpenAI analyzes that transcript to extract intent and key details, then the workflow updates the original lead record with clean fields and an appropriate status. If the lead is a fit or needs next steps, Gmail sends a follow-up email (like a meeting link or recap) without you hunting for templates.
The workflow starts with a new lead in Sheets. Then it runs a call, captures the result, and has AI turn messy conversation into structured notes. Finally, your Google Sheet (and your inbox) reflects what happened so you can act quickly.
What You’re Building
| What Gets Automated | What You’ll Achieve |
|---|---|
|
|
Expected Results
Say you get 10 new leads a day in Google Sheets. Manually, you might spend about 10 minutes calling, 5 minutes writing notes, and 5 minutes sending a follow-up, which is roughly 20 minutes per lead (over 3 hours daily). With this workflow, you’re mainly confirming the sheet columns and your prompts, then letting calls + transcript analysis run in the background. Day to day, you’re often just reviewing outcomes and replying to engaged leads, which can be closer to 30–45 minutes total.
Before You Start
- n8n instance (try n8n Cloud free)
- Self-hosting option if you prefer (Hostinger works well)
- Google Sheets for your lead intake and status tracking
- Twilio to place outbound calls (often via HTTP Request)
- OpenAI API key (get it from the OpenAI dashboard)
Skill level: Intermediate. You’ll connect accounts, map a few fields, and test webhooks end-to-end.
Want someone to build this for you? Talk to an automation expert (free 15-minute consultation).
Step by Step
A new lead lands in Google Sheets. The Sheets Row Trigger watches your lead intake sheet and starts the workflow the moment a new row appears (name, phone, service of interest, and anything else you capture).
Lead context is fetched and normalized. The workflow looks up the lead details, cleans up the called number, and prepares the data your voice agent needs so it doesn’t sound robotic or generic.
An AI opener is created, then the call is initiated. OpenAI builds a short opener based on the lead’s details, and an HTTP Request node triggers the outbound call through your Twilio/ElevenLabs setup.
Post-call events come back through webhooks. When the call ends, the provider posts results and transcript data to your n8n webhook. A transcript formatter cleans it, OpenAI analyzes it, and your Google Sheet gets updated with status plus structured notes. If appropriate, Gmail sends the meeting or next-step email.
You can easily modify the status rules and the follow-up email content based on your needs. See the full implementation guide below for customization options.
Step-by-Step Implementation Guide
Step 1: Configure the Google Sheets Trigger
Set up the lead intake trigger so new rows in your Google Sheet initiate outbound calls.
- Add and open Sheets Row Trigger.
- Credential Required: Connect your googleSheetsTriggerOAuth2Api credentials.
- Set Event to
rowAdded. - Select the Document with
Lead Qualification Voice Agent Demo v1 (Responses)and SheetForm Responses 1. - Keep the polling schedule at Every Minute.
- Connect Sheets Row Trigger to Initiate Outbound Call.
Step 2: Connect Google Sheets
These nodes read and update lead records as the workflow progresses.
- Open Find Lead Row and set the filter lookupValue to
={{ $('Postcall Webhook').item.json.body.data.conversation_initiation_client_data.dynamic_variables.system__called_number }}and lookupColumn toPhone Number (Please enter + country code). - Credential Required: Connect your googleSheetsOAuth2Api credentials in Find Lead Row.
- Open Lookup Lead Details and set the filter lookupValue to
={{ $json.body.called_number }}with the same lookupColumn. - Credential Required: Connect your googleSheetsOAuth2Api credentials in Lookup Lead Details.
- Open Update Lead Record and confirm Operation is
appendOrUpdate. - Verify mapped columns in Update Lead Record, including Budget
={{ $('AI Transcript Analyzer').item.json.choices[0].message.content.budget }}and Lead status={{ $('AI Transcript Analyzer').item.json.choices[0].message.content.leadStatus }}. - Credential Required: Connect your googleSheetsOAuth2Api credentials in Update Lead Record.
+ country code, the lookup filters will not match.Step 3: Configure Webhooks and Data Normalization
Capture inbound and post-call data, then normalize caller details for lookups.
- Open Inbound Webhook and keep HTTP Method as
POSTand Response Mode asresponseNode. - Connect Inbound Webhook to Normalize Called Number.
- In Normalize Called Number, keep Include Other Fields enabled and set country_code to
={{$json.body.called_number.match(/^\+(\d{1,2})/)[1]}}and phone_number to={{$json.body.called_number.replace(/^\+\d{1,2}/, '')}}. - Open Postcall Webhook and keep HTTP Method as
POST. - Connect Postcall Webhook to Transcript Formatter.
- In Transcript Formatter, keep the JavaScript formatter code as provided to output
clean_transcript.
Step 4: Set Up AI Analysis and Parallel Logic
Analyze transcripts and branch the workflow to update records and decision logic.
- Open AI Transcript Analyzer and confirm the Model is
gpt-4o-miniand JSON Output is enabled. - Credential Required: Connect your openAiApi credentials in AI Transcript Analyzer.
- Verify the user message uses
={{ $json.clean_transcript }}and the system message contains the JSON schema for lead analysis. - Confirm parallel execution: AI Transcript Analyzer outputs to both Lead Status Check and Parse Caller Fields in parallel.
- In Lead Status Check, set the condition to equals with left value
={{ $json.choices[0].message.content.leadStatus }}and right valueQualified. - In Parse Caller Fields, confirm country_code is
={{$('Postcall Webhook').item.json.body.data.metadata.phone_call.external_number.match(/^\+(\d{1,2})/)[1]}}and phone_number is={{$('Postcall Webhook').item.json.body.data.metadata.phone_call.external_number.replace(/^\+\d{1,2}/, '')}}. - Confirm parallel execution: Parse Caller Fields outputs to both Update Lead Record and Combine Streams in parallel.
- In Combine Streams, keep Mode as
combineand Combine By ascombineByPosition.
Step 5: Configure Outbound Call and Email Actions
Trigger calls, build voice openers, send meeting emails, and respond to the webhook.
- Open Initiate Outbound Call and set URL to
https://api.elevenlabs.io/v1/convai/twilio/outbound-callwith MethodPOST. - Set to_number in Initiate Outbound Call to
={{ $json["Phone Number (Please enter + country code)"] }}. - Credential Required: Connect your twilioApi credentials in Initiate Outbound Call.
- Credential Required: Connect your httpHeaderAuth credentials in Initiate Outbound Call for the ElevenLabs header authentication.
- Open AI Opener Builder and confirm the user message is
=Hi {{ $json['First Name'] }}, your request: {{ $json['Service Request'] }}and the system prompt labels output asVoice Opener. - Credential Required: Connect your openAiApi credentials in AI Opener Builder.
- Open Return Webhook Reply and keep Respond With as
jsonand Response Body as={ "type": "conversation_initiation_client_data", "dynamic_variables": { "voiceopener": "{{ $json.choices[0].message.content['Voice Opener'] }}" } }. - Open Send Meeting Email, set Send To to
={{ $json.Email }}, and keep the message body and subject as provided. - Credential Required: Connect your gmailOAuth2 credentials in Send Meeting Email.
responseNode mode.Step 6: Test and Activate Your Workflow
Validate each path and confirm that qualified leads receive email follow-ups.
- Click Execute Workflow and add a new row in your Google Sheet to trigger Sheets Row Trigger.
- Send a test request to Inbound Webhook and verify Normalize Called Number and Lookup Lead Details populate the lead details for AI Opener Builder.
- Send a post-call payload to Postcall Webhook and confirm AI Transcript Analyzer outputs
leadStatus,budget, andtimeline. - Verify parallel flow: AI Transcript Analyzer outputs to both Lead Status Check and Parse Caller Fields in parallel, and Parse Caller Fields outputs to both Update Lead Record and Combine Streams in parallel.
- Confirm that qualified leads pass Lead Status Check, merge at Combine Streams, and reach Find Lead Row → Send Meeting Email.
- When tests succeed, toggle the workflow to Active for production use.
Troubleshooting Tips
- Google Sheets credentials can expire or need specific permissions. If things break, check the n8n Credentials panel and confirm the connected Google account still has access to the target spreadsheet.
- If you’re using Wait nodes or external rendering, processing times vary. Bump up the wait duration if downstream nodes fail on empty responses.
- Default prompts in AI nodes are generic. Add your brand voice early or you’ll be editing outputs forever.
Quick Answers
About 45 minutes if your accounts, sheet columns, and webhooks are ready.
No. You’ll mostly map fields, connect credentials, and test the call + webhook loop.
Yes. n8n has a free self-hosted option and a free trial on n8n Cloud. Cloud plans start at $20/month for higher volume. You’ll also need to factor in OpenAI API costs (often a few cents per analyzed transcript) plus Twilio/voice provider call charges.
Two options: n8n Cloud (managed, easiest setup) or self-hosting on a VPS. For self-hosting, Hostinger VPS is affordable and handles n8n well. Self-hosting gives you unlimited executions but requires basic server management.
Yes, and you should. You can swap Google Sheets for Airtable or a CRM by replacing the “Sheets Row Trigger” and “Lookup Lead Details” nodes, then remapping fields into “Parse Caller Fields.” Common changes include different qualification statuses, a new email template in the Gmail node, and a tighter prompt in “AI Transcript Analyzer” so it extracts exactly what your team cares about.
Usually it’s the HTTP Request step pointing at the wrong endpoint or missing auth headers for your Twilio/voice agent setup. Regenerate your API key (or token), update it in n8n credentials or headers, then re-test with one known phone number. Also check your Twilio number configuration and webhook URLs, because a single typo can stop post-call events from ever reaching n8n. If you’re testing fast, rate limits can show up too.
If you self-host, there’s no execution cap (it mostly depends on your server and your call provider). On n8n Cloud, the practical limit is tied to your plan’s monthly executions, and this workflow typically uses multiple executions per lead because it has trigger, call initiation, and post-call webhook handling.
For this workflow, n8n has a few advantages: more complex logic with unlimited branching at no extra cost, a self-hosting option for unlimited executions, and native AI + webhook patterns that are awkward (and pricey) elsewhere. Zapier or Make can still work for simpler “new lead → send email” flows, honestly. Once you add transcript handling, status logic, and multiple write-backs to Sheets, n8n tends to feel more in control. If you want help deciding, Talk to an automation expert.
Once this is running, every new lead gets a consistent first touch and a clean paper trail. You stop babysitting the spreadsheet and start working the opportunities that actually deserve attention.
Need Help Setting This Up?
Our automation experts can build and customize this workflow for your specific needs. Free 15-minute consultation—no commitment required.