{
  "id": "O4m0fA6PJq3Qwm6e",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Job Search and Categorization",
  "tags": [],
  "nodes": [
    {
      "id": "4e86262f-bbf8-45cd-bae6-ca5cb910d41d",
      "name": "Form Trigger",
      "type": "n8n-nodes-base.formTrigger",
      "position": [
        9696,
        9888
      ],
      "parameters": {
        "options": {},
        "formTitle": "Job Search",
        "formFields": {
          "values": [
            {
              "fieldLabel": "Job Role",
              "placeholder": "e.g. Frontend Developer",
              "requiredField": true
            },
            {
              "fieldLabel": "Tech Stack",
              "placeholder": "e.g. React, Node.js, TypeScript",
              "requiredField": true
            },
            {
              "fieldType": "dropdown",
              "fieldLabel": "Country",
              "fieldOptions": {
                "values": [
                  {
                    "option": "India"
                  },
                  {
                    "option": "United States"
                  },
                  {
                    "option": "United Kingdom"
                  },
                  {
                    "option": "Germany"
                  },
                  {
                    "option": "Canada"
                  },
                  {
                    "option": "Australia"
                  },
                  {
                    "option": "Netherlands"
                  },
                  {
                    "option": "Singapore"
                  },
                  {
                    "option": "UAE"
                  },
                  {
                    "option": "Remote / Anywhere"
                  }
                ]
              },
              "requiredField": true
            }
          ]
        },
        "formDescription": "Enter your job preferences to search across multiple job boards"
      },
      "typeVersion": 2.2
    },
    {
      "id": "f9a05be5-e694-4154-b3c4-a26f2e893ea3",
      "name": "Store Form Input",
      "type": "n8n-nodes-base.code",
      "position": [
        9888,
        9888
      ],
      "parameters": {
        "jsCode": "// Store form input for downstream nodes\nconst formData = $input.first().json;\nreturn [{ json: { _jobRole: formData['Job Role'] || '', _techStack: formData['Tech Stack'] || '', _country: formData['Country'] || '' } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "9e218d61-ddad-45a7-a674-168d898b1e9c",
      "name": "Scrape Remotive",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        10144,
        9584
      ],
      "parameters": {
        "url": "=https://remotive.com/api/remote-jobs?search={{ $json._jobRole }}&limit=25",
        "options": {
          "response": {
            "response": {
              "neverError": true
            }
          }
        }
      },
      "typeVersion": 4
    },
    {
      "id": "6d1ac6f0-81d6-4b94-b94f-65daf25aebec",
      "name": "Scrape Arbeitnow",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        10144,
        9792
      ],
      "parameters": {
        "url": "=https://www.arbeitnow.com/api/job-board-api?search={{ $json._jobRole }}",
        "options": {
          "response": {
            "response": {
              "neverError": true
            }
          }
        }
      },
      "typeVersion": 4
    },
    {
      "id": "dd6db0f8-bdc0-4bb9-9519-6b05e6573fa1",
      "name": "Scrape Jobicy",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        10144,
        9984
      ],
      "parameters": {
        "url": "=https://jobicy.com/api/v2/remote-jobs?tag={{ $json._jobRole }}",
        "options": {
          "response": {
            "response": {
              "neverError": true
            }
          }
        }
      },
      "typeVersion": 4
    },
    {
      "id": "e0b2d890-209c-4627-8fc8-52eb6a883a67",
      "name": "Apify LinkedIn Jobs",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        10048,
        10368
      ],
      "parameters": {
        "url": "https://api.apify.com/v2/acts/hMvNSpz3JnHgl5jkh/run-sync-get-dataset-items?token=<your api key>&timeout=120",
        "method": "POST",
        "options": {
          "response": {
            "response": {
              "neverError": true
            }
          }
        },
        "jsonBody": "={{ JSON.stringify({ title: $json._jobRole, location: $json._country, maxItems: 30, publishedAt: 'r86400', sort: 'date' }) }}",
        "sendBody": true,
        "specifyBody": "json"
      },
      "typeVersion": 4
    },
    {
      "id": "27b89ea9-18bb-40a6-81f8-40d653090201",
      "name": "Apify Naukri Jobs",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        9792,
        10368
      ],
      "parameters": {
        "url": "https://api.apify.com/v2/acts/codemaverick~naukri-job-scraper-latest/run-sync-get-dataset-items?token=<your api key>&timeout=120",
        "method": "POST",
        "options": {
          "response": {
            "response": {
              "neverError": true
            }
          }
        },
        "jsonBody": "={{ JSON.stringify({ searchQuery: $json._jobRole, maxItems: 30 }) }}",
        "sendBody": true,
        "specifyBody": "json"
      },
      "typeVersion": 4
    },
    {
      "id": "3c9db3ed-b043-4545-a4cb-2ca69c078538",
      "name": "Merge Free APIs",
      "type": "n8n-nodes-base.merge",
      "position": [
        10384,
        9680
      ],
      "parameters": {},
      "typeVersion": 3
    },
    {
      "id": "45b9e7df-f97b-4875-a4c8-0299d236b3f7",
      "name": "Merge Free + Jobicy",
      "type": "n8n-nodes-base.merge",
      "position": [
        10592,
        9840
      ],
      "parameters": {},
      "typeVersion": 3
    },
    {
      "id": "d4ce9352-42f7-4ab8-ba2b-cff479415dba",
      "name": "Merge + LinkedIn",
      "type": "n8n-nodes-base.merge",
      "position": [
        10784,
        9984
      ],
      "parameters": {},
      "typeVersion": 3
    },
    {
      "id": "16a844a5-2784-4311-b06a-224caf84a9c2",
      "name": "Merge All",
      "type": "n8n-nodes-base.merge",
      "position": [
        10992,
        10080
      ],
      "parameters": {},
      "typeVersion": 3
    },
    {
      "id": "ca754bde-5cc7-4354-8804-58ff8d72a526",
      "name": "Normalize Score and Sort",
      "type": "n8n-nodes-base.code",
      "position": [
        11184,
        9888
      ],
      "parameters": {
        "jsCode": "const items = $input.all();\n\n// Extract stored form data from the first item that has it\nlet jobRole = '';\nlet techStack = '';\nlet country = '';\nfor (const item of items) {\n  if (item.json._jobRole) { jobRole = item.json._jobRole; techStack = item.json._techStack || ''; country = item.json._country || ''; break; }\n}\n\nfunction clean(html) {\n  return (html || '').replace(/<[^>]*>/g, '').replace(/&amp;/g, '&').replace(/&lt;/g, '<').replace(/&gt;/g, '>').replace(/&quot;/g, '\"').replace(/&#39;/g, \"'\").replace(/\\s+/g, ' ').trim();\n}\n\nfunction extractSalary(desc, data) {\n  if (data.salary) return String(data.salary);\n  if (data.salaryMin || data.salaryMax) {\n    const parts = [];\n    if (data.salaryCurrency) parts.push(data.salaryCurrency);\n    if (data.salaryMin) parts.push(Number(data.salaryMin).toLocaleString());\n    if (data.salaryMax) parts.push('- ' + Number(data.salaryMax).toLocaleString());\n    if (data.salaryPeriod) parts.push(data.salaryPeriod);\n    return parts.join(' ');\n  }\n  const m = desc.match(/[\\$\\\u00a3\\\u20ac\\\u20b9]\\s?[\\d,]+(?:\\s?[-\u2013]\\s?[\\$\\\u00a3\\\u20ac\\\u20b9]?\\s?[\\d,]+)?(?:\\s?(?:k|K|LPA|lpa|pa|p\\.a\\.|per year|per annum|yearly|annually))?/);\n  if (m) return m[0].trim();\n  return 'Not mentioned';\n}\n\nfunction extractVisa(desc) {\n  const lower = desc.toLowerCase();\n  if (lower.includes('visa sponsor') || lower.includes('visa support') || lower.includes('we sponsor') || lower.includes('sponsorship available') || lower.includes('will sponsor')) return 'Yes';\n  if (lower.includes('no visa') || lower.includes('no sponsorship') || lower.includes('must be authorized') || lower.includes('must be eligible') || lower.includes('right to work') || lower.includes('authorized to work') || lower.includes('work permit required')) return 'No';\n  return 'Not mentioned';\n}\n\nfunction extractCompanyInfo(desc) {\n  const patterns = [/about\\s+(?:us|the\\s+company|our\\s+company)[:\\s]*([^.]+\\.)/i, /(?:we\\s+are|we're)\\s+(?:a|an)\\s+([^.]+\\.)/i];\n  for (const p of patterns) {\n    const m = desc.match(p);\n    if (m && m[1] && m[1].length > 20) return m[1].trim().substring(0, 200);\n  }\n  const fundingMatch = desc.match(/(?:raised|funding|series\\s+[a-e]|seed\\s+round|venture|backed\\s+by)[^.]+\\./i);\n  if (fundingMatch) return fundingMatch[0].trim().substring(0, 200);\n  return '';\n}\n\nfunction extractCompanySize(desc) {\n  const empMatch = desc.match(/(\\d[\\d,]*)\\+?\\s*(?:employees|team members|people|staff)/i);\n  if (empMatch) {\n    const num = parseInt(empMatch[1].replace(/,/g, ''));\n    if (num < 50) return 'Startup (<50)';\n    if (num < 200) return 'Small (50-200)';\n    if (num < 1000) return 'Medium (200-1K)';\n    if (num < 5000) return 'Large (1K-5K)';\n    return 'Enterprise (5K+)';\n  }\n  const lower = desc.toLowerCase();\n  if (lower.includes('startup') || lower.includes('early stage')) return 'Startup';\n  if (lower.includes('fortune 500') || lower.includes('multinational')) return 'Enterprise (5K+)';\n  return '';\n}\n\n// Category rules based on keywords\nfunction categorize(title, desc) {\n  const t = (title + ' ' + desc).toLowerCase();\n  if (t.includes('frontend') || t.includes('front-end') || t.includes('front end') || t.includes('react') || t.includes('angular') || t.includes('vue')) return 'Frontend';\n  if (t.includes('backend') || t.includes('back-end') || t.includes('back end') || t.includes('django') || t.includes('spring') || t.includes('express') || t.includes('fastapi')) return 'Backend';\n  if (t.includes('fullstack') || t.includes('full-stack') || t.includes('full stack')) return 'Fullstack';\n  if (t.includes('devops') || t.includes('sre') || t.includes('infrastructure') || t.includes('kubernetes') || t.includes('terraform') || t.includes('ci/cd') || t.includes('platform engineer')) return 'DevOps';\n  if (t.includes('data scientist') || t.includes('data engineer') || t.includes('data analyst') || t.includes('machine learning') || t.includes('ml engineer') || t.includes('ai ') || t.includes('analytics')) return 'Data';\n  if (t.includes('mobile') || t.includes('ios') || t.includes('android') || t.includes('flutter') || t.includes('react native') || t.includes('swift') || t.includes('kotlin')) return 'Mobile';\n  if (t.includes('design') || t.includes('ux') || t.includes('ui ') || t.includes('figma') || t.includes('product design')) return 'Design';\n  if (t.includes('qa') || t.includes('quality') || t.includes('test') || t.includes('sdet') || t.includes('automation test')) return 'QA';\n  if (t.includes('product manager') || t.includes('program manager') || t.includes('project manager') || t.includes('scrum') || t.includes('agile lead')) return 'PM';\n  if (t.includes('marketing') || t.includes('seo') || t.includes('growth') || t.includes('content')) return 'Marketing';\n  if (t.includes('sales') || t.includes('business development') || t.includes('account exec')) return 'Sales';\n  if (t.includes('security') || t.includes('cybersec') || t.includes('infosec') || t.includes('penetration')) return 'Security';\n  if (t.includes('cloud') || t.includes('aws') || t.includes('azure') || t.includes('gcp')) return 'Cloud';\n  return 'Other';\n}\n\n// Synonym map - expand role to include similar titles\nconst SYNONYMS = {\n  'engineer': ['developer', 'programmer', 'coder', 'dev', 'sde', 'swe'],\n  'developer': ['engineer', 'programmer', 'coder', 'dev', 'sde', 'swe'],\n  'programmer': ['developer', 'engineer', 'coder', 'dev'],\n  'software': ['web', 'application', 'app', 'platform'],\n  'frontend': ['front-end', 'front end', 'ui', 'react', 'angular', 'vue', 'client-side'],\n  'backend': ['back-end', 'back end', 'server', 'api', 'server-side'],\n  'fullstack': ['full-stack', 'full stack', 'frontend', 'backend'],\n  'devops': ['sre', 'infrastructure', 'platform', 'cloud', 'reliability'],\n  'data': ['analytics', 'bi', 'machine learning', 'ml', 'ai'],\n  'mobile': ['ios', 'android', 'flutter', 'react native', 'app'],\n  'qa': ['test', 'quality', 'sdet', 'automation'],\n  'test': ['qa', 'quality', 'sdet', 'automation'],\n  'design': ['ux', 'ui', 'figma', 'product design', 'graphic'],\n  'manager': ['lead', 'head', 'director', 'principal', 'senior'],\n  'lead': ['manager', 'head', 'principal', 'senior', 'staff'],\n  'senior': ['sr', 'lead', 'principal', 'staff', 'experienced'],\n  'junior': ['jr', 'entry', 'associate', 'trainee', 'intern', 'fresher'],\n  'architect': ['principal', 'staff', 'lead engineer', 'technical lead'],\n  'analyst': ['associate', 'consultant', 'specialist'],\n  'consultant': ['analyst', 'advisor', 'specialist'],\n  'security': ['cybersecurity', 'infosec', 'appsec', 'penetration'],\n  'cloud': ['aws', 'azure', 'gcp', 'infrastructure', 'devops'],\n  'product': ['pm', 'program', 'project'],\n  'marketing': ['growth', 'seo', 'content', 'digital'],\n  'sales': ['business development', 'account', 'revenue']\n};\n\nfunction expandRole(role) {\n  const words = role.toLowerCase().split(/[\\s,\\/]+/).filter(w => w.length > 1);\n  const expanded = new Set(words);\n  for (const w of words) {\n    if (SYNONYMS[w]) {\n      SYNONYMS[w].forEach(s => expanded.add(s));\n    }\n  }\n  return [...expanded];\n}\n\n// Relevance scoring with synonym expansion\nfunction scoreJob(title, desc, role, stack) {\n  let score = 0;\n  const titleLower = title.toLowerCase();\n  const descLower = desc.toLowerCase();\n  const expandedRole = expandRole(role);\n  const stackWords = stack.toLowerCase().split(/[\\s,\\/]+/).filter(w => w.length > 1);\n\n  // Title matches (highest weight)\n  for (const w of expandedRole) {\n    if (titleLower.includes(w)) score += 25;\n  }\n  for (const w of stackWords) {\n    if (titleLower.includes(w)) score += 20;\n  }\n\n  // Description matches\n  for (const w of expandedRole) {\n    if (descLower.includes(w)) score += 8;\n  }\n  for (const w of stackWords) {\n    if (descLower.includes(w)) score += 12;\n  }\n\n  // Normalize to 0-100\n  const maxPossible = (expandedRole.length * 33) + (stackWords.length * 32);\n  return maxPossible > 0 ? Math.min(100, Math.round((score / maxPossible) * 100)) : 50;\n}\n\nconst normalized = items.map(item => {\n  const d = item.json;\n  if (d._jobRole || d.error || d.statusCode >= 400 || (typeof d === 'string')) return [];\n\n  // Remotive\n  if (d.jobs && !Array.isArray(d.data) && !d.jobTitle && !d.companyName) {\n    return d.jobs.map(j => {\n      const desc = clean(j.description || '');\n      return { json: {\n        title: j.title || '', company: j.company_name || '', link: j.url || '',\n        description: desc.substring(0, 800), posted_date: j.publication_date || '',\n        source: 'Remotive', location: j.candidate_required_location || 'Remote',\n        salary: extractSalary(desc, j), job_type: (j.job_type || '').replace(/_/g, ' ') || 'Not mentioned',\n        visa_sponsored: extractVisa(desc), company_size: extractCompanySize(desc), company_info: extractCompanyInfo(desc)\n      }};\n    });\n  }\n\n  // Arbeitnow\n  if (d.data && Array.isArray(d.data)) {\n    return d.data.map(j => {\n      const desc = clean(j.description || '');\n      return { json: {\n        title: j.title || '', company: j.company_name || '', link: j.url || '',\n        description: desc.substring(0, 800), posted_date: j.created_at || '',\n        source: 'Arbeitnow', location: j.location || (j.remote ? 'Remote' : 'Not mentioned'),\n        salary: extractSalary(desc, j), job_type: j.remote ? 'Remote' : 'On-site',\n        visa_sponsored: extractVisa(desc), company_size: extractCompanySize(desc), company_info: extractCompanyInfo(desc)\n      }};\n    });\n  }\n\n  // Jobicy\n  if (d.jobs && Array.isArray(d.jobs) && d.jobs[0] && d.jobs[0].jobTitle) {\n    return d.jobs.map(j => {\n      const desc = clean(j.jobDescription || '');\n      return { json: {\n        title: j.jobTitle || '', company: j.companyName || '', link: j.url || '',\n        description: desc.substring(0, 800), posted_date: j.pubDate || '',\n        source: 'Jobicy', location: j.jobGeo || 'Remote',\n        salary: extractSalary(desc, j), job_type: (Array.isArray(j.jobType) ? j.jobType.join(', ') : j.jobType) || 'Not mentioned',\n        visa_sponsored: extractVisa(desc), company_size: extractCompanySize(desc), company_info: extractCompanyInfo(desc)\n      }};\n    });\n  }\n\n  // LinkedIn (positionName)\n  if (d.positionName || (d.title && d.companyName && d.link)) {\n    const desc = clean(d.descriptionText || d.description || '');\n    return [{ json: {\n      title: d.positionName || d.title || '', company: d.companyName || d.company || '',\n      link: d.link || d.applyUrl || d.url || '',\n      description: desc.substring(0, 800), posted_date: d.postedAt || d.publishedAt || d.postedTime || '',\n      source: 'LinkedIn', location: d.location || d.formattedLocation || 'Not mentioned',\n      salary: d.salary || extractSalary(desc, d), job_type: d.contractType || d.employmentType || d.workType || 'Not mentioned',\n      visa_sponsored: extractVisa(desc), company_size: d.companySize || extractCompanySize(desc),\n      company_info: d.companyDescription ? clean(d.companyDescription).substring(0, 200) : extractCompanyInfo(desc)\n    }}];\n  }\n\n  // Naukri (Job Title)\n  if (d.jobId || d['Job Title'] || (d.title && d.jdURL)) {\n    const desc = clean(d.Description || d.description || d.jobDescription || d['Job Description'] || '');\n    return [{ json: {\n      title: d['Job Title'] || d.title || d.designation || '',\n      company: d.Company || d['Company Name'] || d.companyName || d.company || '',\n      link: d['Job URL'] || d.jdURL || d.url || '', description: desc.substring(0, 800),\n      posted_date: d['Posted Time'] || d.createdDate || d.postedDate || d['Posted Date'] || '',\n      source: 'Naukri',\n      location: d['Location'] || d.placeholders?.find(p => p.type === 'location')?.label || d.location || 'Not mentioned',\n      salary: d['Salary'] || d.placeholders?.find(p => p.type === 'salary')?.label || d.salary || extractSalary(desc, d),\n      job_type: d['Experience'] || d.placeholders?.find(p => p.type === 'experience')?.label || 'Not mentioned',\n      visa_sponsored: extractVisa(desc),\n      company_size: d.ambitionBoxData?.CompanySize || d['Company Size'] || extractCompanySize(desc),\n      company_info: d.ambitionBoxData?.About ? clean(d.ambitionBoxData.About).substring(0, 200) : extractCompanyInfo(desc)\n    }}];\n  }\n\n  // Fallback\n  const desc = clean(d.description || d.jobDescription || '');\n  if (!d.title && !d.jobTitle && !d.positionName) return [];\n  return [{ json: {\n    title: d.title || d.jobTitle || d.positionName || '',\n    company: d.company || d.company_name || d.companyName || '',\n    link: d.url || d.link || '', description: desc.substring(0, 800),\n    posted_date: d.publication_date || d.created_at || d.pubDate || d.postedAt || '',\n    source: 'Other', location: d.candidate_required_location || d.location || d.jobGeo || 'Not mentioned',\n    salary: extractSalary(desc, d), job_type: d.job_type || d.jobType || 'Not mentioned',\n    visa_sponsored: extractVisa(desc), company_size: extractCompanySize(desc), company_info: extractCompanyInfo(desc)\n  }}];\n});\n\n// Flatten, score, categorize, filter, sort\nconst flat = normalized.flat().filter(i => i.json && i.json.title);\nconst scored = flat.map(item => {\n  const j = item.json;\n  const relevance = scoreJob(j.title, j.description, jobRole, techStack);\n  const category = categorize(j.title, j.description);\n  return { json: { ...j, relevance: relevance + '%', category } };\n});\n\n// Filter: must have at least 1 expanded role keyword in title or description\nconst expandedRoleWords = expandRole(jobRole);\nconst filtered = scored.filter(item => {\n  const rel = parseInt(item.json.relevance);\n  if (rel >= 10) return true;\n  const titleLower = item.json.title.toLowerCase();\n  const descLower = (item.json.description || '').toLowerCase();\n  return expandedRoleWords.some(w => titleLower.includes(w) || descLower.includes(w));\n});\n\n// Sort by relevance (highest first), then by date\nfiltered.sort((a, b) => {\n  const ra = parseInt(a.json.relevance);\n  const rb = parseInt(b.json.relevance);\n  if (rb !== ra) return rb - ra;\n  return new Date(b.json.posted_date || 0) - new Date(a.json.posted_date || 0);\n});\n\nreturn filtered;"
      },
      "typeVersion": 2
    },
    {
      "id": "5586ed3e-4466-4873-9d3f-3a74a9f082fb",
      "name": "Google Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        11696,
        9888
      ],
      "parameters": {
        "columns": {
          "value": {
            "Link": "={{ $json.link }}",
            "Salary": "={{ $json.salary }}",
            "Source": "={{ $json.source }}",
            "Company": "={{ $json.company }}",
            "Category": "={{ $json.category }}",
            "Job Type": "={{ $json.job_type }}",
            "Location": "={{ $json.location }}",
            "Job Title": "={{ $json.title }}",
            "Relevance": "={{ $json.relevance }}",
            "Date Posted": "={{ $json.posted_date }}",
            "Company Size": "={{ $json.company_size }}",
            "Visa Sponsored": "={{ $json.visa_sponsored }}",
            "Company Info / Funding": "={{ $json.company_info }}"
          },
          "mappingMode": "defineBelow"
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "YOUR_SHEET_ID_HERE"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4
    },
    {
      "id": "bc6daee0-891e-48da-af5d-e45d5f8721d1",
      "name": "Sticky Note: Trigger",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        9600,
        9648
      ],
      "parameters": {
        "color": 3,
        "width": 432,
        "height": 424,
        "content": "### User Inputs & Trigger\n- **Form Trigger**: Collects user job search preferences:\n  1. **Job Role** (e.g. *Software Engineer*)\n  2. **Tech Stack** (e.g. *React, Node.js*)\n  3. **Country** (Dropdown selection)\n- **Store Form Input**: Saves these values to variables (`_jobRole`, `_techStack`, `_country`) for downstream APIs."
      },
      "typeVersion": 1
    },
    {
      "id": "7a1fc04d-f93c-49a5-8f05-3298960746fe",
      "name": "Sticky Note: Scrapers",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        10064,
        9360
      ],
      "parameters": {
        "color": 2,
        "width": 268,
        "height": 1176,
        "content": "### Parallel Job Scrapers\nFetches job listings from 5 sources:\n- **Remotive** (Free API, Remote)\n- **Arbeitnow** (Free API, Germany/Europe)\n- **Jobicy** (Free API, Remote Focus)\n- **Apify LinkedIn** (Paid Scraper, Country-specific)\n- **Apify Naukri** (Paid Scraper, India/Global)"
      },
      "typeVersion": 1
    },
    {
      "id": "6e27df1e-cd80-44b4-b489-cbd77e4d36df",
      "name": "Sticky Note: Merge",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        10368,
        9552
      ],
      "parameters": {
        "color": 7,
        "width": 736,
        "height": 678,
        "content": "### Data Consolidation (Merge Chain)\n- Sequentially appends arrays from all 5 scraper nodes.\n- Ensures all job listings are merged into a single downstream stream before normalization and scoring."
      },
      "typeVersion": 1
    },
    {
      "id": "ad6f0ee0-626d-4109-b96c-3e66b81a8035",
      "name": "Sticky Note: Scoring",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        11104,
        9664
      ],
      "parameters": {
        "color": 4,
        "width": 384,
        "height": 362,
        "content": "### Normalize, Score & Sort\nRuns custom JavaScript to:\n- **Normalize**: Parse fields like salary, visa support, company size across all API schemas.\n- **Score Relevance**: Rank matching based on user-requested role and tech stack (using synonym expansion).\n- **Filter**: Drop highly irrelevant jobs.\n- **Sort**: Order by highest relevance and post date."
      },
      "typeVersion": 1
    },
    {
      "id": "a6235494-8420-4a7b-8046-d09e71bbb0da",
      "name": "Sticky Note: Sheets",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        11584,
        9696
      ],
      "parameters": {
        "color": 2,
        "width": 280,
        "height": 344,
        "content": "### Google Sheets Output\n- Enter your Google Sheet ID .\n\nhttps://docs.google.com/spreadsheets/d/<your google sheet ID>/edit?gid=0#gid=0"
      },
      "typeVersion": 1
    },
    {
      "id": "f8af41f0-ee2e-4086-b15b-975f0eed96d0",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        9008,
        9472
      ],
      "parameters": {
        "width": 400,
        "height": 384,
        "content": "## Pre requisites\n\nThis is a simple way to get job details for the job listings directly in your spreadsheet\n\n- go to Apify and create a free account .\n-  link - https://console.apify.com/\n- to get your api key go to - https://console.apify.com/settings/integrations\n\n- approve the naukri actor to work using this link-https://console.apify.com/actors/GLb4E7UrStD7XLJxO?approvePermissions=true\n"
      },
      "typeVersion": 1
    },
    {
      "id": "e3cb9f0f-c4d6-47fa-940d-346169b2632d",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        9600,
        10128
      ],
      "parameters": {
        "color": 4,
        "width": 688,
        "height": 400,
        "content": "## Configure this two nodes\n\n- replace the URL to link -\n\nlinkedin -  https://api.apify.com/v2/acts/hMvNSpz3JnHgl5jkh/run-sync-get-dataset-items?token=<Your API key>&timeout=120\n\nnaukri - https://api.apify.com/v2/acts/codemaverick~naukri-job-scraper-latest/run-sync-get-dataset-items?token=<your API key>&timeout=120"
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "executionOrder": "v1"
  },
  "versionId": "244e3b51-0b2b-4c67-8646-79fd2006e460",
  "connections": {
    "Merge All": {
      "main": [
        [
          {
            "node": "Normalize Score and Sort",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Form Trigger": {
      "main": [
        [
          {
            "node": "Store Form Input",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Scrape Jobicy": {
      "main": [
        [
          {
            "node": "Merge Free + Jobicy",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Merge Free APIs": {
      "main": [
        [
          {
            "node": "Merge Free + Jobicy",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Scrape Remotive": {
      "main": [
        [
          {
            "node": "Merge Free APIs",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge + LinkedIn": {
      "main": [
        [
          {
            "node": "Merge All",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Scrape Arbeitnow": {
      "main": [
        [
          {
            "node": "Merge Free APIs",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Store Form Input": {
      "main": [
        [
          {
            "node": "Scrape Remotive",
            "type": "main",
            "index": 0
          },
          {
            "node": "Scrape Arbeitnow",
            "type": "main",
            "index": 0
          },
          {
            "node": "Scrape Jobicy",
            "type": "main",
            "index": 0
          },
          {
            "node": "Apify LinkedIn Jobs",
            "type": "main",
            "index": 0
          },
          {
            "node": "Apify Naukri Jobs",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Apify Naukri Jobs": {
      "main": [
        [
          {
            "node": "Merge All",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Apify LinkedIn Jobs": {
      "main": [
        [
          {
            "node": "Merge + LinkedIn",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Merge Free + Jobicy": {
      "main": [
        [
          {
            "node": "Merge + LinkedIn",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Normalize Score and Sort": {
      "main": [
        [
          {
            "node": "Google Sheets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}