This workflow corresponds to n8n.io template #16615 — we link there as the canonical source.
This workflow follows the Emailsend → Google Sheets recipe pattern — see all workflows that pair these two integrations.
The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →
{
"id": "26ffab59-8fcb-4e53-8277-97f94081aab7",
"meta": {
"templateCredsSetupCompleted": false
},
"name": "AI Inbound Lead Qualifier \u2014 by Operstead",
"tags": [],
"nodes": [
{
"id": "2e9b0163-a46e-462a-b2b8-61838583875d",
"name": "Inbound Lead Webhook",
"type": "n8n-nodes-base.webhook",
"position": [
240,
300
],
"parameters": {
"path": "inbound-lead",
"options": {},
"httpMethod": "POST",
"responseMode": "responseNode"
},
"typeVersion": 1
},
{
"id": "1f988dda-3c2d-4cea-87c0-dc6a296c78ea",
"name": "Normalize Lead Fields",
"type": "n8n-nodes-base.set",
"position": [
460,
300
],
"parameters": {
"values": {
"string": [
{
"name": "name",
"value": "={{ $json.body.name || $json.body.full_name || ($json.body.first_name + ' ' + ($json.body.last_name || '')) }}"
},
{
"name": "email",
"value": "={{ $json.body.email || $json.body.work_email }}"
},
{
"name": "company",
"value": "={{ $json.body.company || $json.body.company_name || '' }}"
},
{
"name": "website",
"value": "={{ $json.body.website || $json.body.domain || '' }}"
},
{
"name": "message",
"value": "={{ $json.body.message || $json.body.note || $json.body.what_do_you_need_help_with || '' }}"
},
{
"name": "budget",
"value": "={{ $json.body.budget || '' }}"
},
{
"name": "timeline",
"value": "={{ $json.body.timeline || '' }}"
},
{
"name": "source",
"value": "={{ $json.body.source || $json.headers.referer || 'unknown' }}"
}
]
},
"options": {},
"keepOnlySet": true
},
"typeVersion": 2
},
{
"id": "722c3602-6ff9-45aa-97c5-68d3c258e8c7",
"name": "Qualify with AI",
"type": "@n8n/n8n-nodes-langchain.openAi",
"position": [
680,
300
],
"parameters": {
"modelId": {
"__rl": true,
"mode": "list",
"value": "gpt-4o-mini"
},
"options": {
"temperature": 0.2
},
"messages": {
"values": [
{
"role": "system",
"content": "You are a senior sales qualifier for a B2B service business. Score the incoming lead from 0-100 on these dimensions and output STRICT JSON only:\n- fit_score (0-100): how well they match our ICP (B2B, decision-maker, real pain)\n- budget_score (0-100): signs they can actually pay\n- urgency_score (0-100): signs they need this soon\n- overall (0-100): weighted blend\n- tier: one of 'HOT' (>=75), 'WARM' (50-74), 'NURTURE' (<50)\n- reasoning: 2-3 sentences explaining the score\n- next_action: a single concrete next step for the sales person\n- red_flags: array of any red flags (empty if none)\n\nBUYER: customize this prompt for your business \u2014 replace the ICP description above with your real ICP."
},
{
"role": "user",
"content": "Lead submission:\nName: {{ $json.name }}\nEmail: {{ $json.email }}\nCompany: {{ $json.company }}\nWebsite: {{ $json.website }}\nMessage: {{ $json.message }}\nBudget: {{ $json.budget }}\nTimeline: {{ $json.timeline }}\nSource: {{ $json.source }}"
}
]
},
"resource": "chat",
"operation": "message",
"jsonOutput": true
},
"typeVersion": 1
},
{
"id": "f6304712-fe3d-4e89-b5fc-c57776ffc9b4",
"name": "Combine Lead + Score",
"type": "n8n-nodes-base.set",
"position": [
900,
300
],
"parameters": {
"values": {
"number": [
{
"name": "overall_score",
"value": "={{ $json.message.content.overall }}"
},
{
"name": "fit_score",
"value": "={{ $json.message.content.fit_score }}"
},
{
"name": "budget_score",
"value": "={{ $json.message.content.budget_score }}"
},
{
"name": "urgency_score",
"value": "={{ $json.message.content.urgency_score }}"
}
],
"string": [
{
"name": "tier",
"value": "={{ $json.message.content.tier }}"
},
{
"name": "reasoning",
"value": "={{ $json.message.content.reasoning }}"
},
{
"name": "next_action",
"value": "={{ $json.message.content.next_action }}"
}
]
},
"include": "all",
"options": {},
"keepOnlySet": false
},
"typeVersion": 2
},
{
"id": "e1f61701-8858-4878-8bc7-33e544d3ae7a",
"name": "Route by Tier",
"type": "n8n-nodes-base.switch",
"position": [
1120,
300
],
"parameters": {
"mode": "rules",
"rules": {
"values": [
{
"outputKey": "HOT",
"conditions": {
"options": {
"caseSensitive": true,
"typeValidation": "loose"
},
"combinator": "and",
"conditions": [
{
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.tier }}",
"rightValue": "HOT"
}
]
},
"renameOutput": true
},
{
"outputKey": "WARM",
"conditions": {
"options": {
"caseSensitive": true,
"typeValidation": "loose"
},
"combinator": "and",
"conditions": [
{
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.tier }}",
"rightValue": "WARM"
}
]
},
"renameOutput": true
},
{
"outputKey": "NURTURE",
"conditions": {
"options": {
"caseSensitive": true,
"typeValidation": "loose"
},
"combinator": "and",
"conditions": [
{
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.tier }}",
"rightValue": "NURTURE"
}
]
},
"renameOutput": true
}
]
},
"options": {}
},
"typeVersion": 3
},
{
"id": "d3e32c15-a236-4e02-84d1-c7679bd98e95",
"name": "Slack: HOT Lead Alert",
"type": "n8n-nodes-base.slack",
"position": [
1380,
120
],
"parameters": {
"text": "=:fire: *HOT LEAD ({{ $json.overall_score }}/100)*\n*{{ $json.name }}* @ *{{ $json.company }}*\n:email: {{ $json.email }}\n:speech_balloon: {{ $json.message }}\n\n*Why hot:* {{ $json.reasoning }}\n*Next:* {{ $json.next_action }}",
"select": "channel",
"resource": "message",
"channelId": {
"__rl": true,
"mode": "id",
"value": "REPLACE_ME_CHANNEL_ID"
},
"operation": "post",
"otherOptions": {}
},
"typeVersion": 2
},
{
"id": "2ec57bd5-7ace-4216-bd34-4bf0cbb2525e",
"name": "Sheets: Append HOT",
"type": "n8n-nodes-base.googleSheets",
"position": [
1380,
280
],
"parameters": {
"columns": {
"value": {
"Name": "={{ $json.name }}",
"Email": "={{ $json.email }}",
"Score": "={{ $json.overall_score }}",
"Source": "={{ $json.source }}",
"Company": "={{ $json.company }}",
"Message": "={{ $json.message }}",
"Reasoning": "={{ $json.reasoning }}",
"Timestamp": "={{ $now.toISO() }}",
"Next Action": "={{ $json.next_action }}"
},
"mappingMode": "defineBelow"
},
"options": {},
"resource": "sheet",
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "list",
"value": "Hot Leads"
},
"documentId": {
"__rl": true,
"mode": "id",
"value": "REPLACE_ME_SHEET_ID"
}
},
"typeVersion": 4
},
{
"id": "f4f5240f-573c-430f-9ff7-3a5522fa2106",
"name": "Email: HOT Auto-Reply",
"type": "n8n-nodes-base.emailSend",
"position": [
1380,
440
],
"parameters": {
"html": "=<p>Hi {{ $json.name }},</p><p>Thanks for reaching out. Based on what you've shared, this looks like exactly the kind of work we love. I'll be in touch within 24 hours with two times for a 30-minute call.</p><p>In the meantime, here's a quick read that might be useful: <a href=\"https://example.com/case-study\">how we helped a similar team</a>.</p><p>Talk soon,<br>YOUR NAME</p>",
"options": {},
"subject": "=Got it, {{ $json.name }} \u2014 let's find a time",
"toEmail": "={{ $json.email }}",
"fromEmail": "you@example.com",
"emailFormat": "html"
},
"typeVersion": 2
},
{
"id": "fbea70f9-1f22-4cad-aaba-8d2020cdfe20",
"name": "Sheets: Append WARM",
"type": "n8n-nodes-base.googleSheets",
"position": [
1380,
600
],
"parameters": {
"columns": {
"value": {
"Name": "={{ $json.name }}",
"Email": "={{ $json.email }}",
"Score": "={{ $json.overall_score }}",
"Source": "={{ $json.source }}",
"Company": "={{ $json.company }}",
"Message": "={{ $json.message }}",
"Reasoning": "={{ $json.reasoning }}",
"Timestamp": "={{ $now.toISO() }}",
"Next Action": "={{ $json.next_action }}"
},
"mappingMode": "defineBelow"
},
"options": {},
"resource": "sheet",
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "list",
"value": "Warm Leads"
},
"documentId": {
"__rl": true,
"mode": "id",
"value": "REPLACE_ME_SHEET_ID"
}
},
"typeVersion": 4
},
{
"id": "c5275c61-4ae8-499a-9f4b-bab5d7ca0f58",
"name": "Email: WARM Auto-Reply",
"type": "n8n-nodes-base.emailSend",
"position": [
1380,
760
],
"parameters": {
"html": "=<p>Hi {{ $json.name }},</p><p>Thanks for the note. Based on what you've shared I want to make sure we'd actually be the right fit before booking time. A few quick questions \u2014 could you tell me:</p><ul><li>What's the current state today?</li><li>What does success look like 90 days from now?</li><li>What budget range do you have in mind?</li></ul><p>Even a 2-sentence answer per bullet helps a lot.</p><p>Best,<br>YOUR NAME</p>",
"options": {},
"subject": "=Thanks for reaching out, {{ $json.name }}",
"toEmail": "={{ $json.email }}",
"fromEmail": "you@example.com",
"emailFormat": "html"
},
"typeVersion": 2
},
{
"id": "3624f324-e5e7-4deb-b52a-14059b04f8fd",
"name": "Sheets: Append NURTURE",
"type": "n8n-nodes-base.googleSheets",
"position": [
1380,
920
],
"parameters": {
"columns": {
"value": {
"Name": "={{ $json.name }}",
"Email": "={{ $json.email }}",
"Score": "={{ $json.overall_score }}",
"Source": "={{ $json.source }}",
"Company": "={{ $json.company }}",
"Message": "={{ $json.message }}",
"Reasoning": "={{ $json.reasoning }}",
"Red Flags": "={{ JSON.stringify($json.message?.content?.red_flags || []) }}",
"Timestamp": "={{ $now.toISO() }}"
},
"mappingMode": "defineBelow"
},
"options": {},
"resource": "sheet",
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "list",
"value": "Nurture"
},
"documentId": {
"__rl": true,
"mode": "id",
"value": "REPLACE_ME_SHEET_ID"
}
},
"typeVersion": 4
},
{
"id": "50cd053b-5ded-47d7-878f-91ebeeea3b06",
"name": "Email: NURTURE Auto-Reply",
"type": "n8n-nodes-base.emailSend",
"position": [
1380,
1080
],
"parameters": {
"html": "=<p>Hi {{ $json.name }},</p><p>Thanks for reaching out. Based on what you've shared we may not be the right fit for a paid engagement today, but here are some free resources that should help:</p><ul><li><a href=\"https://example.com/guide\">Our free starter guide</a></li><li><a href=\"https://example.com/newsletter\">Weekly newsletter</a> \u2014 tactics, no fluff</li></ul><p>If things change, come back any time.</p><p>Best,<br>YOUR NAME</p>",
"options": {},
"subject": "=Thanks, {{ $json.name }} \u2014 a few resources",
"toEmail": "={{ $json.email }}",
"fromEmail": "you@example.com",
"emailFormat": "html"
},
"typeVersion": 2
},
{
"id": "30d07721-cb5a-428c-875f-89edaff75fdb",
"name": "Respond to Webhook",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
1640,
300
],
"parameters": {
"options": {},
"respondWith": "json",
"responseBody": "={ \"ok\": true, \"tier\": \"{{ $('Combine Lead + Score').item.json.tier }}\" }"
},
"typeVersion": 1
},
{
"id": "d9113e7f-add0-4904-a20f-9b1624ff4031",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
180,
-500
],
"parameters": {
"width": 900,
"height": 580,
"content": "## AI Inbound Lead Qualifier\n\n### How it works\nA webhook receives an inbound lead from your website or CRM form. The fields are normalised, then an OpenAI node scores the lead on fit, budget and urgency and assigns it a tier: HOT, WARM or NURTURE.\n\nA Switch node sends each tier down its own branch. Every lead is appended to its own tab in Google Sheets and receives a tailored auto-reply by email. HOT leads additionally post an alert to Slack, so you can respond while the lead is still warm. The webhook then returns a response, so the submitting form gets a clean confirmation.\n\n### Setup\n1. Add your OpenAI credential to **Qualify with AI**, and edit the ICP and scoring rules in its system prompt so they describe your business.\n2. Add your Google Sheets, Slack and SMTP credentials.\n3. Replace the placeholders: `REPLACE_ME_SHEET_ID`, `REPLACE_ME_CHANNEL_ID`, the `fromEmail` address, and `YOUR NAME` in the email copy.\n4. Point your website or CRM form at the **Inbound Lead Webhook** URL.\n\nAllow about 25 minutes. No credentials are bundled - add your own.\n\n### Customization\nChange the tier names and thresholds in **Route by Tier** to match your sales process, and add or remove branches freely. If you do not use Slack, delete the Slack node and connect the HOT branch straight to Google Sheets."
},
"typeVersion": 1
},
{
"id": "ad66254a-083e-4cbe-8a7e-f26c632a8554",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
180,
180
],
"parameters": {
"color": 7,
"width": 440,
"height": 260,
"content": "## 1. Receive and normalise\nThe webhook accepts your form's POST. Field names are standardised before scoring."
},
"typeVersion": 1
},
{
"id": "fb972cc4-7f0b-4dd7-8cee-d3470334bbd2",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
640,
180
],
"parameters": {
"color": 7,
"width": 440,
"height": 260,
"content": "## 2. Score and tier with AI\nOpenAI rates fit, budget and urgency, then assigns HOT, WARM or NURTURE. Edit the ICP in the system prompt."
},
"typeVersion": 1
},
{
"id": "sticky-3",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
1100,
20
],
"parameters": {
"color": 7,
"width": 760,
"height": 1240,
"content": "## 3. Route, log and reply\nEach tier appends to its own Sheets tab and sends a tailored auto-reply. HOT leads also alert Slack. The webhook then responds."
},
"typeVersion": 1
}
],
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "e2e028e9-1504-4fa8-82d6-31f9495b7876",
"connections": {
"Route by Tier": {
"main": [
[
{
"node": "Slack: HOT Lead Alert",
"type": "main",
"index": 0
},
{
"node": "Sheets: Append HOT",
"type": "main",
"index": 0
},
{
"node": "Email: HOT Auto-Reply",
"type": "main",
"index": 0
}
],
[
{
"node": "Sheets: Append WARM",
"type": "main",
"index": 0
},
{
"node": "Email: WARM Auto-Reply",
"type": "main",
"index": 0
}
],
[
{
"node": "Sheets: Append NURTURE",
"type": "main",
"index": 0
},
{
"node": "Email: NURTURE Auto-Reply",
"type": "main",
"index": 0
}
]
]
},
"Qualify with AI": {
"main": [
[
{
"node": "Combine Lead + Score",
"type": "main",
"index": 0
}
]
]
},
"Combine Lead + Score": {
"main": [
[
{
"node": "Route by Tier",
"type": "main",
"index": 0
}
]
]
},
"Inbound Lead Webhook": {
"main": [
[
{
"node": "Normalize Lead Fields",
"type": "main",
"index": 0
}
]
]
},
"Email: HOT Auto-Reply": {
"main": [
[
{
"node": "Respond to Webhook",
"type": "main",
"index": 0
}
]
]
},
"Normalize Lead Fields": {
"main": [
[
{
"node": "Qualify with AI",
"type": "main",
"index": 0
}
]
]
},
"Slack: HOT Lead Alert": {
"main": [
[
{
"node": "Respond to Webhook",
"type": "main",
"index": 0
}
]
]
},
"Email: WARM Auto-Reply": {
"main": [
[
{
"node": "Respond to Webhook",
"type": "main",
"index": 0
}
]
]
},
"Email: NURTURE Auto-Reply": {
"main": [
[
{
"node": "Respond to Webhook",
"type": "main",
"index": 0
}
]
]
}
}
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This workflow receives inbound leads via a webhook, normalizes common form fields, and uses OpenAI to score and tier each lead as HOT, WARM, or NURTURE. It logs the result to Google Sheets, sends a tier-specific email auto-reply, and alerts a Slack channel for HOT leads.…
Source: https://n8n.io/workflows/16615/ — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
Property managers and operations teams who want better visibility into unresolved maintenance requests.
Consulting firms in strategy, management, or IT who want to automate client onboarding and internal task assignment.
Property management teams handling leases, IDs, and compliance documents.
This workflow captures new leads via webhook, enriches and scores them with Apollo and Google Gemini, logs everything in Google Sheets, and automates outreach, reply handling, follow-ups, meeting prep
Watch on Youtube▶️