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 →
{
"name": "Comet LeadGen Pipeline",
"nodes": [
{
"parameters": {
"rule": {
"interval": [
{
"field": "cronExpression",
"expression": "0 19 * * 2,3,4"
}
]
}
},
"name": "Cron \u2014 Tu/We/Th 19:00 UTC",
"type": "n8n-nodes-base.cron",
"typeVersion": 1,
"position": [
240,
300
],
"id": "node-cron-01"
},
{
"parameters": {
"httpMethod": "POST",
"path": "comet-trigger",
"responseMode": "responseNode",
"options": {}
},
"name": "Webhook Trigger (manual)",
"type": "n8n-nodes-base.webhook",
"typeVersion": 1,
"position": [
240,
460
],
"id": "node-webhook-01"
},
{
"parameters": {
"functionCode": "// Step 1 \u2014 Merge trigger, validate payload\nconst data = $input.item.json;\nconst icp = data.icp || 'usa_dental_medspa';\nconst dryRun = data.dry_run || false;\n\nconst validIcps = ['usa_dental_medspa', 'pl_logistyka_wielkopolska'];\nif (!validIcps.includes(icp)) {\n throw new Error(`Unknown ICP: ${icp}. Valid: ${validIcps.join(', ')}`);\n}\n\nreturn [{\n json: {\n project_id: `CP-${new Date().toISOString().replace(/[^0-9]/g, '').slice(0,14)}`,\n icp,\n dry_run: dryRun,\n started_at: new Date().toISOString(),\n status: 'AWAITING_SCRAPE'\n }\n}];"
},
"name": "Step 1 \u2014 Init Pipeline",
"type": "n8n-nodes-base.function",
"typeVersion": 1,
"position": [
460,
380
],
"id": "node-step1"
},
{
"parameters": {
"url": "={{$env['SCRAPIO_BASE_URL']}}/companies/search",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "=Bearer {{$env['SCRAPIO_API_KEY']}}"
}
]
},
"sendBody": true,
"bodyParameters": {
"parameters": [
{
"name": "industry",
"value": "={{$json.icp === 'usa_dental_medspa' ? 'dental healthcare medspa' : 'logistics transportation'}}"
},
{
"name": "location",
"value": "={{$json.icp === 'usa_dental_medspa' ? 'USA' : 'Wielkopolska Poland'}}"
},
{
"name": "limit",
"value": "=50"
}
]
},
"options": {
"timeout": 30000
}
},
"name": "Step 2 \u2014 Scrap.io Search",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 3,
"position": [
680,
380
],
"id": "node-step2"
},
{
"parameters": {
"functionCode": "// Step 3 \u2014 Build search params + filter Scrap.io results\nconst state = $('Step 1 \u2014 Init Pipeline').item.json;\nconst scrapio = $input.item.json;\n\nconst companies = scrapio.companies || [];\n\n// Map do naszego formatu\nconst rawLeads = companies.map((c, i) => ({\n id: `${state.project_id}-${String(i+1).padStart(3,'0')}`,\n name: c.name || '',\n address: c.address || '',\n phone: c.phone || null,\n website: c.website || null,\n email: c.email || null,\n employee_count: c.employee_count || null,\n linkedin_url: c.linkedin_url || null,\n source: 'scrapio'\n})).filter(l => l.name);\n\nreturn [{\n json: {\n ...state,\n raw_leads: rawLeads,\n raw_leads_count: rawLeads.length,\n status: 'AWAITING_LLM_PARSE'\n }\n}];"
},
"name": "Step 3 \u2014 Build Search Params",
"type": "n8n-nodes-base.function",
"typeVersion": 1,
"position": [
900,
380
],
"id": "node-step3"
},
{
"parameters": {
"url": "https://api.openai.com/v1/chat/completions",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "=Bearer {{$env['OPENAI_API_KEY']}}"
}
]
},
"sendBody": true,
"bodyParameters": {
"parameters": [
{
"name": "model",
"value": "gpt-4o-mini"
},
{
"name": "messages",
"value": "=[{\"role\":\"system\",\"content\":\"You are a B2B lead qualifier. Return valid JSON only.\"},{\"role\":\"user\",\"content\":\"Qualify these leads and score A/B/C fit for AI automation services. Return JSON array with fields: name, fit_score, confidence (0-100), approach_angle, hours_saved_monthly, disqualify (bool). Leads: \" + JSON.stringify($json.raw_leads.slice(0,10))}]"
},
{
"name": "response_format",
"value": "={\"type\":\"json_object\"}"
},
{
"name": "temperature",
"value": "=0.1"
}
]
},
"options": {
"timeout": 60000
}
},
"name": "Step 5 \u2014 LLM Parser (OpenAI)",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 3,
"position": [
1120,
380
],
"id": "node-step5-llm"
},
{
"parameters": {
"functionCode": "// Step 5b \u2014 Parse LLM response + triage\nconst state = $('Step 3 \u2014 Build Search Params').item.json;\nconst llmResp = $input.item.json;\n\nlet parsedLeads = [];\ntry {\n const content = llmResp.choices[0].message.content;\n const data = JSON.parse(content);\n parsedLeads = data.leads || data.results || [];\n} catch(e) {\n console.error('LLM parse error:', e.message);\n}\n\n// Triage\nconst enrichedLeads = parsedLeads.filter(l => \n !l.disqualify && \n ['A','B'].includes(l.fit_score) && \n (l.confidence || 0) >= 40\n);\n\nconst failedLeads = parsedLeads.filter(l => l.disqualify);\n\nreturn [{\n json: {\n ...state,\n parsed_leads: parsedLeads,\n enriched_leads: enrichedLeads,\n failed_leads: failedLeads,\n enriched_count: enrichedLeads.length,\n status: 'AWAITING_CRM_EXPORT'\n }\n}];"
},
"name": "Step 6 \u2014 Triage + Exception Check",
"type": "n8n-nodes-base.function",
"typeVersion": 1,
"position": [
1340,
380
],
"id": "node-step6"
},
{
"parameters": {
"conditions": {
"number": [
{
"value1": "={{$json.enriched_count}}",
"operation": "larger",
"value2": 0
}
]
}
},
"name": "Has Qualified Leads?",
"type": "n8n-nodes-base.if",
"typeVersion": 1,
"position": [
1560,
380
],
"id": "node-if-leads"
},
{
"parameters": {
"url": "https://api.hubapi.com/crm/v3/objects/contacts/batch/create",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "=Bearer {{$env['HUBSPOT_API_KEY']}}"
}
]
},
"sendBody": true,
"bodyParameters": {
"parameters": [
{
"name": "inputs",
"value": "={{$json.enriched_leads.map(l => ({properties: {company: l.name, address: l._address || '', phone: l._phone || '', lead_fit_score: l.fit_score, approach_angle: l.approach_angle || '', hs_lead_status: 'NEW'}}))}}"
}
]
},
"options": {
"timeout": 30000
}
},
"name": "Step 7a \u2014 HubSpot Export",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 3,
"position": [
1780,
300
],
"id": "node-step7-hubspot"
},
{
"parameters": {
"functionCode": "// Step 8 \u2014 Generate final report + Slack notification\nconst state = $('Step 6 \u2014 Triage + Exception Check').item.json;\nconst hubspotResult = $input.item.json;\n\nconst exportedCount = (hubspotResult.results || []).length;\nconst topLeads = (state.enriched_leads || []).slice(0,3).map(l => l.name).join(', ');\n\nconst report = {\n project_id: state.project_id,\n icp: state.icp,\n status: 'DONE',\n raw_count: state.raw_leads_count,\n parsed_count: (state.parsed_leads || []).length,\n exported_count: exportedCount,\n top_leads: topLeads,\n generated_at: new Date().toISOString()\n};\n\nreturn [{json: report}];"
},
"name": "Step 8 \u2014 Report Generator",
"type": "n8n-nodes-base.function",
"typeVersion": 1,
"position": [
2000,
300
],
"id": "node-step8"
},
{
"parameters": {
"url": "={{$env['SLACK_WEBHOOK_URL']}}",
"sendBody": true,
"bodyParameters": {
"parameters": [
{
"name": "text",
"value": "=\u2705 *Comet Pipeline {{$json.project_id}}* \u2014 DONE\n\ud83d\udcca Scraped: {{$json.raw_count}} | Exported: {{$json.exported_count}}\n\ud83c\udfc6 Top: {{$json.top_leads}}\n\ud83d\udccc ICP: `{{$json.icp}}`"
}
]
},
"options": {}
},
"name": "Slack Notification",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 3,
"position": [
2220,
300
],
"id": "node-slack"
},
{
"parameters": {
"functionCode": "// No qualified leads \u2014 log and stop\nconst state = $json;\nconsole.log('No qualified leads for project:', state.project_id);\nreturn [{json: {...state, status: 'NO_LEADS'}}];"
},
"name": "Log \u2014 No Leads",
"type": "n8n-nodes-base.function",
"typeVersion": 1,
"position": [
1780,
480
],
"id": "node-no-leads"
}
],
"connections": {
"Cron \u2014 Tu/We/Th 19:00 UTC": {
"main": [
[
{
"node": "Step 1 \u2014 Init Pipeline",
"type": "main",
"index": 0
}
]
]
},
"Webhook Trigger (manual)": {
"main": [
[
{
"node": "Step 1 \u2014 Init Pipeline",
"type": "main",
"index": 0
}
]
]
},
"Step 1 \u2014 Init Pipeline": {
"main": [
[
{
"node": "Step 2 \u2014 Scrap.io Search",
"type": "main",
"index": 0
}
]
]
},
"Step 2 \u2014 Scrap.io Search": {
"main": [
[
{
"node": "Step 3 \u2014 Build Search Params",
"type": "main",
"index": 0
}
]
]
},
"Step 3 \u2014 Build Search Params": {
"main": [
[
{
"node": "Step 5 \u2014 LLM Parser (OpenAI)",
"type": "main",
"index": 0
}
]
]
},
"Step 5 \u2014 LLM Parser (OpenAI)": {
"main": [
[
{
"node": "Step 6 \u2014 Triage + Exception Check",
"type": "main",
"index": 0
}
]
]
},
"Step 6 \u2014 Triage + Exception Check": {
"main": [
[
{
"node": "Has Qualified Leads?",
"type": "main",
"index": 0
}
]
]
},
"Has Qualified Leads?": {
"main": [
[
{
"node": "Step 7a \u2014 HubSpot Export",
"type": "main",
"index": 0
}
],
[
{
"node": "Log \u2014 No Leads",
"type": "main",
"index": 0
}
]
]
},
"Step 7a \u2014 HubSpot Export": {
"main": [
[
{
"node": "Step 8 \u2014 Report Generator",
"type": "main",
"index": 0
}
]
]
},
"Step 8 \u2014 Report Generator": {
"main": [
[
{
"node": "Slack Notification",
"type": "main",
"index": 0
}
]
]
}
},
"active": false,
"settings": {
"executionOrder": "v1",
"errorWorkflow": "",
"timezone": "UTC"
},
"tags": [
"leadgen",
"comet",
"b2b",
"n8n"
],
"versionId": "1.0.0"
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Comet LeadGen Pipeline. Uses httpRequest. Scheduled trigger; 12 nodes.
Source: https://github.com/Gruszkoland/leadgen-comet/blob/master/n8n_workflows/comet_leadgen_pipeline.json — 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.
Workflow A — WhatsApp Lead Intake & Qualification. Uses postgres, httpRequest, errorTrigger. Scheduled trigger; 67 nodes.
Build authentic Reddit presence and generate qualified leads through AI-powered community engagement that provides genuine value without spam or promotion.
This workflow runs on scheduled weekly and monthly triggers to generate unified marketing performance reports. It processes multiple websites by collecting analytics data, paid ads performance, and CR
Fetch Multiple Google Analytics GA4 metrics daily, post to Discord, update previous day’s entry as GA data finalizes over seven days. Automates daily traffic reporting Maintains single message per day
WABA Message Journey Flow Documentation This document outlines the automated workflow for sending WhatsApp messages to contacts, triggered hourly and managed through disposition and message count logi