AutomationFlowsWeb Scraping › Main Orchestrator

Main Orchestrator

Main Orchestrator. Uses httpRequest. Scheduled trigger; 5 nodes.

Cron / scheduled trigger★★★★☆ complexity5 nodesHTTP Request
Web Scraping Trigger: Cron / scheduled Nodes: 5 Complexity: ★★★★☆ Added:

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 →

Download .json
{
  "name": "main-orchestrator",
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "resume-gen",
        "responseMode": "responseNode",
        "options": {
          "binaryPropertyName": "resume"
        }
      },
      "id": "orch-001",
      "name": "Webhook",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        240,
        300
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": false,
            "leftValue": "",
            "typeValidation": "loose"
          },
          "conditions": [
            {
              "id": "cond-is-pdf",
              "leftValue": "={{ ($binary?.resume?.mimeType || $binary?.data?.mimeType || '').toLowerCase().includes('pdf') }}",
              "rightValue": true,
              "operator": {
                "type": "boolean",
                "operation": "equals"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "id": "orch-002",
      "name": "Is PDF?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        480,
        300
      ]
    },
    {
      "parameters": {
        "operation": "pdf",
        "binaryPropertyName": "resume"
      },
      "id": "orch-003",
      "name": "Extract from File",
      "type": "n8n-nodes-base.extractFromFile",
      "typeVersion": 1,
      "position": [
        720,
        180
      ]
    },
    {
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "const item = items[0];\nconst binaryKey = Object.keys(item.binary || {})[0] || 'resume';\nconst binData = item.binary?.[binaryKey];\nconst text = binData?.data ? Buffer.from(binData.data, 'base64').toString('utf-8') : '';\nreturn [{ json: { text, body: item.json.body || {} } }];\n"
      },
      "id": "orch-004",
      "name": "Read TXT Binary",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        720,
        420
      ]
    },
    {
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "const item = items[0];\nconst resumeText = (item.json.text || item.json.body?.resume || '').trim();\nconst webhookBody = $('Webhook').item.json.body || {};\nconst jdUrl  = (webhookBody.jd_url  || '').trim();\nconst jdText = (webhookBody.jd_text || '').trim();\nif (!resumeText) throw new Error('No resume text extracted.');\nif (!jdUrl && !jdText) throw new Error('Provide jd_url or jd_text.');\nreturn [{ json: { resume_text: resumeText, jd_url: jdUrl, jd_text: jdText } }];\n"
      },
      "id": "orch-005",
      "name": "Prepare Inputs",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        960,
        300
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "http://localhost:5678/webhook/jd-scraper",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ { url: $json.jd_url, text: $json.jd_text } }}",
        "options": {
          "timeout": 45000
        }
      },
      "id": "orch-006",
      "name": "Call JD Scraper",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4,
      "position": [
        1200,
        300
      ],
      "continueOnFail": true
    },
    {
      "parameters": {
        "method": "POST",
        "url": "http://localhost:5678/webhook/resume-parser",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ { resume_text: $('Prepare Inputs').item.json.resume_text } }}",
        "options": {
          "timeout": 60000
        }
      },
      "id": "orch-007",
      "name": "Call Resume Parser",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4,
      "position": [
        1440,
        300
      ],
      "continueOnFail": true
    },
    {
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "// Build the exact JSON body for AI tailoring engine\nconst jdResult     = $('Call JD Scraper').item.json;\nconst resumeResult = items[0].json;\n\nlet jd = Array.isArray(jdResult) ? jdResult[0] : jdResult;\nlet resume = Array.isArray(resumeResult) ? resumeResult[0] : resumeResult;\n\nconst jdRaw = typeof jd.jd_raw === 'string' ? jd.jd_raw : JSON.stringify(jd.jd_raw || '');\nif (!jdRaw.trim()) throw new Error('JD Scraper returned empty.');\n\nconst resumeJson = {\n  contact:    resume.contact    || {},\n  summary:    resume.summary    || '',\n  skills:     resume.skills     || [],\n  experience: resume.experience || [],\n  projects:   resume.projects   || [],\n  education:  resume.education  || []\n};\n\n// Store the pre-built JSON string to avoid expression serialization issues\nreturn [{ json: {\n  _aiBody: JSON.stringify({ resume_json: resumeJson, jd_raw: jdRaw }),\n  _latexBody: null,\n  resume_json: resumeJson,\n  jd_raw: jdRaw\n} }];\n"
      },
      "id": "orch-008",
      "name": "Merge for AI",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1680,
        300
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "http://localhost:5678/webhook/ai-tailoring-engine",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ $json }}",
        "options": {
          "timeout": 120000
        }
      },
      "id": "orch-009",
      "name": "Call AI Tailoring Engine",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4,
      "position": [
        1920,
        300
      ],
      "continueOnFail": true
    },
    {
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "// Build latex body from AI tailoring result\nconst data = items[0].json;\nconst body = JSON.stringify({ tailored_resume: data.tailored_resume });\nreturn [{ json: { ...data, _latexBody: body } }];\n"
      },
      "id": "orch-010a",
      "name": "Prep LaTeX Body",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2100,
        300
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "http://localhost:5678/webhook/latex-generator",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ $json }}",
        "options": {
          "timeout": 150000
        }
      },
      "id": "orch-010",
      "name": "Call LaTeX Generator",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4,
      "position": [
        2280,
        300
      ],
      "continueOnFail": true
    },
    {
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "const latex = items[0].json || {};\nconst ai = $('Call AI Tailoring Engine').item.json || {};\n\nreturn [{ json: {\n  pdf_base64:       latex.pdf_base64    ?? null,\n  tex_source:       latex.tex_source    ?? '',\n  ats_score:        ai.ats_score        ?? null,\n  matched_keywords: ai.matched_keywords ?? [],\n  compile_error:    latex.compile_error ?? null,\n  generated_at:     new Date().toISOString(),\n  status:           latex.pdf_base64 ? 'success' : 'partial'\n} }];\n"
      },
      "id": "orch-011",
      "name": "Build Response",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2460,
        300
      ]
    },
    {
      "parameters": {
        "respondWith": "allIncomingItems",
        "options": {
          "responseHeaders": {
            "entries": [
              {
                "name": "Access-Control-Allow-Origin",
                "value": "*"
              }
            ]
          }
        }
      },
      "id": "orch-012",
      "name": "Respond to Webhook",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.1,
      "position": [
        2640,
        300
      ]
    }
  ],
  "connections": {
    "Webhook": {
      "main": [
        [
          {
            "node": "Is PDF?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Is PDF?": {
      "main": [
        [
          {
            "node": "Extract from File",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Read TXT Binary",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract from File": {
      "main": [
        [
          {
            "node": "Prepare Inputs",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Read TXT Binary": {
      "main": [
        [
          {
            "node": "Prepare Inputs",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Inputs": {
      "main": [
        [
          {
            "node": "Call JD Scraper",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Call JD Scraper": {
      "main": [
        [
          {
            "node": "Call Resume Parser",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Call Resume Parser": {
      "main": [
        [
          {
            "node": "Merge for AI",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge for AI": {
      "main": [
        [
          {
            "node": "Call AI Tailoring Engine",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Call AI Tailoring Engine": {
      "main": [
        [
          {
            "node": "Prep LaTeX Body",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prep LaTeX Body": {
      "main": [
        [
          {
            "node": "Call LaTeX Generator",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Call LaTeX Generator": {
      "main": [
        [
          {
            "node": "Build Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Response": {
      "main": [
        [
          {
            "node": "Respond to Webhook",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  },
  "staticData": null,
  "id": 6,
  "active": true
}
Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

Main Orchestrator. Uses httpRequest. Scheduled trigger; 5 nodes.

Source: https://github.com/MoYousif4387/job-search-ai-system/blob/c1d4ac0641f4571797ddc8a9c441e862aeffed36/n8n-workflows/main-orchestrator.json — original creator credit. Request a take-down →

More Web Scraping workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

Web Scraping

Birthday Automation - Production (Fixed). Uses stopAndError, httpRequest, emailSend, bannerbear. Scheduled trigger; 86 nodes.

Stop And Error, HTTP Request, Email Send +1
Web Scraping

This template runs two scheduled workflows to govern Microsoft Entra ID (Azure AD) guest accounts by detecting stale users via Microsoft Graph, staging deletions in SharePoint with a 72-hour window, n

Microsoft SharePoint, Microsoft Teams, Microsoft Entra +1
Web Scraping

Jira-Allure-Auto-Qa. Uses httpRequest, jira. Scheduled trigger; 68 nodes.

HTTP Request, Jira
Web Scraping

Spotify-Sync-Surrealdb-V1. Uses httpRequest, n8n-nodes-surrealdb, spotify. Scheduled trigger; 62 nodes.

HTTP Request, N8N Nodes Surrealdb, Spotify
Web Scraping

As n8n instances scale, teams often lose track of sub-workflows—who uses them, where they are referenced, and whether they can be safely updated. This leads to inefficiencies like unnecessary copies o

HTTP Request, n8n, N8N Trigger +1