AutomationFlowsAI & RAG › Weekly Job Discovery and Cv Matching with Gemini 1.5 Pro and Decodo Scraper

Weekly Job Discovery and Cv Matching with Gemini 1.5 Pro and Decodo Scraper

ByAbdullah Alshiekh @abdullah01 on n8n.io

This workflow automates the entire search process: every week, it uses Decodo’s reliable scraping engine to scan the web for fresh opportunities in your region and industry — no manual searching, no endless scrolling.

Cron / scheduled trigger★★★★☆ complexityAI-powered17 nodesGoogle Gemini Chat@Decodo/N8N Nodes DecodoChain SummarizationAgentGmail
AI & RAG Trigger: Cron / scheduled Nodes: 17 Complexity: ★★★★☆ AI nodes: yes Added:

This workflow corresponds to n8n.io template #11125 — we link there as the canonical source.

This workflow follows the Agent → Chainsummarization 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 →

Download .json
{
  "id": "sdhO9f92RhFTuMTs",
  "name": "Job Listing Tracking Decodo (Template)",
  "tags": [],
  "nodes": [
    {
      "id": "a4ceb35e-fbf7-4298-a0b2-6fc0a3b6b6e3",
      "name": "Google Gemini Chat Model (Agent)",
      "type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
      "position": [
        560,
        400
      ],
      "parameters": {
        "options": {},
        "modelName": "models/gemini-1.5-pro"
      },
      "typeVersion": 1
    },
    {
      "id": "23f47c29-22e7-46b3-abec-7ea82300ad3f",
      "name": "Google Gemini Chat Model (Summarizer)",
      "type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
      "position": [
        -48,
        384
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 1
    },
    {
      "id": "434b83d1-d234-4891-bd6f-3226bb908671",
      "name": "Schedule Trigger1",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -1664,
        176
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "weeks",
              "triggerAtDay": [
                6
              ]
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "9a8afe02-250b-4e18-992b-6b85456fc0e3",
      "name": "Set Search Config1",
      "type": "n8n-nodes-base.set",
      "position": [
        -1440,
        176
      ],
      "parameters": {
        "mode": "raw",
        "options": {},
        "jsonOutput": "{\n  \"topic\": \"INSERT_TOPIC_HERE\",\n  \"regions\": [\"INSERT_REGION_HERE\"],\n  \"platforms\": [\"linkedin.com\"],\n  \"search_terms\": [\"hiring\", \"vacancy\", \"job opening\", \"career\"]\n}\n"
      },
      "typeVersion": 3.4
    },
    {
      "id": "24cef7ec-e5fa-4707-a83e-8e2282a0714c",
      "name": "Google Search Jobs1",
      "type": "@decodo/n8n-nodes-decodo.decodo",
      "position": [
        -1168,
        176
      ],
      "parameters": {
        "geo": "={{ $json.regions[0] }}",
        "query": "={{$json.topic}} {{$json.search_terms}} site:{{ $json.platforms[0] }} {{ $json.regions[0] }} after:2025-10-01\n",
        "headless": false,
        "operation": "google_search"
      },
      "typeVersion": 1
    },
    {
      "id": "884af97e-1f75-4b86-8256-fcafefb2e630",
      "name": "Parse Search Results1",
      "type": "n8n-nodes-base.code",
      "position": [
        -912,
        176
      ],
      "parameters": {
        "jsCode": "// Safely get the organic results array from Decodo Google Search\n\nconst root = $json.results?.[0]?.content?.results;\n\n// Some Decodo versions nest it as results.organic, others as organic directly.\n// This handles both shapes.\nconst organic = root?.results?.organic || root?.organic || [];\n\nif (!Array.isArray(organic) || organic.length === 0) {\n  return []; // nothing to process\n}\n\n// Map each search result to its own item\nreturn organic.map(item => ({\n  json: {\n    url: item.url || \"\",\n    title: item.title || \"\",\n    desc: item.desc || \"\",\n    pos: item.pos || item.pos_overall || null,\n    url_shown: item.url_shown || \"\",\n    favicon_text: item.favicon_text || \"\",\n    // keep any context you want to reuse later:\n    region: $json.region || \"\",\n    platform: $json.platform || \"\"\n  }\n}));\n"
      },
      "typeVersion": 2
    },
    {
      "id": "f5a63c2c-0236-452f-a222-5636c8340eee",
      "name": "Loop Job URLs1",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        -576,
        176
      ],
      "parameters": {
        "options": {},
        "batchSize": "=1"
      },
      "typeVersion": 3
    },
    {
      "id": "f4a6f5f4-711a-4c22-8afb-e4db83c77548",
      "name": "Scrape Page HTML1",
      "type": "@decodo/n8n-nodes-decodo.decodo",
      "position": [
        -272,
        256
      ],
      "parameters": {
        "url": "={{ $json.url }}"
      },
      "typeVersion": 1
    },
    {
      "id": "87392b6e-31c7-4104-9d83-6e935afb8956",
      "name": "Clean HTML Text1",
      "type": "n8n-nodes-base.code",
      "position": [
        -192,
        496
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "const item = $input.item.json;\n\nlet html = \"\";\n\ntry {\n  html = item.results[0].content || \"\";\n} catch (e) {\n  html = \"\";\n}\n\nlet cleaned = html\n  .replace(/<script[^>]*>[\\s\\S]*?<\\/script>/gi, \"\")\n  .replace(/<style[^>]*>[\\s\\S]*?<\\/style>/gi, \"\")\n  .replace(/<noscript[^>]*>[\\s\\S]*?<\\/noscript>/gi, \"\")\n  .replace(/<\\/?[^>]+>/g, \" \")\n  .replace(/&nbsp;/gi, \" \")\n  .replace(/&amp;/gi, \"&\")\n  .replace(/&quot;/gi, '\"')\n  .replace(/&#39;/gi, \"'\")\n  .replace(/&lt;/gi, \"<\")\n  .replace(/&gt;/gi, \">\")\n  .replace(/\\s+/g, \" \")\n  .trim();\n\nreturn {\n  json: {\n    text_clean: cleaned\n  }\n};\n"
      },
      "typeVersion": 2
    },
    {
      "id": "bc76fed8-9777-4fc3-9080-0ca8f4a10046",
      "name": "AI Summarizer1",
      "type": "@n8n/n8n-nodes-langchain.chainSummarization",
      "position": [
        -64,
        160
      ],
      "parameters": {
        "options": {
          "summarizationMethodAndPrompts": {
            "values": {
              "prompt": "=You will receive raw cleaned text {{ $json.text_clean }} from a job-posting webpage (LinkedIn or Indeed). \nYour task is to produce a short, dense summary of the job posting focusing ONLY on \nthe information needed for job-listing tracking.\n\nDo NOT rewrite the entire page. \nDo NOT include irrelevant text, branding, disclaimers, repetitive paragraphs, or legal content.\n\nExtract only the following elements IF they appear in the text:\n\n- Company name\n- Job title\n- Location (city + country if possible)\n- Employment type (Full-time, Part-time, Contract, Remote, Hybrid, Internship)\n- Key responsibilities (very short, 2\u20133 bullets max)\n- Required skills or technologies (condense into a simple list)\n- Preferred qualifications (if present)\n- Posted date or time reference (e.g., \u201cposted 4 days ago\u201d)\n- Any noted salary or benefits (if present)\n\nReturn your result as a **short human-readable text summary**, not JSON.\n\nExample style:\n\u201cCompany: X  \nRole: Senior Data Scientist  \nLocation: Berlin, Germany  \nEmployment: Full-time  \nResponsibilities: \u2014 ; \u2014 ; \u2014  \nSkills: Python, TensorFlow, SQL  \nPreferred: MSc/PhD  \nPosted: 2 days ago\u201d\n\nIf a field is missing in the original content, skip it silently. \nKeep the entire summary under 8\u201310 lines. \nAvoid extra explanations.\n",
              "summarizationMethod": "stuff"
            }
          }
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "2f0cdf6c-fc57-45f3-bd94-a6209d118040",
      "name": "Aggregate Summaries1",
      "type": "n8n-nodes-base.code",
      "position": [
        272,
        160
      ],
      "parameters": {
        "jsCode": "// Collect all items coming from Summarization/Extraction\nconst items = $input.all();\n\n// Extract each summary from each item\nconst summaries = items.map(item => item.json);\n\n// Build a single output item\nreturn [\n  {\n    json: {\n      summaries\n    }\n  }\n];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "bab23a2e-af2c-4ba0-b708-72d999b4b4ca",
      "name": "Job Matcher Agent1",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        560,
        160
      ],
      "parameters": {
        "text": "=You are a personal AI job-matching analyst.\n\nINPUT YOU WILL RECEIVE:\n1. The user\u2019s full CV text.\n2. The job listings scraped from one region and one platform \n   (LinkedIn OR Indeed) using Decodo.\n   Each job listing contains:\n   - job_title\n   - company_name\n   - location\n   - posted_date\n   - platform\n   - job_description\n   - skills_required\n   - experience_level\n   - url\n\n\nThe region and platform are fixed for this report. \nDo not mention any other region or platform.\n\n-----------------------------------\nSTEP 1 \u2014 Understand the Candidate\n-----------------------------------\nAnalyze the CV deeply:\n- Identify the candidate\u2019s strongest skills, technologies, tools, and domains.\n- Determine the type of roles the candidate fits (automation engineer, AI engineer, network engineer, etc.).\n- Determine seniority level and career strengths.\n\n-----------------------------------\nSTEP 2 \u2014 Match Jobs to the Candidate\n-----------------------------------\nFor each scraped job:\n\n1. Determine if the job is relevant to the candidate\u2019s career path.\n2. Compare job requirements with the CV.\n3. Compute a **Match Percentage (0\u2013100%)** based on:\n   - Skill overlap\n   - Experience relevance\n   - Seniority fit\n   - Domain fit\n4. Exclude jobs below 50% match.\n5. For each included job, prepare:\n   - Job Title\n   - Company Name\n   - Location\n   - Platform (LinkedIn or Indeed)\n   - Match Percentage\n   - Short explanation of why it matches\n   - Posted Date (use posted_date provided \u2014 do NOT guess)\n   - URL\n\n-----------------------------------\nSTEP 3 \u2014 Generate The Final Weekly Report\n-----------------------------------\nWrite ONE single message structured as follows:\n\nA) Candidate Overview\n   - 1\u20132 sentences summarizing the candidate\u2019s strengths and professional identity.\n\nB) Matching Jobs (all from ONE region and ONE platform)\n   - List all relevant jobs ordered by Match Percentage (highest \u2192 lowest):\n     - Job Title \u2013 Company Name\n       Match: XX%\n       Posted: <posted_date from job listing>\n       Why it matches:\n         \u2022 <reason 1>\n         \u2022 <reason 2>\n       Link: <url>\n \nC) Key Insights for the Candidate\n   - 3\u20135 short insights:\n     \u2022 What role types seem to fit them best.\n     \u2022 What skills appear most often in matched jobs.\n     \u2022 Whether the region looks promising.\n     \u2022 Any skill gaps that could increase their match %.\n\n-----------------------------------\nRULES\n-----------------------------------\n- The report must be plain text (no markdown, no JSON).\n- Do NOT mention today\u2019s date.\n- Do NOT fabricate dates \u2014 only use posted_date from the job listing.\n- Only mention the region and platform that appear in the input.\n- Do NOT invent job listings or details.\n- Do NOT output sections with zero matches.\n- Maintain a professional, supportive tone.\n\n\nuser_cv : \"{{ $json.cv_text }}\"",
        "options": {},
        "promptType": "define"
      },
      "typeVersion": 3
    },
    {
      "id": "a6e31cfb-9b44-45f5-8751-9133d8147cd5",
      "name": "Send Email Report1",
      "type": "n8n-nodes-base.gmail",
      "position": [
        1008,
        160
      ],
      "parameters": {
        "sendTo": "user@example.com",
        "message": "={{ $json.output }}",
        "options": {
          "appendAttribution": false
        },
        "subject": "=Weekly Job Listing Report \u2013 LinkedIn/Indeed Hiring Trends ({{ new Date().toLocaleDateString() }})",
        "emailType": "text"
      },
      "typeVersion": 2.1
    },
    {
      "id": "4f7e7fd7-adaf-4cb9-9a2e-554f7d3d05aa",
      "name": "Sticky Note10",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1488,
        96
      ],
      "parameters": {
        "color": 4,
        "width": 704,
        "height": 256,
        "content": "Groupt A: \ndefines target search parameters and uses the Decodo API (requires credentials) to search for job listings. It then filters out invalid entries to generate a clean list of URLs for processing."
      },
      "typeVersion": 1
    },
    {
      "id": "78cabaf6-22fa-4f44-86b5-fa78b74ddcec",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -752,
        64
      ],
      "parameters": {
        "color": 5,
        "width": 640,
        "height": 560,
        "content": "Group B:\ngoes through each job URL to scrape the full page HTML using Decodo, ensuring proxies handle any blocking issues. It then strips out all tags and scripts to produce clean, plain text for analysis."
      },
      "typeVersion": 1
    },
    {
      "id": "9f3f1439-0de9-4a23-bfd7-21ed81ca5909",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -80,
        16
      ],
      "parameters": {
        "color": 3,
        "width": 1200,
        "height": 336,
        "content": "Group C: \nuses AI and takes all the raw job postings converts them into key details. It then collects all the individual summaries and aggregates them into a single list for the final analysis and prepare them to be emailed."
      },
      "typeVersion": 1
    },
    {
      "id": "7938eb14-a48d-4f60-b4be-466cb17be9bd",
      "name": "Sticky Note15",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1728,
        -400
      ],
      "parameters": {
        "width": 1008,
        "height": 528,
        "content": "## How to Set Up **Decodo** Credentials in n8n\n\n### Part 1: Get Your Decodo Authentication Token\n\n* **Activate Your Plan: The Decodo node requires a Web Scraping API Advanced plan. You can begin with a free trial, which is available on the Decodo dashboard.**\n* **Locate Your Token: Once your plan is active, navigate to the Web Scraping API page within your Decodo account.**\n* **Copy Your Token: Find and copy the authentication token generated for you on that page.**\n\n### Part 2: Add the Token to n8n\n\n* **Open n8n Credentials: Inside n8n, open the credentials window.**\n\n* **Create a New Credential: Select the option to create a new credential.**\n\n* **Find the Decodo Type: Search for and select the \"Decodo Credentials API\".**\n\n* **Paste and Save: Enter your authentication token (that you copied from the Decodo dashboard) into the field and save it.**\n\n\n### For detailed instructions : github.com/Decodo/n8n-nodes-decodo/tree/main"
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "83aefaae-3872-4a03-9909-45a81c2ba7f4",
  "connections": {
    "AI Summarizer1": {
      "main": [
        [
          {
            "node": "Aggregate Summaries1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Loop Job URLs1": {
      "main": [
        [
          {
            "node": "AI Summarizer1",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Scrape Page HTML1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Clean HTML Text1": {
      "main": [
        [
          {
            "node": "Loop Job URLs1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Schedule Trigger1": {
      "main": [
        [
          {
            "node": "Set Search Config1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Scrape Page HTML1": {
      "main": [
        [
          {
            "node": "Clean HTML Text1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Job Matcher Agent1": {
      "main": [
        [
          {
            "node": "Send Email Report1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set Search Config1": {
      "main": [
        [
          {
            "node": "Google Search Jobs1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google Search Jobs1": {
      "main": [
        [
          {
            "node": "Parse Search Results1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Aggregate Summaries1": {
      "main": [
        [
          {
            "node": "Job Matcher Agent1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Search Results1": {
      "main": [
        [
          {
            "node": "Loop Job URLs1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google Gemini Chat Model (Agent)": {
      "ai_languageModel": [
        [
          {
            "node": "Job Matcher Agent1",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Google Gemini Chat Model (Summarizer)": {
      "ai_languageModel": [
        [
          {
            "node": "AI Summarizer1",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    }
  }
}
Pro

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

About this workflow

This workflow automates the entire search process: every week, it uses Decodo’s reliable scraping engine to scan the web for fresh opportunities in your region and industry — no manual searching, no endless scrolling.

Source: https://n8n.io/workflows/11125/ — original creator credit. Request a take-down →

More AI & RAG workflows → · Browse all categories →

Related workflows

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

AI & RAG

Businesses waste countless hours manually gathering online insights across platforms.

Google Gemini Chat, @Decodo/N8N Nodes Decodo, Agent +1
AI & RAG

Sign Up for Decodo HERE for discount

Data Table, Output Parser Structured, @Decodo/N8N Nodes Decodo +3
AI & RAG

Staying up-to-date with AI and LLM developments requires reading dozens of articles every week. Manual research is time-consuming and often leads to “information overload” or reading low-quality click

Chain Summarization, Agent, Gmail +3
AI & RAG

Sign up for Decodo — get better pricing here

@Decodo/N8N Nodes Decodo, Google Gemini Chat, Output Parser Structured +5
AI & RAG

This n8n workflow automates job discovery by scanning company career pages, extracting open positions using AI, filtering them by department, and sending real-time alerts via Slack and email. It is id

@Decodo/N8N Nodes Decodo, Google Gemini Chat, Agent +3