n8n Lead Generation Workflow: Free JSON, 2.3 Cents a Lead
Catch, enrich, score, log and alert in one n8n flow that counts as one execution per lead. Copy the JSON, then check consent rules before you email anyone.
Saksham Dogra 9 min read Updated on
A good n8n workflow for lead generation does five things in order: catch the lead (webhook or form), enrich it (look up the company), score it with AI, log it to Google Sheets or your CRM, and ping Slack when a lead is hot. Below is that exact pipeline as an importable n8n JSON template, a node-by-node build guide, what it costs per lead, and the consent rules that apply before you email anyone it captures.
Everything here was checked against n8n’s documentation and the vendors’ pricing pages on 28 October 2026. The template is a starting point, not a turnkey product: you must add your own credentials, and you should test it on your n8n version before going live. Node versions change between n8n releases.
What this lead generation workflow does
| Step | n8n node | Node type (as in the JSON) | Job |
|---|---|---|---|
| 1. Capture | Webhook | n8n-nodes-base.webhook |
Receives a POST from your site form |
| 2. Clean | Edit Fields (Set) | n8n-nodes-base.set |
Trims email, pulls out the domain, records consent |
| 3. Enrich | HTTP Request | n8n-nodes-base.httpRequest |
Fetches the lead’s company homepage |
| 4. Qualify | Basic LLM Chain | @n8n/n8n-nodes-langchain.chainLlm |
Scores the lead 0-100 with a reason |
| 4a. Model | Anthropic Chat Model | @n8n/n8n-nodes-langchain.lmChatAnthropic |
The LLM behind the chain |
| 4b. Parser | Structured Output Parser | @n8n/n8n-nodes-langchain.outputParserStructured |
Forces clean JSON: score, tier, reason |
| 5. Log | Google Sheets | n8n-nodes-base.googleSheets |
Appends one row per lead |
| 6. Route | If | n8n-nodes-base.if |
Passes only scores of 70 or more |
| 7. Alert | Slack | n8n-nodes-base.slack |
Posts hot leads to #sales-leads |
Every node above is listed in n8n’s built-in node documentation. The type strings match the node names in n8n’s source code, which is what the editor reads when you paste JSON.
Why this design? Two choices keep it cheap and dependable:
- Enrichment without a paid data API. Fetching the company homepage from the email domain gives the model real context (what the company does, roughly how big it looks) for free. If you already pay for a data provider, n8n has Clearbit, Hunter and HubSpot nodes you can swap in at step 3.
- A Basic LLM Chain, not an AI Agent. Scoring is one prompt in and one answer out. An agent adds tool calls and tokens you do not need. The Structured Output Parser makes the answer machine-readable so the If node can compare a number.
Step-by-step build
1. Webhook trigger (or n8n Form)
Add a Webhook node, set the HTTP method to POST and the path to new-lead. n8n gives you two URLs: a test URL that works while you click “Listen for test event”, and a production URL that only works once you publish the workflow. Point your site’s form at the production URL when you are done.
If you do not have a form yet, swap the Webhook for the n8n Form trigger (n8n-nodes-base.formTrigger), which hosts a simple form for you. Either way, send these fields: name, email, company, message, marketing_consent (true or false from an unticked checkbox) and consent_text (the exact wording next to that box).
Secure the webhook. n8n’s docs list Basic auth, Header auth and JWT auth for webhook callers, plus an IP allowlist option. A header secret shared with your form backend is the simplest.
2. Normalize the lead
An Edit Fields (Set) node lowercases the email, extracts the domain with {{ $json.body.email.split('@')[1] }}, converts the consent checkbox to a true/false value and stamps received_at. Later nodes reference this node by name, so every downstream step sees the same clean data.
3. Enrich: fetch the company website
An HTTP Request node calls https://{{ $json.domain }} and returns the page as text. It is set to continue on error, because plenty of leads use Gmail or have slow sites, and a failed fetch should not drop the lead. The prompt strips HTML tags and passes the first 3,000 characters to the model.
4. Qualify with AI
The Basic LLM Chain carries a short system message that describes your ideal customer and asks for a score, a tier (hot, warm or cold) and a one-sentence reason. Connect an Anthropic Chat Model sub-node (or the OpenAI Chat Model, if you prefer) and a Structured Output Parser with an example like {"score": 82, "tier": "hot", "reason": "..."}. Set temperature to 0 so the same lead gets the same score.
Edit the system message. “5-200 staff that wants workflow automation” is a placeholder; your ideal customer profile is the single biggest lever on scoring quality.
5. Log to Google Sheets (or a CRM)
The Google Sheets node appends a row to a tab called Leads. Create these header cells first: received_at, name, email, company, message, score, tier, reason, marketing_consent, consent_text. Keeping the consent wording next to each lead is how you later prove consent under CASL and the Spam Act (more on that below).
Prefer a CRM? Replace the node with n8n’s HubSpot node, or any CRM node, and map the same fields.
6. Route and alert in Slack
The If node checks score >= 70. The true branch goes to a Slack node that posts the name, company, score and reason to #sales-leads. The false branch ends quietly; warm and cold leads are already in the sheet for a weekly review.
The importable n8n workflow JSON
Copy everything below, open a blank workflow in n8n and paste it onto the canvas.
{
"name": "Lead capture: enrich, AI qualify, Sheets, Slack (unboxth)",
"nodes": [
{
"parameters": {
"httpMethod": "POST",
"path": "new-lead",
"responseMode": "onReceived",
"options": {}
},
"id": "a1f0c0de-0001-4000-8000-000000000001",
"name": "Lead webhook",
"type": "n8n-nodes-base.webhook",
"typeVersion": 2,
"position": [0, 300],
"webhookId": "a1f0c0de-0001-4000-8000-0000000000aa"
},
{
"parameters": {
"assignments": {
"assignments": [
{ "id": "f1", "name": "name", "value": "={{ $json.body.name }}", "type": "string" },
{ "id": "f2", "name": "email", "value": "={{ ($json.body.email || '').trim().toLowerCase() }}", "type": "string" },
{ "id": "f3", "name": "company", "value": "={{ $json.body.company }}", "type": "string" },
{ "id": "f4", "name": "message", "value": "={{ $json.body.message }}", "type": "string" },
{ "id": "f5", "name": "domain", "value": "={{ ($json.body.email || '').split('@')[1] || '' }}", "type": "string" },
{ "id": "f6", "name": "marketing_consent", "value": "={{ $json.body.marketing_consent === true || $json.body.marketing_consent === 'true' }}", "type": "boolean" },
{ "id": "f7", "name": "consent_text", "value": "={{ $json.body.consent_text || '' }}", "type": "string" },
{ "id": "f8", "name": "received_at", "value": "={{ $now.toISO() }}", "type": "string" }
]
},
"options": {}
},
"id": "a1f0c0de-0002-4000-8000-000000000002",
"name": "Normalize lead",
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [220, 300]
},
{
"parameters": {
"url": "=https://{{ $json.domain }}",
"options": {
"response": { "response": { "responseFormat": "text", "outputPropertyName": "html" } },
"timeout": 8000
}
},
"id": "a1f0c0de-0003-4000-8000-000000000003",
"name": "Fetch company website",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [440, 300],
"onError": "continueRegularOutput"
},
{
"parameters": {
"promptType": "define",
"text": "=Lead name: {{ $('Normalize lead').item.json.name }}\nEmail domain: {{ $('Normalize lead').item.json.domain }}\nCompany (as typed): {{ $('Normalize lead').item.json.company }}\nTheir message: {{ $('Normalize lead').item.json.message }}\n\nFirst 3,000 characters of their website (may be empty):\n{{ ($json.html || '').replace(/<[^>]*>/g, ' ').replace(/\\s+/g, ' ').slice(0, 3000) }}",
"hasOutputParser": true,
"messages": {
"messageValues": [
{
"message": "You qualify inbound B2B leads for a small agency. Our ideal customer: a company with 5-200 staff that wants workflow automation and has budget. Free email domains (gmail.com, outlook.com, yahoo.com) are not disqualifying on their own. Score 0-100. tier is hot (70+), warm (40-69) or cold (under 40). reason is one short sentence. Never invent facts that are not in the input."
}
]
}
},
"id": "a1f0c0de-0004-4000-8000-000000000004",
"name": "Qualify lead",
"type": "@n8n/n8n-nodes-langchain.chainLlm",
"typeVersion": 1.5,
"position": [660, 300]
},
{
"parameters": {
"model": { "__rl": true, "mode": "id", "value": "PICK_A_SMALL_CLAUDE_MODEL" },
"options": { "maxTokensToSample": 300, "temperature": 0 }
},
"id": "a1f0c0de-0005-4000-8000-000000000005",
"name": "Anthropic Chat Model",
"type": "@n8n/n8n-nodes-langchain.lmChatAnthropic",
"typeVersion": 1.3,
"position": [600, 520]
},
{
"parameters": {
"jsonSchemaExample": "{\n \"score\": 82,\n \"tier\": \"hot\",\n \"reason\": \"30-person logistics firm asking for an automation quote this quarter.\"\n}"
},
"id": "a1f0c0de-0006-4000-8000-000000000006",
"name": "Structured Output Parser",
"type": "@n8n/n8n-nodes-langchain.outputParserStructured",
"typeVersion": 1.2,
"position": [780, 520]
},
{
"parameters": {
"operation": "append",
"documentId": { "__rl": true, "mode": "url", "value": "https://docs.google.com/spreadsheets/d/YOUR_SHEET_ID/edit" },
"sheetName": { "__rl": true, "mode": "name", "value": "Leads" },
"columns": {
"mappingMode": "defineBelow",
"value": {
"received_at": "={{ $('Normalize lead').item.json.received_at }}",
"name": "={{ $('Normalize lead').item.json.name }}",
"email": "={{ $('Normalize lead').item.json.email }}",
"company": "={{ $('Normalize lead').item.json.company }}",
"message": "={{ $('Normalize lead').item.json.message }}",
"score": "={{ $json.output.score }}",
"tier": "={{ $json.output.tier }}",
"reason": "={{ $json.output.reason }}",
"marketing_consent": "={{ $('Normalize lead').item.json.marketing_consent }}",
"consent_text": "={{ $('Normalize lead').item.json.consent_text }}"
},
"matchingColumns": [],
"schema": [
{ "id": "received_at", "displayName": "received_at", "type": "string", "canBeUsedToMatch": true },
{ "id": "name", "displayName": "name", "type": "string", "canBeUsedToMatch": true },
{ "id": "email", "displayName": "email", "type": "string", "canBeUsedToMatch": true },
{ "id": "company", "displayName": "company", "type": "string", "canBeUsedToMatch": true },
{ "id": "message", "displayName": "message", "type": "string", "canBeUsedToMatch": true },
{ "id": "score", "displayName": "score", "type": "string", "canBeUsedToMatch": true },
{ "id": "tier", "displayName": "tier", "type": "string", "canBeUsedToMatch": true },
{ "id": "reason", "displayName": "reason", "type": "string", "canBeUsedToMatch": true },
{ "id": "marketing_consent", "displayName": "marketing_consent", "type": "string", "canBeUsedToMatch": true },
{ "id": "consent_text", "displayName": "consent_text", "type": "string", "canBeUsedToMatch": true }
]
},
"options": {}
},
"id": "a1f0c0de-0007-4000-8000-000000000007",
"name": "Append to Google Sheets",
"type": "n8n-nodes-base.googleSheets",
"typeVersion": 4.5,
"position": [960, 300]
},
{
"parameters": {
"conditions": {
"options": { "caseSensitive": true, "leftValue": "", "typeValidation": "loose" },
"conditions": [
{
"id": "c1",
"leftValue": "={{ $('Qualify lead').item.json.output.score }}",
"rightValue": 70,
"operator": { "type": "number", "operation": "gte" }
}
],
"combinator": "and"
},
"options": {}
},
"id": "a1f0c0de-0008-4000-8000-000000000008",
"name": "Hot lead?",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [1180, 300]
},
{
"parameters": {
"select": "channel",
"channelId": { "__rl": true, "mode": "name", "value": "#sales-leads" },
"text": "=:fire: Hot lead ({{ $('Qualify lead').item.json.output.score }}/100): {{ $('Normalize lead').item.json.name }} at {{ $('Normalize lead').item.json.company }} <mailto:{{ $('Normalize lead').item.json.email }}>\n{{ $('Qualify lead').item.json.output.reason }}",
"otherOptions": {}
},
"id": "a1f0c0de-0009-4000-8000-000000000009",
"name": "Alert Slack",
"type": "n8n-nodes-base.slack",
"typeVersion": 2.2,
"position": [1400, 200]
}
],
"connections": {
"Lead webhook": { "main": [[{ "node": "Normalize lead", "type": "main", "index": 0 }]] },
"Normalize lead": { "main": [[{ "node": "Fetch company website", "type": "main", "index": 0 }]] },
"Fetch company website": { "main": [[{ "node": "Qualify lead", "type": "main", "index": 0 }]] },
"Anthropic Chat Model": { "ai_languageModel": [[{ "node": "Qualify lead", "type": "ai_languageModel", "index": 0 }]] },
"Structured Output Parser": { "ai_outputParser": [[{ "node": "Qualify lead", "type": "ai_outputParser", "index": 0 }]] },
"Qualify lead": { "main": [[{ "node": "Append to Google Sheets", "type": "main", "index": 0 }]] },
"Append to Google Sheets": { "main": [[{ "node": "Hot lead?", "type": "main", "index": 0 }]] },
"Hot lead?": { "main": [[{ "node": "Alert Slack", "type": "main", "index": 0 }], []] }
},
"settings": { "executionOrder": "v1" },
"pinData": {}
}
Before you activate it:
- Add credentials. The JSON contains no keys. Open the Anthropic Chat Model, Google Sheets and Slack nodes and select or create a credential in each.
- Pick the model. Replace
PICK_A_SMALL_CLAUDE_MODELby choosing a small, cheap model from the node’s dropdown. Scoring does not need a frontier model. - Point to your sheet and channel. Replace
YOUR_SHEET_IDand#sales-leads. - Test on your version. The JSON pins node versions that n8n still supports (Webhook 2, HTTP Request 4.2, Google Sheets 4.5, Slack 2.2 and so on), but newer n8n releases default to newer versions and may show a field differently. Run a test with a fake lead, check each node’s output, then publish.
What it costs per lead
n8n Cloud bills by execution: one full run of a workflow, however many steps it has. That is the key difference from Zapier (each action is a task) and Make (most modules cost a credit). Prices below were checked 28 October 2026 and change often.
Worked example: 1,000 inbound leads a month on n8n Cloud Starter
- n8n Starter: €20 a month billed yearly, for 2,500 executions. At the ECB reference rate of $1.1133 per euro (28 October 2026), that is about $22.27 (about C$31.28 or A$31.66).
- Each lead = 1 execution, so 1,000 leads use 1,000 of 2,500.
- AI tokens per lead: about 1,500 input tokens (prompt plus website snippet) and 200 output tokens. On Claude Haiku 5.5 at $0.10 per million input and $0.50 per million output tokens: 1,500 × $0.10 / 1,000,000 = $0.00015, plus 200 × $0.50 / 1,000,000 = $0.0001. Total $0.00025 per lead, or $0.25 for 1,000.
- Google Sheets and Slack API calls: no per-call charge from n8n.
- Total: $22.27 + $0.25 = about $22.52 a month, or 2.3 cents per lead. At the full 2,500 leads it drops to about $22.90 total, under 1 cent per lead.
| Platform | How this flow is billed | Usage for 1,000 leads | Notes |
|---|---|---|---|
| n8n Cloud Starter | 1 execution per lead | 1,000 of 2,500 executions | €20/mo yearly; trial of 1,000 executions, no card |
| n8n self-hosted (Community Edition) | Free software | Server cost only | You run updates and backups |
| Make | Most module actions = 1 credit | About 5,000-6,000 credits | Core is $12/mo billed yearly ($16 monthly) for 10,000 credits; AI modules can use more |
| Zapier | Each successful action = 1 task; trigger and Filter are free | About 4,000-8,000 tasks (AI steps use 1, 3 or 5 tasks) | Professional starts at $19.99/mo; check the task slider for this volume |
The model choice matters more than you might expect at scale. A frontier model at 40 times the per-token price or more (Claude Opus 5.5 lists $4/$20 per million tokens) would still be cents per lead, but there is no scoring benefit to justify it for a three-field answer.
For the full plan-by-plan comparison, see our n8n vs Make vs Zapier pricing breakdown, and if you want to drop the n8n fee entirely, read n8n self-hosted vs cloud cost.
Consent rules before you email these leads (US, Canada, Australia)
Logging a form submission and alerting your team is internal. Emailing that lead a marketing message is regulated, and the rule depends on where the recipient is. This is general information, not legal advice; confirm with a lawyer for your situation.
| Country | Law | Consent before marketing email? | Must include | Unsubscribe deadline | Max penalty |
|---|---|---|---|---|---|
| United States | CAN-SPAM Act | No, but must offer opt-out | Accurate headers and subject, ad disclosure, valid postal address, opt-out | Honor within 10 business days | Up to $53,088 per email |
| Canada | CASL | Yes, express or implied | Sender identification, contact info, unsubscribe | Process within 10 business days; link valid 60 days | C$10M per violation (business) |
| Australia | Spam Act 2003 | Yes, express or inferred | Sender name or business name, contact details, unsubscribe | Honor within 5 working days; works for 30 days | ACMA enforcement action |
What this means for the workflow:
- Keep the consent checkbox unticked by default. The CRTC says a pre-checked box cannot give express consent under CASL; the user must take a positive action.
- Store the proof. Both the CRTC and ACMA put the onus on the sender to prove consent. That is why the template saves
marketing_consentandconsent_textwith a timestamp in every row. - CASL reaches you from outside Canada. The CRTC’s FAQ says commercial messages sent to recipients in Canada from another country must comply.
- No harvested lists. ACMA says you cannot use or supply lists made with address-harvesting software, and you are responsible for consent on any list you buy.
- Replying to an inquiry is different from a newsletter. A direct reply to the lead’s question is usually not the issue. Adding them to a nurture sequence is. If
marketing_consentis false, keep them out of your email tool.
Who should use this template (and who should not)
| You are… | Use this? | Why |
|---|---|---|
| An agency or B2B startup getting 50-2,500 inbound leads a month | Yes | One execution per lead keeps n8n Starter cheap, and AI scoring saves triage time |
| Already on HubSpot or Salesforce with built-in lead scoring | Maybe not | Your CRM’s native scoring may be enough; use n8n only for the Slack routing |
| A team with nobody comfortable editing expressions or JSON | Not yet | Zapier or Make will be easier to maintain; see our Zapier alternatives guide |
| Planning to scrape contacts and cold-email them | No | This flow is for inbound leads; harvested lists break the Spam Act and likely CASL |
| Handling high volume with strict data residency needs | Check first | n8n Cloud is hosted in Frankfurt; self-hosting gives you control of location |
Common problems and fixes
- Webhook works in test, not in production. The production URL only registers after you publish the workflow. Check the Executions tab for production runs, since they do not display in the editor.
- The LLM node errors with no output format. Make sure “Require Specific Output Format” is on in the Basic LLM Chain and the Structured Output Parser is connected.
- Website fetch fails for most leads. Normal for free-mail domains. The node continues on error and the model scores from the form text alone.
- Google Sheets writes to the wrong columns. Header names must match exactly. Re-open the node and refresh the column mapping after creating the headers.
If you upgrade the scoring step to a full AI Agent with tools, see n8n AI agent cost per run for how tool calls change the token bill. For a customer-facing bot on WhatsApp, see n8n WhatsApp chatbot cost. More n8n builds and cost breakdowns live in the AI automation hub.
Frequently asked questions
Is there a free n8n lead generation template?
How do I import a workflow JSON into n8n?
How much does an n8n lead generation workflow cost per lead?
Can n8n scrape LinkedIn for leads?
Do I need consent to email leads from my n8n workflow?
Should I use Make or Zapier instead of n8n for lead routing?
Sources
- 1. Webhook node (n8n Docs) docs.n8n.io
- 2. Basic LLM Chain node (n8n Docs) docs.n8n.io
- 3. n8n documentation index (node list) docs.n8n.io
- 4. n8n pricing n8n.io
- 5. Claude pricing (Anthropic) claude.com
- 6. Zapier pricing and task rates zapier.com
- 7. Make pricing make.com
- 8. CAN-SPAM Act: A Compliance Guide for Business (FTC) ftc.gov
- 9. FAQ about Canada's Anti-Spam Legislation (CRTC) crtc.gc.ca
- 10. Avoid sending spam (ACMA, Australia) acma.gov.au
- 11. Euro foreign exchange reference rates (ECB, 28 Oct 2026) ecb.europa.eu
Founder, unboxth
Saksham Dogra is the founder of unboxth. He writes founder to founder about building an AI startup from anywhere: company setup, costs, tools and fundraising.