This workflow corresponds to n8n.io template #14859 — we link there as the canonical source.
This workflow follows the Form Trigger → 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
},
"name": "Job Search Lead Generation Workflow",
"nodes": [
{
"id": "eac4c227-44d3-49bd-8a14-953a7df6b376",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-32,
128
],
"parameters": {
"width": 480,
"height": 576,
"content": "### How it works\n\n1. Captures job search inputs via the form.\n2. Parses inputs and initiates scraper for job listings.\n3. Scrapes jobs and removes duplicates before saving.\n4. Scores jobs using AI and determines lead qualification.\n5. Saves qualified jobs and loops back for next batch.\n\n### Setup steps\n\n- [ ] Ensure Apify API credentials are set for job scraping.\n- [ ] Connect to Google Sheets API for saving and retrieving data.\n- [ ] Configure OpenAI API credentials for AI scoring.\n- [ ] Ensure Gmail API access for sending messages to be configured.\n\n### Customization\n\nAdjust the AI scoring logic in the 'AI Score and Qualify Lead' node to match specific business criteria.\n\n\nMake a copy of Gsheets: https://docs.google.com/spreadsheets/d/1-7nF5jwil_PenpLfLlqlTdDfBj5q4987drCZj2gkLrQ/edit?usp=sharing"
},
"typeVersion": 1
},
{
"id": "99d2484a-dd46-4486-b51e-091021f52fb7",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
560,
304
],
"parameters": {
"color": 7,
"width": 384,
"height": 304,
"content": "## Input and parse form\n\nCaptures job search inputs and parses them for further processing."
},
"typeVersion": 1
},
{
"id": "8196d2b0-2269-4940-97ff-f9d3c5bf2d27",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
976,
240
],
"parameters": {
"color": 7,
"height": 352,
"content": "## Iterate through searches\n\nLoops through parsed search terms and initiates the job scraping process."
},
"typeVersion": 1
},
{
"id": "0761d4da-95a7-4ee6-ace2-9c30c75ee843",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
1248,
320
],
"parameters": {
"color": 7,
"width": 544,
"height": 448,
"content": "## Scrape jobs and notify\n\nScrapes job listings using Apify and sends notification emails."
},
"typeVersion": 1
},
{
"id": "5348e392-1682-474a-8991-5825d80b1832",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
1424,
0
],
"parameters": {
"color": 7,
"width": 864,
"height": 272,
"content": "## Flatten, deduplicate, and save\n\nProcesses scraped data, removes duplicates, and saves raw jobs to a sheet."
},
"typeVersion": 1
},
{
"id": "50fad5bf-1db9-4255-bd6a-e1429c8edbbc",
"name": "Sticky Note5",
"type": "n8n-nodes-base.stickyNote",
"position": [
2352,
224
],
"parameters": {
"color": 7,
"width": 384,
"height": 400,
"content": "## Loop each job and check company\n\nIterates through each saved job and checks for company name presence."
},
"typeVersion": 1
},
{
"id": "0969dc55-06b0-4a2f-819e-b711af10ceae",
"name": "Sticky Note6",
"type": "n8n-nodes-base.stickyNote",
"position": [
2768,
80
],
"parameters": {
"color": 7,
"width": 368,
"height": 304,
"content": "## Company name validation\n\nValidates the presence of a company name and saves non-qualified jobs."
},
"typeVersion": 1
},
{
"id": "55d5679f-9248-4f44-b516-8a29760c99f2",
"name": "Sticky Note7",
"type": "n8n-nodes-base.stickyNote",
"position": [
3168,
192
],
"parameters": {
"color": 7,
"width": 1312,
"height": 496,
"content": "## AI score and lead qualification\n\nScores jobs using AI and determines lead qualification, saving qualified leads."
},
"typeVersion": 1
},
{
"id": "ebe65da7-02d2-4481-a2f5-639e0c2b6697",
"name": "When Job Form Submitted",
"type": "n8n-nodes-base.formTrigger",
"position": [
608,
432
],
"parameters": {
"options": {},
"formTitle": "Job Search Configuration",
"formFields": {
"values": [
{
"fieldLabel": "Job Roles",
"placeholder": "Chef, Nurse, Driver, Welder",
"requiredField": true
},
{
"fieldLabel": "Locations",
"placeholder": "Kuwait, UAE, Germany",
"requiredField": true
},
{
"fieldType": "number",
"fieldLabel": "Max Results Per Search",
"placeholder": "Minimum 10"
},
{
"fieldType": "dropdown",
"fieldLabel": "Posted Since",
"fieldOptions": {
"values": [
{
"option": "24 hours"
},
{
"option": "3 days"
},
{
"option": "1 week"
},
{
"option": "2 weeks"
},
{
"option": "1 month"
}
]
}
}
]
},
"formDescription": "Configure job search parameters for lead generation"
},
"typeVersion": 2.5
},
{
"id": "95f70dc7-5ead-4a29-8408-a5bf2afd0f2d",
"name": "Parse Form Input Arrays",
"type": "n8n-nodes-base.code",
"position": [
800,
432
],
"parameters": {
"jsCode": "// Parse the form inputs into arrays\nconst jobRoles = $input.first().json['Job Roles']\n .split(',')\n .map(r => r.trim())\n .filter(r => r.length > 0);\n\nconst locations = $input.first().json['Locations']\n .split(',')\n .map(l => l.trim())\n .filter(l => l.length > 0);\n\nconst maxResults = parseInt($input.first().json['Max Results Per Search']) || 10;\nconst postedSince = $input.first().json['Posted Since'] || '1 week';\n\n// Create search combinations\nconst searches = [];\nfor (const role of jobRoles) {\n for (const location of locations) {\n searches.push({\n job_role: role,\n location: location,\n max_results: maxResults,\n posted_since: postedSince\n });\n }\n}\n\nreturn searches.map(s => ({ json: s }));"
},
"typeVersion": 2
},
{
"id": "1bc35fcc-51b9-42e9-a1b4-c05fc6b8918d",
"name": "Loop Over Search Batches",
"type": "n8n-nodes-base.splitInBatches",
"position": [
1024,
432
],
"parameters": {
"options": {
"reset": false
}
},
"typeVersion": 3
},
{
"id": "38ba3296-d66e-4526-8277-2b9a2623b16a",
"name": "Flatten Job Results and ID",
"type": "n8n-nodes-base.code",
"position": [
1472,
112
],
"parameters": {
"jsCode": "// Flatten all job results and add unique IDs\nconst jobs = $input.all().flatMap(item => {\n if (Array.isArray(item.json)) {\n return item.json;\n }\n return [item.json];\n});\n\n// Add unique IDs and search context\nconst searchContext = $('Loop Over Search Batches').item.json;\n\n// Simple hash function for deduplication\nfunction simpleHash(str) {\n let hash = 0;\n for (let i = 0; i < str.length; i++) {\n const char = str.charCodeAt(i);\n hash = ((hash << 5) - hash) + char;\n hash = hash & hash; // Convert to 32bit integer\n }\n return Math.abs(hash).toString(36);\n}\n\nreturn jobs.map((job, idx) => {\n // Create deterministic hash from job_url or company+title+location\n const hashInput = (job.job_url || `${job.company_name || ''}|${job.job_title || job.designation || ''}|${job.job_location || job.location || ''}`).toLowerCase().trim();\n const job_hash = simpleHash(hashInput) + '-' + simpleHash(hashInput.split('').reverse().join(''));\n\n return {\n json: {\n unique_id: `${Date.now()}-${idx}-${Math.random().toString(36).substr(2, 9)}`,\n job_hash: job_hash,\n lead_source: 'job_board',\n search_role: searchContext.job_role,\n search_location: searchContext.location,\n ...job\n }\n };\n});"
},
"typeVersion": 2
},
{
"id": "d26e5c4e-d7d0-4072-8a14-98dcd5355f1a",
"name": "Read Jobs from Sheets",
"type": "n8n-nodes-base.googleSheets",
"position": [
1696,
112
],
"parameters": {
"options": {
"outputFormatting": {
"values": {
"date": "FORMATTED_STRING",
"general": "UNFORMATTED_VALUE"
}
}
},
"sheetName": {
"__rl": true,
"mode": "id",
"value": "1451193517"
},
"documentId": {
"__rl": true,
"mode": "id",
"value": "1hex1u1cpI5sMx8I45ktgpZ4VhXReQA4EZdoCTVEc1bI"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.7,
"alwaysOutputData": true
},
{
"id": "4fed2722-26fe-49b3-91aa-1c58f23b1a64",
"name": "Identify Duplicate Jobs",
"type": "n8n-nodes-base.code",
"position": [
1920,
112
],
"parameters": {
"jsCode": "// Get flattened jobs and existing sheet data\nconst flattenedJobs = $('Flatten Job Results and ID').all();\nconst existingRows = $('Read Jobs from Sheets').all();\n\n// Build set of existing job hashes\nconst existingHashes = new Set();\nfor (const row of existingRows) {\n if (row.json.job_hash) {\n existingHashes.add(row.json.job_hash);\n }\n}\n\n// Filter out duplicates\nconst uniqueJobs = flattenedJobs.filter(job => {\n return !existingHashes.has(job.json.job_hash);\n});\n\n// If no new unique jobs, return empty array (pipeline stops naturally)\nif (uniqueJobs.length === 0) {\n return [];\n}\n\nreturn uniqueJobs;"
},
"typeVersion": 2
},
{
"id": "4ab93d56-5387-45dd-936a-c0480a265ca1",
"name": "Append Raw Jobs to Sheets",
"type": "n8n-nodes-base.googleSheets",
"position": [
2144,
112
],
"parameters": {
"columns": {
"value": {
"status": "NEW",
"job_url": "={{ $json.platform_url }}",
"job_type": "={{ $json.job_type }}",
"job_title": "={{ $json.title }}",
"unique_id": "={{ $json.unique_id }}",
"created_at": "={{ $now }}",
"job_source": "={{ $json.platform }}",
"company_name": "={{ $json.company_name }}",
"job_location": "={{ $json.location }}",
"original_json": "={{ JSON.stringify($json) }}",
"job_description": "={{ $json.description }}",
"job_posted_date": "={{ $json.posted_date }}"
},
"schema": [
{
"id": "unique_id",
"type": "string",
"display": true,
"required": false,
"displayName": "unique_id",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "job_posted_date",
"type": "string",
"display": true,
"required": false,
"displayName": "job_posted_date",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "job_source",
"type": "string",
"display": true,
"required": false,
"displayName": "job_source",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "job_title",
"type": "string",
"display": true,
"required": false,
"displayName": "job_title",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "job_location",
"type": "string",
"display": true,
"required": false,
"displayName": "job_location",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "job_description",
"type": "string",
"display": true,
"required": false,
"displayName": "job_description",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "job_type",
"type": "string",
"display": true,
"required": false,
"displayName": "job_type",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "job_url",
"type": "string",
"display": true,
"required": false,
"displayName": "job_url",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "company_name",
"type": "string",
"display": true,
"required": false,
"displayName": "company_name",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "company_id",
"type": "string",
"display": true,
"required": false,
"displayName": "company_id",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "job_category",
"type": "string",
"display": true,
"required": false,
"displayName": "job_category",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "qualified",
"type": "string",
"display": true,
"required": false,
"displayName": "qualified",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "qualification_reason",
"type": "string",
"display": true,
"required": false,
"displayName": "qualification_reason",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "status",
"type": "string",
"display": true,
"required": false,
"displayName": "status",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "original_json",
"type": "string",
"display": true,
"required": false,
"displayName": "original_json",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "created_at",
"type": "string",
"display": true,
"required": false,
"displayName": "created_at",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {
"useAppend": true
},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "id",
"value": "1726393267"
},
"documentId": {
"__rl": true,
"mode": "id",
"value": "1hex1u1cpI5sMx8I45ktgpZ4VhXReQA4EZdoCTVEc1bI"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.7
},
{
"id": "9891f9b8-220e-4a52-bed3-b59d2fad45aa",
"name": "Loop Over Job Batches",
"type": "n8n-nodes-base.splitInBatches",
"position": [
2400,
448
],
"parameters": {
"options": {
"reset": false
}
},
"typeVersion": 3
},
{
"id": "7f1acfec-3935-4e47-8dc3-8fa014c6571f",
"name": "AI Job Scoring Agent",
"type": "@n8n/n8n-nodes-langchain.openAi",
"position": [
3216,
368
],
"parameters": {
"modelId": {
"__rl": true,
"mode": "list",
"value": "gpt-4o-mini",
"cachedResultName": "GPT-4O-MINI"
},
"options": {
"textFormat": {
"textOptions": {
"type": "json_object"
}
}
},
"responses": {
"values": [
{
"content": "=You are a lead qualification engine for a manpower recruitment agency.\n\nCONTEXT:\nWe supply manpower for hospitality, logistics, healthcare, oil & gas, and construction industries.\nWe help companies fill urgent hiring needs with international candidates.\n\nINPUT:\n\n* Job Title: {{ $json.job_title }}\n* Job Location: {{ $json.job_location }}\n* Company Name: {{ $json.company_name }}\n* Platform: {{ $json.job_source }}\n* Job Description: {{ $json.job_description }}\n\n---\n\nCOUNTRY EXTRACTION RULE:\n\nExtract the COUNTRY from the job location.\n\nExamples:\n\n* \"Geldern, NW, DE\" \u2192 Germany\n* \"Dubai, UAE\" \u2192 United Arab Emirates\n* \"Kuwait City\" \u2192 Kuwait\n* \"Doha, QA\" \u2192 Qatar\n* \"Remote\" \u2192 Remote\n* If unclear \u2192 return \"Unknown\"\n\n---\n\nSCORING LOGIC (1 to 10):\n\nHigh Score (8-10):\n\n* Job is in hospitality, logistics, healthcare, oil & gas, or construction\n* Role is frontline or mid-level (nurse, cook, driver, welder, laborer)\n* Country is GCC (UAE, Saudi Arabia, Qatar, Kuwait, Oman, Bahrain) OR Malaysia, Singapore, Brunei\n* Company is active employer (not job board or agency)\n* Job posted recently (within 30 days)\n\nMedium Score (5-7):\n\n* Role is relevant but senior (HR Manager, Operations Director)\n* Company industry partially relevant\n* Country outside GCC but still valid market\n\nLow Score (1-4):\n\n* Role unrelated (IT, Marketing, Finance)\n* Company appears to be staffing agency\n* Job appears fake or incomplete\n\n---\n\nDECISION:\n\n* Score 7+ \u2192 ACCEPT\n* Score < 7 \u2192 REJECT\n\n---\n\nINDUSTRY CLASSIFICATION:\nClassify the job into exactly ONE of these industries:\n\n* Oil & Gas\n* Construction\n* Services (Banking & Insurance)\n* Logistics & Supply Chain\n* Manufacturing\n* Hospitality\n* Telecommunications & IT\n* Facility Management\n* Aviation / Airport\n* Retail\n* Shipbuilding\n* Automobile\n* Drivers & Operators\n* Furniture & Interiors\n* Garments & Furnishing\n* Agriculture\n* Community Services\n* Education\n* Healthcare\n* Other\n\n---\n\nOUTPUT FORMAT (STRICT JSON ONLY):\n\n{\n\"lead_score\": 8,\n\"decision\": \"ACCEPT\",\n\"reason\": \"Active hospital in UAE hiring nurses for immediate deployment.\",\n\"industry\": \"Healthcare\",\n\"country\": \"United Arab Emirates\"\n}\n"
}
]
},
"builtInTools": {}
},
"credentials": {
"openAiApi": {
"name": "<your credential>"
}
},
"typeVersion": 2.1
},
{
"id": "b942d8f6-178f-49a7-bfae-37fa69c4520e",
"name": "Parse AI Lead Scores",
"type": "n8n-nodes-base.code",
"position": [
3520,
368
],
"parameters": {
"jsCode": "const job_d = $('Loop Over Job Batches').item.json;\nconst raw = $input.first().json;\n\n// \u00f0\u0178\u201d\u00a5 GET COMPANY FROM JOB DATA\nlet savedJob = {};\n// Company data comes from job_d\n\n// \u00f0\u0178\u201d\u00a5 PRIORITY LOGIC\n// 1. job_d.company_name\n// 2. fallback ''\nconst company_name = job_d?.company_name || '';\n\n// \u00f0\u0178\u201d\u00a5 PARSE AI RESPONSE\nlet parsed = {};\n\nif (raw?.output?.[0]?.content?.[0]?.text) {\n const text = raw.output[0].content[0].text;\n\n if (typeof text === 'object') {\n parsed = text;\n } else if (typeof text === 'string') {\n try {\n parsed = JSON.parse(text);\n } catch (e) {\n parsed = {};\n }\n }\n}\n\n// fallback\nif (!parsed || Object.keys(parsed).length === 0) {\n parsed = {\n lead_score: 0,\n decision: 'REJECT',\n reason: 'Parse error',\n industry: 'Other',\n country: 'Unknown'\n };\n}\n\n// \u00e2\u0153\u2026 FINAL OUTPUT\nreturn [{\n json: {\n ...job_d,\n\n // \u00f0\u0178\u201d\u00a5 FIXED COMPANY NAME\n company_name,\n\n // debug (remove later)\n company_source: job_d?.company_name ? 'job_data' : 'missing',\n\n lead_score: parsed.lead_score ?? 0,\n decision: parsed.decision ?? 'REJECT',\n reason: parsed.reason ?? '',\n industry: parsed.industry ?? 'Other',\n country: parsed.country ?? 'Unknown'\n }\n}];"
},
"typeVersion": 2
},
{
"id": "b2640e0a-e2ef-4da5-b5dd-e7558214ad22",
"name": "Check Lead Acceptance",
"type": "n8n-nodes-base.if",
"position": [
3728,
368
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "loose"
},
"combinator": "and",
"conditions": [
{
"id": "id-1",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.decision }}",
"rightValue": "ACCEPT"
}
]
},
"looseTypeValidation": true
},
"typeVersion": 2.3
},
{
"id": "6906f1c0-387a-46cf-9033-1f740a6b456d",
"name": "Set Job as Qualified",
"type": "n8n-nodes-base.set",
"position": [
3984,
304
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "id-1",
"name": "status",
"type": "string",
"value": "QUALIFIED"
},
{
"id": "id-2",
"name": "company_id",
"type": "string",
"value": "={{ ($json.company_name || '').toLowerCase().trim().replace(/\\s+/g, '_') }}"
}
]
},
"includeOtherFields": true
},
"typeVersion": 3.4
},
{
"id": "7e94057c-8d2d-49bc-9088-a599c4d899ae",
"name": "Append Qualified Job to Sheets",
"type": "n8n-nodes-base.googleSheets",
"position": [
4160,
304
],
"parameters": {
"columns": {
"value": {
"status": "={{ $json.status }}",
"country": "={{ $json.country }}",
"qualified": "={{ $json.decision }}",
"unique_id": "={{ $json.unique_id }}",
"company_id": "={{ $json.company_id }}",
"job_category": "={{ $json.industry }}",
"qualification_reason": "={{ $json.reason }}"
},
"schema": [
{
"id": "unique_id",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "unique_id",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "job_posted_date",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "job_posted_date",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "job_source",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "job_source",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "job_title",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "job_title",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "job_location",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "job_location",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "country",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "country",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "job_description",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "job_description",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "job_type",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "job_type",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "job_url",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "job_url",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "company_name",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "company_name",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "company_id",
"type": "string",
"display": true,
"required": false,
"displayName": "company_id",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "job_category",
"type": "string",
"display": true,
"required": false,
"displayName": "job_category",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "qualified",
"type": "string",
"display": true,
"required": false,
"displayName": "qualified",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "qualification_reason",
"type": "string",
"display": true,
"required": false,
"displayName": "qualification_reason",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "status",
"type": "string",
"display": true,
"required": false,
"displayName": "status",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "original_json",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "original_json",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "created_at",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "created_at",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [
"unique_id"
],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "appendOrUpdate",
"sheetName": {
"__rl": true,
"mode": "id",
"value": "1726393267"
},
"documentId": {
"__rl": true,
"mode": "id",
"value": "1hex1u1cpI5sMx8I45ktgpZ4VhXReQA4EZdoCTVEc1bI"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.7
},
{
"id": "7c9f0806-b406-4fbc-96d8-3464a5fc2f45",
"name": "Cycle Job Processing",
"type": "n8n-nodes-base.noOp",
"position": [
4336,
528
],
"parameters": {},
"typeVersion": 1
},
{
"id": "485a21f5-1f73-4f82-ac54-f051f0f30506",
"name": "Submit Job Scrape Request",
"type": "n8n-nodes-base.httpRequest",
"position": [
1296,
448
],
"parameters": {
"url": "https://api.apify.com/v2/acts/agentx~all-jobs-scraper/run-sync-get-dataset-items",
"method": "POST",
"options": {
"timeout": 300000
},
"jsonBody": "={\n \"keyword\": \"{{ $json.job_role }}\",\n \"country\": \"{{ $json.location }}\",\n \"max_results\": {{ $json.max_results }},\n \"posted_since\": \"{{ $json.posted_since }}\"\n}",
"sendBody": true,
"specifyBody": "json",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth"
},
"credentials": {},
"typeVersion": 4.2
},
{
"id": "66197d6c-a845-4379-b589-41a449b52887",
"name": "Detect Missing Company Names",
"type": "@mendable/n8n-nodes-firecrawl.firecrawl",
"position": [
2816,
208
],
"parameters": {
"url": "={{ $json.job_url }}",
"operation": "scrape",
"scrapeOptions": {
"options": {
"formats": {
"format": [
{
"type": "json"
}
]
},
"headers": {}
}
},
"requestOptions": {}
},
"credentials": {},
"typeVersion": 1
},
{
"id": "d0471948-3460-4358-9497-23e59d3e8ecb",
"name": "Check Company Name Presence",
"type": "n8n-nodes-base.if",
"position": [
2592,
352
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "loose"
},
"combinator": "and",
"conditions": [
{
"id": "d1193fa9-2103-4e14-9088-e05e2a3f0363",
"operator": {
"type": "string",
"operation": "empty",
"singleValue": true
},
"leftValue": "=[undefined]",
"rightValue": ""
}
]
},
"looseTypeValidation": true
},
"typeVersion": 2.3
},
{
"id": "0890e82f-036e-4a0e-82a3-11c78793dd6b",
"name": "Append Jobs with Company Names",
"type": "n8n-nodes-base.googleSheets",
"position": [
2992,
208
],
"parameters": {
"columns": {
"value": {
"unique_id": "={{ $('Check for Company Name').item.json.unique_id }}",
"company_name": "={{ $json.data.metadata.ogDescription }}"
},
"schema": [
{
"id": "unique_id",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "unique_id",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "job_posted_date",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "job_posted_date",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "job_source",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "job_source",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "job_title",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "job_title",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "job_location",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "job_location",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "country",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "country",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "job_description",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "job_description",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "job_type",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "job_type",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "job_url",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "job_url",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "company_name",
"type": "string",
"display": true,
"required": false,
"displayName": "company_name",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "company_id",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "company_id",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "job_category",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "job_category",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "qualified",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "qualified",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "qualification_reason",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "qualification_reason",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "status",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "status",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "original_json",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "original_json",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "created_at",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "created_at",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [
"unique_id"
],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {
"useAppend": true
},
"operation": "appendOrUpdate",
"sheetName": {
"__rl": true,
"mode": "id",
"value": "1726393267"
},
"documentId": {
"__rl": true,
"mode": "id",
"value": "1hex1u1cpI5sMx8I45ktgpZ4VhXReQA4EZdoCTVEc1bI"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.7
},
{
"id": "3fec290e-1367-4ce5-b0cd-7ca29eb2f2dc",
"name": "Save Qualified Job to Sheets",
"type": "n8n-nodes-base.googleSheets",
"position": [
4064,
528
],
"parameters": {
"columns": {
"value": {
"status": "=NOT_QUALIFIED",
"country": "={{ $json.country }}",
"qualified": "={{ $json.decision }}",
"unique_id": "={{ $json.unique_id }}",
"job_category": "={{ $json.industry }}",
"qualification_reason": "={{ $json.reason }}"
},
"schema": [
{
"id": "unique_id",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "unique_id",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "job_posted_date",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "job_posted_date",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "job_source",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "job_source",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "job_title",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "job_title",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "job_location",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "job_location",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "country",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "country",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "job_description",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "job_description",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "job_type",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "job_type",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "job_url",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "job_url",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "company_name",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "company_name",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "company_id",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "company_id",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "job_category",
"type": "string",
"display": true,
"required": false,
"displayName": "job_category",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "qualified",
"type": "string",
"display": true,
"required": false,
"displayName": "qualified",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "qualification_reason",
"type": "string",
"display": true,
"required": false,
"displayName": "qualification_reason",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "status",
"type": "string",
"display": true,
"required": false,
"displayName": "status",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "original_json",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "original_json",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "created_at",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "created_at",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [
"unique_id"
],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "appendOrUpdate",
"sheetName": {
"__rl": true,
"mode": "id",
"value": "1726393267"
},
"documentId": {
"__rl": true,
"mode": "id",
"value": "1hex1u1cpI5sMx8I45ktgpZ4VhXReQA4EZdoCTVEc1bI"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.7
}
],
"connections": {
"AI Job Scoring Agent": {
"main": [
[
{
"node": "Parse AI Lead Scores",
"type": "main",
"index": 0
}
]
]
},
"Cycle Job Processing": {
"main": [
[
{
"node": "Loop Over Job Batches",
"type": "main",
"index": 0
}
]
]
},
"Parse AI Lead Scores": {
"main": [
[
{
"node": "Check Lead Acceptance",
"type": "main",
"index": 0
}
]
]
},
"Set Job as Qualified": {
"main": [
[
{
"node": "Append Qualified Job to Sheets",
"type": "main",
"index": 0
}
]
]
},
"Check Lead Acceptance": {
"main": [
[
{
"node": "Set Job as Qualified",
"type": "main",
"index": 0
}
],
[
{
"node": "Save Qualified Job to Sheets",
"type": "main",
"index": 0
}
]
]
},
"Loop Over Job Batches": {
"main": [
[
{
"node": "Loop Over Search Batches",
"type": "main",
"index": 0
}
],
[
{
"node": "Check Company Name Presence",
"type": "main",
"index": 0
}
]
]
},
"Read Jobs from Sheets": {
"main": [
[
{
"node": "Identify Duplicate Jobs",
"type": "main",
"index": 0
}
]
]
},
"Identify Duplicate Jobs": {
"main": [
[
{
"node": "Append Raw Jobs to Sheets",
"type": "main",
"index": 0
}
]
]
},
"Parse Form Input Arrays": {
"main": [
[
{
"node": "Loop Over Search Batches",
"type": "main",
"index": 0
}
]
]
},
"When Job Form Submitted": {
"main": [
[
{
"node": "Parse Form Input Arrays",
"type": "main",
"index": 0
}
]
]
},
"Loop Over Search Batches": {
"main": [
[],
[
{
"node": "Submit Job Scrape Request",
"type": "main",
"index": 0
}
]
]
},
"Append Raw Jobs to Sheets": {
"main": [
[
{
"node": "Loop Over Job Batches",
"type": "main",
"index": 0
}
]
]
},
"Submit Job Scrape Request": {
"main": [
[
{
"node": "Flatten Job Results and ID",
"type": "main",
"index": 0
}
]
]
},
"Flatten Job Results and ID": {
"main": [
[
{
"node": "Read Jobs from Sheets",
"type": "main",
"index": 0
}
]
]
},
"Check Company Name Presence": {
"main": [
[
{
"node": "Detect Missing Company Names",
"type": "main",
"index": 0
}
],
[
{
"node": "AI Job Scoring Agent",
"type": "main",
"index": 0
}
]
]
},
"Detect Missing Company Names": {
"main": [
[
{
"node": "Append Jobs with Company Names",
"type": "main",
"index": 0
}
]
]
},
"Save Qualified Job to Sheets": {
"main": [
[
{
"node": "Cycle Job Processing",
"type": "main",
"index": 0
}
]
]
},
"Append Jobs with Company Names": {
"main": [
[
{
"node": "AI Job Scoring Agent",
"type": "main",
"index": 0
}
]
]
},
"Append Qualified Job to Sheets": {
"main": [
[
{
"node": "Cycle Job Processing",
"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.
googleSheetsOAuth2ApiopenAiApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This n8n template helps recruitment agencies discover active job openings, filter them based on hiring relevance, and qualify them using AI — specifically designed for semi-skilled manpower hiring use cases. Job lead discovery using Apify scraping Hash-based deduplication to…
Source: https://n8n.io/workflows/14859/ — 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 workflow is Part 2 of the HR Client Acquisition system and builds on the lead discovery pipeline from the previous workflow:
Product - SERP Analysis (Serper + Firecrawl). Uses formTrigger, httpRequest, googleSheets, openAi. Event-driven trigger; 40 nodes.
Product - SERP Analysis (Serper & Crawl4AI). Uses formTrigger, httpRequest, googleSheets, openAi. Event-driven trigger; 39 nodes.
Product - SERP Analysis (SerpAPI + Crawl4AI). Uses formTrigger, httpRequest, googleSheets, openAi. Event-driven trigger; 38 nodes.
This n8n template automates website analysis and ecommerce URL classification using AI. It scrapes a website, extracts business intelligence, maps all internal pages, and categorises them into product