This workflow corresponds to n8n.io template #17339 — we link there as the canonical source.
This workflow follows the HubSpot → Slack 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": "agMwsrOiBW2hGa83",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "Lead Capture Lite FREE (Form \u2192 HubSpot \u2192 Slack)",
"tags": [],
"nodes": [
{
"id": "bed610d8-7dbd-47a9-a43a-87cfbdd53586",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-16,
-144
],
"parameters": {
"width": 452,
"height": 608,
"content": "## Lead Capture Lite \u2014 Form \u2192 HubSpot \u2192 Slack\n\n**What it does**: Receives form submissions via webhook, normalizes the fields (name split, phone cleanup, email validation), upserts the contact into HubSpot, and posts a notification card to Slack.\n\n**Setup (5 min)**:\n1. Add your **HubSpot** credential to the Upsert node (service key / private app / OAuth2 with `crm.objects.contacts` read/write)\n2. Add your **Slack** credential to the Notify node (`chat:write` scope, invite the bot to your channel)\n3. Change the Slack channel in the Notify node (default `#leads`)\n4. Activate, copy the **Production** webhook URL into your form tool (Typeform/Tally/website form POST)\n\n**Field mapping**: common names (email/name/phone/company/message and their variants) are handled automatically. To add a custom field name, add an alias in the `pick(...)` calls at the top of the Normalize node."
},
"typeVersion": 1
},
{
"id": "73bfb4c4-e55b-4e84-89fa-0837f0c48797",
"name": "Webhook - Form Intake",
"type": "n8n-nodes-base.webhook",
"position": [
480,
128
],
"parameters": {
"path": "lead-intake-lite",
"options": {},
"httpMethod": "POST"
},
"typeVersion": 2
},
{
"id": "399dbbd1-61fb-4409-902a-27140d00a691",
"name": "Normalize",
"type": "n8n-nodes-base.code",
"position": [
704,
128
],
"parameters": {
"jsCode": "const raw = $input.first().json.body || $input.first().json;\nconst pick = (...keys) => { for (const k of keys) { if (raw[k]) return String(raw[k]).trim(); } return ''; };\nconst email = pick('email','Email','work_email').toLowerCase();\nconst fullName = pick('name','full_name','Name');\nconst nameParts = fullName.split(/\\s+/);\nreturn [{ json: {\n email,\n firstName: nameParts[0] || '',\n lastName: nameParts.slice(1).join(' ') || '',\n fullName,\n phone: pick('phone','Phone').replace(/(?!^\\+)[^\\d]/g, ''),\n company: pick('company','Company'),\n message: pick('message','Message'),\n emailOk: /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(email)\n} }];"
},
"typeVersion": 2
},
{
"id": "20798e5e-bdd6-4d69-adc8-d840dad89a13",
"name": "HubSpot - Upsert Contact",
"type": "n8n-nodes-base.hubspot",
"position": [
928,
128
],
"parameters": {
"email": "={{ $json.email }}",
"options": {},
"authentication": "appToken",
"additionalFields": {
"lastName": "={{ $json.lastName }}",
"firstName": "={{ $json.firstName }}",
"companyName": "={{ $json.company }}",
"phoneNumber": "={{ $json.phone }}"
}
},
"credentials": {
"hubspotAppToken": {
"name": "<your credential>"
}
},
"typeVersion": 2.1
},
{
"id": "6fe6cef3-d9cf-48f4-8cb2-139e508b15e6",
"name": "Slack - Notify",
"type": "n8n-nodes-base.slack",
"position": [
1152,
128
],
"parameters": {
"text": "=\ud83c\udd95 New lead: *{{ $('Normalize').first().json.fullName }}* ({{ $('Normalize').first().json.email }}) \u2014 {{ $('Normalize').first().json.company || 'no company' }}\n\ud83d\udcac {{ $('Normalize').first().json.message || '(no message)' }}",
"select": "channel",
"channelId": {
"__rl": true,
"mode": "name",
"value": "#leads"
},
"otherOptions": {}
},
"credentials": {
"slackApi": {
"name": "<your credential>"
}
},
"typeVersion": 2.3
}
],
"active": false,
"settings": {
"binaryMode": "separate",
"availableInMCP": false,
"executionOrder": "v1"
},
"versionId": "34b99146-0479-4db6-a108-0173faff0d74",
"nodeGroups": [],
"connections": {
"Normalize": {
"main": [
[
{
"node": "HubSpot - Upsert Contact",
"type": "main",
"index": 0
}
]
]
},
"Webhook - Form Intake": {
"main": [
[
{
"node": "Normalize",
"type": "main",
"index": 0
}
]
]
},
"HubSpot - Upsert Contact": {
"main": [
[
{
"node": "Slack - Notify",
"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.
hubspotAppTokenslackApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This workflow receives form submissions via an n8n webhook, normalizes lead fields (name, email, phone, company, message), upserts the contact into HubSpot, and posts a new-lead notification to a Slack channel. Receives a POST request with lead data through an n8n webhook…
Source: https://n8n.io/workflows/17339/ — 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.
This is ideal for agencies, freelancers, SaaS founders, and small sales teams who want every lead recorded and followed up automatically within seconds. The workflow supports two storage options: HubS
This workflow receives inbound leads via webhook, uses Anthropic Claude (with website scraping and web search) to score and classify them, then updates HubSpot lifecycle stage, creates deals for hot l
Real-Time Lead Processing - Captures and processes leads instantly from website forms with zero delay Intelligent Fit Scoring - Automatically scores leads 0-100 based on company size, seniority, and r
This workflow receives B2B referral submissions via a webhook, validates the payload, emails the referrer and referred lead via Gmail, alerts the sales team in Slack, deduplicates and creates records
This workflow receives inbound leads via webhook, validates and normalizes the data, scores and routes the lead to a sales rep, checks for duplicates and upserts the contact in HubSpot, drafts an outr