This workflow corresponds to n8n.io template #15059 — we link there as the canonical source.
This workflow follows the Agent → 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 →
{
"meta": {
"templateCredsSetupCompleted": true
},
"nodes": [
{
"id": "877ed4c9-4222-4070-999f-26d05b261e92",
"name": "Normalise Tally Payload",
"type": "@n8n/n8n-nodes-langchain.agent",
"onError": "continueErrorOutput",
"position": [
5744,
2224
],
"parameters": {
"text": "=Extract structured fields from this raw Tally form submission:\n\n{{ JSON.stringify($json) }}\n\nReturn a JSON object with exactly: company_name (string), website_url (string), linkedin_url (string), criteria_list (array of strings), submission_id (string). If a field is missing use empty string or empty array. For website_url ensure it starts with https://.",
"options": {
"systemMessage": "You are a data extraction agent. Parse raw Tally form JSON and return clean structured fields.\n\nCRITICAL: Return ONLY a raw JSON object. No markdown fences, no explanation.\n\nOUTPUT SCHEMA: {\"company_name\": \"string\", \"website_url\": \"string\", \"linkedin_url\": \"string\", \"criteria_list\": [\"string\"], \"submission_id\": \"string\"}"
},
"promptType": "define"
},
"typeVersion": 3
},
{
"id": "d493f616-dfa2-4531-9e23-26c4244d7f0f",
"name": "GPT-5.4 Model",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"position": [
5744,
2400
],
"parameters": {
"model": "gpt-5.4",
"options": {}
},
"credentials": {
"openAiApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "e7b72072-4f0e-4b57-bd87-401b3f3a4a26",
"name": "Map Lead Fields",
"type": "n8n-nodes-base.set",
"position": [
6112,
2208
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "set-001-a",
"name": "company_name",
"type": "string",
"value": "={{ JSON.parse($json.output).company_name }}"
},
{
"id": "set-001-b",
"name": "website_url",
"type": "string",
"value": "={{ JSON.parse($json.output).website_url }}"
},
{
"id": "set-001-c",
"name": "linkedin_url",
"type": "string",
"value": "={{ JSON.parse($json.output).linkedin_url }}"
},
{
"id": "set-001-d",
"name": "criteria_list",
"type": "array",
"value": "={{ JSON.parse($json.output).criteria_list }}"
},
{
"id": "set-001-e",
"name": "submission_id",
"type": "string",
"value": "={{ JSON.parse($json.output).submission_id }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "5ba47b50-01da-4bd1-8db2-4d0f2ce68b83",
"name": "Fetch Company Homepage",
"type": "n8n-nodes-base.httpRequest",
"onError": "continueErrorOutput",
"position": [
6400,
2208
],
"parameters": {
"url": "={{ $json.website_url }}",
"options": {
"timeout": 15000,
"redirect": {
"redirect": {
"maxRedirects": 5
}
},
"response": {
"response": {
"responseFormat": "text"
}
}
},
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "User-Agent",
"value": "Mozilla/5.0 (compatible; research-bot/1.0)"
},
{
"name": "Accept",
"value": "text/html"
}
]
}
},
"typeVersion": 4.2
},
{
"id": "371b9931-4231-42fc-818b-947d090a07bc",
"name": "Strip HTML to Plain Text",
"type": "n8n-nodes-base.code",
"position": [
6688,
2208
],
"parameters": {
"jsCode": "const lead = $('Map Lead Fields').first().json;\nconst html = $input.first().json.data || $input.first().json.body || '';\n\nlet text = html\n .replace(/<script[\\s\\S]*?<\\/script>/gi, ' ')\n .replace(/<style[\\s\\S]*?<\\/style>/gi, ' ')\n .replace(/<nav[\\s\\S]*?<\\/nav>/gi, ' ')\n .replace(/<footer[\\s\\S]*?<\\/footer>/gi, ' ')\n .replace(/<head[\\s\\S]*?<\\/head>/gi, ' ')\n .replace(/<[^>]+>/g, ' ')\n .replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '\"').replace(/ /g, ' ')\n .replace(/\\s+/g, ' ')\n .trim();\n\nconst truncated = text.length > 6000 ? text.substring(0, 6000) + '...[truncated]' : text;\n\nreturn [{ json: { ...lead, homepage_text: truncated } }];"
},
"typeVersion": 2
},
{
"id": "fe570469-82d0-4f53-94ba-b6075b3a5841",
"name": "Analyse Website Content",
"type": "@n8n/n8n-nodes-langchain.agent",
"onError": "continueErrorOutput",
"position": [
6896,
2208
],
"parameters": {
"text": "=Analyse this company homepage content and extract B2B intelligence.\n\nCompany name: {{ $json.company_name }}\nWebsite: {{ $json.website_url }}\nBuyer's scoring criteria: {{ ($json.criteria_list || []).join(', ') }}\n\nHomepage text:\n{{ $json.homepage_text }}\n\nExtract: what the company does, tech stack (tool names, integrations, platform mentions visible on page), company size signals, industry, and signals relevant to the buyer's criteria.",
"options": {
"systemMessage": "You are a B2B intelligence analyst. Read real homepage content and extract structured signals. Only report what is visible on the page \u2014 do not invent.\n\nCRITICAL: Return ONLY a raw JSON object. No markdown fences, no explanation.\n\nOUTPUT SCHEMA: {\"company_summary\": \"one sentence\", \"industry\": \"string\", \"company_size_signal\": \"enterprise/mid-market/SMB/unknown\", \"tech_stack\": [\"string\"], \"tech_categories\": {\"category\": [\"tech\"]}, \"criteria_signals\": {\"criterion\": \"what the page says\"}, \"confidence\": \"high/medium/low\"}"
},
"promptType": "define"
},
"typeVersion": 3
},
{
"id": "69f3db17-e921-4c5e-a482-1dfbc7022718",
"name": "GPT-5.4 Model 2",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"position": [
6896,
2368
],
"parameters": {
"model": "gpt-5.4",
"options": {}
},
"credentials": {
"openAiApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "e0c013ac-c4b1-443f-9450-bcb8809f6c60",
"name": "Map Website Analysis",
"type": "n8n-nodes-base.set",
"position": [
7472,
2192
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "set-002-a",
"name": "company_name",
"type": "string",
"value": "={{ $('Strip HTML to Plain Text').first().json.company_name }}"
},
{
"id": "set-002-b",
"name": "website_url",
"type": "string",
"value": "={{ $('Strip HTML to Plain Text').first().json.website_url }}"
},
{
"id": "set-002-c",
"name": "linkedin_url",
"type": "string",
"value": "={{ $('Strip HTML to Plain Text').first().json.linkedin_url }}"
},
{
"id": "set-002-d",
"name": "criteria_list",
"type": "array",
"value": "={{ $('Strip HTML to Plain Text').first().json.criteria_list }}"
},
{
"id": "set-002-e",
"name": "company_summary",
"type": "string",
"value": "={{ JSON.parse($json.output).company_summary }}"
},
{
"id": "set-002-f",
"name": "industry",
"type": "string",
"value": "={{ JSON.parse($json.output).industry }}"
},
{
"id": "set-002-g",
"name": "company_size_signal",
"type": "string",
"value": "={{ JSON.parse($json.output).company_size_signal }}"
},
{
"id": "set-002-h",
"name": "tech_stack",
"type": "array",
"value": "={{ JSON.parse($json.output).tech_stack }}"
},
{
"id": "set-002-i",
"name": "criteria_signals",
"type": "object",
"value": "={{ JSON.parse($json.output).criteria_signals }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "641244a6-5b37-4023-a094-608c175af214",
"name": "Score the Lead",
"type": "@n8n/n8n-nodes-langchain.agent",
"onError": "continueErrorOutput",
"position": [
7648,
2192
],
"parameters": {
"text": "=Score this B2B lead against the buyer's criteria using real website intelligence:\n\nCompany: {{ $json.company_name }}\nWebsite: {{ $json.website_url }}\nLinkedIn: {{ $json.linkedin_url }}\nBuyer criteria: {{ ($json.criteria_list || []).join(', ') }}\nWhat the company does: {{ $json.company_summary }}\nIndustry: {{ $json.industry }}\nCompany size signal: {{ $json.company_size_signal }}\nTech stack detected: {{ ($json.tech_stack || []).join(', ') }}\nCriteria signals from page: {{ JSON.stringify($json.criteria_signals || {}) }}\n\nScore 1-10. Grade: A (8-10), B (6-7), C (4-5), D (1-3). Write 2-3 sentence reasoning and one-sentence recommended action.",
"options": {
"systemMessage": "You are a lead scoring agent for a B2B sales team. Score leads based on real website intelligence, not assumptions.\n\nCRITICAL: Return ONLY a raw JSON object. No markdown fences, no explanation.\n\nOUTPUT SCHEMA: {\"score\": 7, \"grade\": \"B\", \"reasoning\": \"2-3 sentence explanation grounded in the website data\", \"recommended_action\": \"one sentence for the sales rep\"}"
},
"promptType": "define"
},
"typeVersion": 3
},
{
"id": "b61e1f00-4544-473f-9dbb-09de4890675c",
"name": "GPT-5.4 Model 3",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"position": [
7648,
2352
],
"parameters": {
"model": "gpt-5.4",
"options": {}
},
"credentials": {
"openAiApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "87274bd4-056c-4d50-b3cb-62ebcea28be9",
"name": "Build Sheet Row",
"type": "n8n-nodes-base.set",
"position": [
7984,
2176
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "set-003-a",
"name": "timestamp",
"type": "string",
"value": "={{ $now.toISO() }}"
},
{
"id": "set-003-b",
"name": "company",
"type": "string",
"value": "={{ $('Map Website Analysis').first().json.company_name }}"
},
{
"id": "set-003-c",
"name": "website_url",
"type": "string",
"value": "={{ $('Map Website Analysis').first().json.website_url }}"
},
{
"id": "set-003-d",
"name": "linkedin_url",
"type": "string",
"value": "={{ $('Map Website Analysis').first().json.linkedin_url }}"
},
{
"id": "set-003-e",
"name": "criteria",
"type": "string",
"value": "={{ ($('Map Website Analysis').first().json.criteria_list || []).join(', ') }}"
},
{
"id": "set-003-f",
"name": "company_summary",
"type": "string",
"value": "={{ $('Map Website Analysis').first().json.company_summary }}"
},
{
"id": "set-003-g",
"name": "tech_stack",
"type": "string",
"value": "={{ ($('Map Website Analysis').first().json.tech_stack || []).join(', ') }}"
},
{
"id": "set-003-h",
"name": "score",
"type": "number",
"value": "={{ JSON.parse($json.output).score }}"
},
{
"id": "set-003-i",
"name": "grade",
"type": "string",
"value": "={{ JSON.parse($json.output).grade }}"
},
{
"id": "set-003-j",
"name": "reasoning",
"type": "string",
"value": "={{ JSON.parse($json.output).reasoning }}"
},
{
"id": "set-003-k",
"name": "recommended_action",
"type": "string",
"value": "={{ JSON.parse($json.output).recommended_action }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "8058a091-67d7-4131-a149-def64a4b9a02",
"name": "Tally Trigger",
"type": "n8n-nodes-tallyforms.tallyTrigger",
"position": [
5568,
2224
],
"parameters": {
"formId": "YOUR_TALLY_FORM_ID"
},
"credentials": {
"tallyApi": {
"name": "<your credential>"
}
},
"typeVersion": 2
},
{
"id": "82fa06c7-03dc-41f8-b1e5-efca5ae94b9f",
"name": "Sticky Note - Data Capture",
"type": "n8n-nodes-base.stickyNote",
"position": [
5536,
1888
],
"parameters": {
"color": 7,
"width": 756,
"height": 712,
"content": "## Data Capture & Normalization\n\nTally Trigger captures lead data on form submit. Agent 1 normalizes the raw payload. Map Lead Fields organizes the data for the research phase."
},
"typeVersion": 1
},
{
"id": "1577ddf9-48f7-4f63-b424-dc3fa5e78ee3",
"name": "Sticky Note - Research",
"type": "n8n-nodes-base.stickyNote",
"position": [
6336,
1888
],
"parameters": {
"color": 7,
"width": 1052,
"height": 728,
"content": "## Website Research & Analysis\n\nFetches the company homepage, strips HTML to plain text, and sends it to Agent 2 for intelligence extraction: industry, tech stack, size signals, and criteria matches."
},
"typeVersion": 1
},
{
"id": "27eb2a26-22dc-4916-9dcf-fa75ca20fbef",
"name": "Sticky Note - Scoring & Output",
"type": "n8n-nodes-base.stickyNote",
"position": [
7424,
1888
],
"parameters": {
"color": 7,
"width": 952,
"height": 664,
"content": "## Lead Scoring & Output\n\nAgent 3 scores 1-10 against the buyer's criteria and assigns a grade. Build Sheet Row formats the data and appends it to Google Sheets."
},
"typeVersion": 1
},
{
"id": "34169519-3911-441c-8e01-6254d771ee02",
"name": "Sticky Note - Overview",
"type": "n8n-nodes-base.stickyNote",
"position": [
5008,
1888
],
"parameters": {
"width": 500,
"height": 884,
"content": "## Score Inbound Leads with AI using Tally, OpenAI and Google Sheets\n\n### How it works\n1. A marketing employee submits a Tally form with a company name, LinkedIn URL, website URL, and scoring criteria.\n2. The Tally Trigger fires instantly on submission and passes the raw payload to Agent 1, which normalises it into clean fields.\n3. An HTTP Request fetches the company's actual homepage HTML.\n4. A Code node strips the HTML to readable plain text.\n5. Agent 2 reads the real homepage content and extracts B2B intelligence: what the company does, their tech stack, size signals, and industry.\n6. Agent 3 scores the lead 1-10 against the criteria from the Tally form, assigns a grade A-D, and writes a recommended action.\n7. The scored lead is appended to a Google Sheet.\n\n### Setup\n1. Create your lead scoring form in Tally with fields: Company Name, LinkedIn URL, Company Website URL, Scoring Criteria (checkboxes), and Additional Notes.\n2. Connect the Tally Trigger node and select your Tally form from the dropdown.\n3. Add your OpenAI API key under Credentials > OpenAI.\n4. Add Google Sheets OAuth2 credentials.\n5. Create a Google Sheet with a tab named exactly \"leads\" and these column headers in Row 1 (all lowercase):\n timestamp | company | website_url | linkedin_url | criteria | company_summary | tech_stack | score | grade | reasoning | recommended_action\n6. Paste your Sheet ID into the Append Lead to Sheet node.\n7. Submit a test entry through your Tally form to verify the full flow."
},
"typeVersion": 1
},
{
"id": "512d45e1-6c4e-4752-8279-2f61a0080a47",
"name": "Append Lead to Sheet",
"type": "n8n-nodes-base.googleSheets",
"position": [
8192,
2176
],
"parameters": {
"columns": {
"value": {
"grade": "={{ $json.grade }}",
"score": "={{ $json.score }}",
"company": "={{ $json.company }}",
"criteria": "={{ $json.criteria }}",
"reasoning": "={{ $json.reasoning }}",
"timestamp": "={{ $json.timestamp }}",
"tech_stack": "={{ $json.tech_stack }}",
"website_url": "={{ $json.website_url }}",
"linkedin_url": "={{ $json.linkedin_url }}",
"company_summary": "={{ $json.company_summary }}",
"recommended_action": "={{ $json.recommended_action }}"
},
"schema": [
{
"id": "timestamp",
"type": "string",
"display": true,
"required": false,
"displayName": "timestamp",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "company",
"type": "string",
"display": true,
"required": false,
"displayName": "company",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "website_url",
"type": "string",
"display": true,
"required": false,
"displayName": "website_url",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "linkedin_url",
"type": "string",
"display": true,
"required": false,
"displayName": "linkedin_url",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "criteria",
"type": "string",
"display": true,
"required": false,
"displayName": "criteria",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "company_summary",
"type": "string",
"display": true,
"required": false,
"displayName": "company_summary",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "tech_stack",
"type": "string",
"display": true,
"required": false,
"displayName": "tech_stack",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "score",
"type": "string",
"display": true,
"required": false,
"displayName": "score",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "grade",
"type": "string",
"display": true,
"required": false,
"displayName": "grade",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "reasoning",
"type": "string",
"display": true,
"required": false,
"displayName": "reasoning",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "recommended_action",
"type": "string",
"display": true,
"required": false,
"displayName": "recommended_action",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "id",
"value": "leads"
},
"documentId": {
"__rl": true,
"mode": "id",
"value": "YOUR_SPREADSHEET_ID"
}
},
"credentials": {},
"typeVersion": 4.7
}
],
"connections": {
"GPT-5.4 Model": {
"ai_languageModel": [
[
{
"node": "Normalise Tally Payload",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Tally Trigger": {
"main": [
[
{
"node": "Normalise Tally Payload",
"type": "main",
"index": 0
}
]
]
},
"Score the Lead": {
"main": [
[
{
"node": "Build Sheet Row",
"type": "main",
"index": 0
}
]
]
},
"Build Sheet Row": {
"main": [
[
{
"node": "Append Lead to Sheet",
"type": "main",
"index": 0
}
]
]
},
"GPT-5.4 Model 2": {
"ai_languageModel": [
[
{
"node": "Analyse Website Content",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"GPT-5.4 Model 3": {
"ai_languageModel": [
[
{
"node": "Score the Lead",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Map Lead Fields": {
"main": [
[
{
"node": "Fetch Company Homepage",
"type": "main",
"index": 0
}
]
]
},
"Map Website Analysis": {
"main": [
[
{
"node": "Score the Lead",
"type": "main",
"index": 0
}
]
]
},
"Fetch Company Homepage": {
"main": [
[
{
"node": "Strip HTML to Plain Text",
"type": "main",
"index": 0
}
],
[
{
"node": "Strip HTML to Plain Text",
"type": "main",
"index": 0
}
]
]
},
"Analyse Website Content": {
"main": [
[
{
"node": "Map Website Analysis",
"type": "main",
"index": 0
}
]
]
},
"Normalise Tally Payload": {
"main": [
[
{
"node": "Map Lead Fields",
"type": "main",
"index": 0
}
]
]
},
"Strip HTML to Plain Text": {
"main": [
[
{
"node": "Analyse Website Content",
"type": "main",
"index": 0
}
]
]
}
}
}
Credentials you'll need
Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.
openAiApitallyApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This workflow automatically scores B2B leads by fetching and analyzing real company website data. It helps marketing and sales teams qualify inbound leads without manually researching each company.
Source: https://n8n.io/workflows/15059/ — 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.
K&S-Media Downloadliste SQL. Uses httpRequest, agent, googleSheets, lmChatOpenAi. Event-driven trigger; 97 nodes.
🎯 Create viral TikToks, Shorts, Reels, podcasts, and ASMR videos in minutes — all on autopilot.
Generate AI viral videos with NanoBanana & VEO3, shared on socials via Blotato 2. Uses @blotato/n8n-nodes-blotato, googleSheets, lmChatOpenAi, toolThink. Event-driven trigger; 94 nodes.
> Note: This workflow uses sticky notes extensively to document each logical section of the automation. Sticky notes are mandatory and already included to explain OCR, AI parsing, folder logic, dup
This template is designed for marketers, content creators, and e-commerce brands who want to automate the creation of professional ad videos at scale. It’s ideal for teams looking to generate consiste