AutomationFlowsAI & RAG › Applyiq

Applyiq

ApplyIQ. Uses chainLlm, n8n-nodes-serpapi, supabase, lmChatOpenAi. Webhook trigger; 22 nodes.

Webhook trigger★★★★☆ complexityAI-powered22 nodesChain LlmN8N Nodes SerpapiSupabaseOpenAI Chat
AI & RAG Trigger: Webhook Nodes: 22 Complexity: ★★★★☆ AI nodes: yes Added:

This workflow follows the Chainllm → OpenAI Chat 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
{
  "name": "ApplyIQ",
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "ApplyIQ",
        "options": {}
      },
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2.1,
      "position": [
        -240,
        0
      ],
      "id": "58cbdc33-f74a-4531-af38-8600db321fd8",
      "name": "Webhook"
    },
    {
      "parameters": {
        "promptType": "define",
        "text": "=Extract a complete candidate profile from this resume.\n\nResume:\n{{ $json.body.resume_text }}\n\nUser's stated target job: {{ $json.body.target_job }}\nUser's stated experience level: {{ $json.body.experience_level }}\n\nReturn ONLY this JSON:\n{\n  \"candidate_name\": \"\",\n  \"experience_level\": \"\",\n  \"years_of_experience\": 0,\n  \"key_skills\": [],\n  \"soft_skills\": [],\n  \"domains\": [],\n  \"education\": \"\",\n  \"notable_projects\": [],\n  \"certifications\": [],\n  \"preferred_job_titles\": [],\n  \"strengths\": [],\n  \"weaknesses\": [],\n  \"recommended_keywords\": []\n}\n\nRules:\n- experience_level: exactly one of \"fresh-graduate\", \"junior\", \"mid-level\", \"senior\" \u2014 infer from resume AND user input\n- key_skills: ALL technical skills found (tools, languages, frameworks)\n- notable_projects: max 3, each as short string \"name \u2014 impact/metric\"\n- preferred_job_titles: 5 titles this candidate realistically qualifies for, aligned with the user's target job\n- weaknesses: gaps relative to the target job (be honest)\n- recommended_keywords: ATS keywords missing from resume but expected for target job",
        "messages": {
          "messageValues": [
            {
              "message": "You are a resume parsing engine. Return ONLY valid JSON starting with { and ending with }. No markdown, no explanation, no text outside JSON. Analyze deeply \u2014 never leave arrays empty if information exists in the resume."
            }
          ]
        },
        "batching": {}
      },
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "typeVersion": 1.9,
      "position": [
        16,
        0
      ],
      "id": "fd840d28-11e1-4188-ae33-8b7770af9a3c",
      "name": "Resume Screening AI"
    },
    {
      "parameters": {
        "jsCode": "const aiOutput = $input.first().json.text || '';\n\nlet cleaned = aiOutput.replace(/```json/g, '').replace(/```/g, '').trim();\nconst jsonMatch = cleaned.match(/\\{[\\s\\S]*\\}/);\nif (jsonMatch) cleaned = jsonMatch[0];\n\nconst formData = $('Webhook').first().json.body;\nconst userTargetJob = formData.target_job || '';\nconst userLocation = formData.target_location || 'Indonesia';\nconst userExpLevel = formData.experience_level || 'fresh-graduate';\n\nlet parsed;\ntry {\n  parsed = JSON.parse(cleaned);\n} catch (e) {\n  parsed = {};\n}\n\n// Merge dengan default agar semua field selalu ada\nconst profile = {\n  candidate_name: parsed.candidate_name || formData.full_name || '',\n  experience_level: parsed.experience_level || userExpLevel,\n  years_of_experience: parsed.years_of_experience ?? 0,\n  key_skills: parsed.key_skills || [],\n  soft_skills: parsed.soft_skills || [],\n  domains: parsed.domains || [],\n  education: parsed.education || '',\n  notable_projects: parsed.notable_projects || [],\n  certifications: parsed.certifications || [],\n  preferred_job_titles: (parsed.preferred_job_titles && parsed.preferred_job_titles.length > 0)\n    ? parsed.preferred_job_titles\n    : [userTargetJob],\n  strengths: parsed.strengths || [],\n  weaknesses: parsed.weaknesses || [],\n  recommended_keywords: parsed.recommended_keywords || []\n};\n\nreturn [{\n  json: {\n    candidate_profile: profile,\n    resume_text: formData.resume_text || '',\n    target_location: userLocation,\n    target_job: userTargetJob,\n    email: formData.email || '',\n    full_name: formData.full_name || ''\n  }\n}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        336,
        0
      ],
      "id": "5d0928c8-6f9a-4386-83c5-9014dffbccca",
      "name": "Parse Resume"
    },
    {
      "parameters": {
        "jsCode": "const aiOutput = $input.first().json.text || '';\n\nlet cleaned = aiOutput.replace(/```json/g, '').replace(/```/g, '').trim();\nconst jsonMatch = cleaned.match(/\\{[\\s\\S]*\\}/);\nif (jsonMatch) cleaned = jsonMatch[0];\n\nlet parsed;\ntry {\n  parsed = JSON.parse(cleaned);\n} catch (e) {\n  parsed = {\n    ats_score: 0,\n    score_breakdown: {},\n    strengths: [],\n    what_to_add: [],\n    what_to_remove: [],\n    keyword_suggestions: [],\n    rewrite_suggestions: [],\n    overall_advice: 'Analisa CV gagal diproses. Silakan coba lagi.'\n  };\n}\n\nreturn [{\n  json: {\n    ...($('Parse Job Titles').first().json),\n    cv_improvement: parsed\n  }\n}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1488,
        0
      ],
      "id": "73eb4d44-8fad-4983-bc7c-9c77c475505f",
      "name": "Parse CV Improvement"
    },
    {
      "parameters": {
        "operation": "google_jobs",
        "q": "={{ $json.search_query }}",
        "additionalFields": {
          "gl": "id",
          "hl": "id"
        },
        "requestOptions": {}
      },
      "type": "n8n-nodes-serpapi.serpApi",
      "typeVersion": 1,
      "position": [
        1888,
        0
      ],
      "id": "e0b393b6-e323-41d9-929d-aae64524b4d8",
      "name": "Google_jobs search",
      "credentials": {
        "serpApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "options": {}
      },
      "type": "n8n-nodes-base.splitInBatches",
      "typeVersion": 3,
      "position": [
        2304,
        0
      ],
      "id": "a604762d-443c-4f17-b616-77f5431cab86",
      "name": "Loop Over Items"
    },
    {
      "parameters": {
        "promptType": "define",
        "text": "=Score this candidate against this specific job.\n\nCANDIDATE:\n- Skills: {{ $json.candidate_profile.key_skills }}\n- Experience level: {{ $json.candidate_profile.experience_level }}\n- Projects: {{ $json.candidate_profile.notable_projects }}\n- Certifications: {{ $json.candidate_profile.certifications }}\n\nJOB:\n- Title: {{ $json.title }}\n- Company: {{ $json.company_name }}\n- Location: {{ $json.location }}\n- Description: {{ $json.description }}\n\nReturn ONLY:\n{\n  \"match_score\": 0,\n  \"matched_skills\": [],\n  \"missing_skills\": [],\n  \"recommendation\": \"apply\",\n  \"reason\": \"\",\n  \"seniority_mismatch\": false\n}\n\nScoring method:\n1. List the CORE required skills from the job description (ignore nice-to-have requirements like \"X years experience\", university status, or soft skills)\n2. matched_skills = core requirements the candidate has evidence for\n3. missing_skills = core requirements the candidate lacks\n4. match_score = (matched / total core) \u00d7 100, adjusted:\n   - +10 if candidate has a relevant project or certification\n   - -15 ONLY if the job explicitly requires senior/managerial level (5+ years)\n5. recommendation = \"apply\" if match_score >= 35, else \"skip\"\n6. For fresh-graduate candidates: entry-level, junior, internship, and associate roles should almost always be \"apply\" if 2+ core skills match\n7. reason: 1-2 kalimat Bahasa Indonesia, sebutkan skill yang match dan yang kurang",
        "messages": {
          "messageValues": [
            {
              "message": "You are a strict but fair recruitment expert for the Indonesian job market. Return ONLY valid JSON. No text outside JSON. Calculate scores from actual evidence \u2014 never use default or placeholder scores."
            }
          ]
        },
        "batching": {}
      },
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "typeVersion": 1.9,
      "position": [
        2416,
        176
      ],
      "id": "db10bc05-fe19-4c7d-bc7e-50e02ade3b29",
      "name": "Job Scoring AI "
    },
    {
      "parameters": {
        "jsCode": "const aiOutput = $input.first().json.text || '';\n\nlet cleaned = aiOutput.replace(/```json/g, '').replace(/```/g, '').trim();\nconst jsonMatch = cleaned.match(/\\{[\\s\\S]*\\}/);\nif (jsonMatch) cleaned = jsonMatch[0];\n\nlet parsed;\ntry {\n  parsed = JSON.parse(cleaned);\n} catch (e) {\n  parsed = { match_score: 0, matched_skills: [], missing_skills: [], recommendation: 'skip', reason: 'Parse gagal' };\n}\n\nconst rec = (parsed.recommendation || '').toLowerCase().trim();\n\n// \u2705 FIX: ambil data job dari Loop Over Items, bukan dari output AI\nconst jobData = $('Loop Over Items').item.json;\n\nreturn [{\n  json: {\n    match_score: Number(parsed.match_score) || 0,\n    matched_skills: parsed.matched_skills || [],\n    missing_skills: parsed.missing_skills || [],\n    recommendation: rec.includes('apply') ? 'apply' : 'skip',\n    reason: parsed.reason || '',\n    job_title: jobData.title || 'N/A',\n    company: jobData.company_name || 'N/A',\n    job_location: jobData.location || '',\n    job_link: jobData.apply_options?.[0]?.link || jobData.share_link || '',\n    candidate_profile: jobData.candidate_profile,\n    resume_text: jobData.resume_text,\n    cv_improvement: jobData.cv_improvement,\n    email: jobData.email,\n    full_name: jobData.full_name\n  }\n}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2656,
        384
      ],
      "id": "056be34e-08ca-4731-afea-515bb60f26d6",
      "name": "Parse Job Scoring"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 3
          },
          "conditions": [
            {
              "id": "b7e5ec49-721f-4f86-a4be-92d72d0695a1",
              "leftValue": "={{ $json.recommendation }}",
              "rightValue": "apply",
              "operator": {
                "type": "string",
                "operation": "equals",
                "name": "filter.operator.equals"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.filter",
      "typeVersion": 2.3,
      "position": [
        2768,
        176
      ],
      "id": "231360ce-a191-4b25-ba2e-05d3c6ccdeea",
      "name": "Filter Job"
    },
    {
      "parameters": {
        "promptType": "define",
        "text": "=Tulis cover letter Bahasa Indonesia untuk lamaran ini.\n\nKandidat: {{ $json.full_name }}\nPosisi: {{ $json.job_title }}\nPerusahaan: {{ $json.company }}\nSkills yang match dengan job: {{ $json.matched_skills }}\nResume lengkap: {{ $json.resume_text }}\n\nStruktur wajib (3 paragraf):\n1. Perkenalan + alasan spesifik tertarik pada posisi {{ $json.job_title }} di {{ $json.company }}\n2. 2-3 pencapaian KONKRET dari resume dengan angka (proyek, metrik, hasil) yang relevan dengan matched_skills\n3. Penutup profesional + ajakan interview\n\nLarangan:\n- Tidak boleh ada kalimat klise (\"pekerja keras\", \"mampu bekerja dalam tim\")\n- Tidak boleh menyebut skill yang TIDAK ada di resume\n- Maksimal 250 kata",
        "messages": {
          "messageValues": [
            {
              "message": "Kamu adalah career coach profesional untuk pasar kerja Indonesia. Tulis cover letter yang personal, spesifik, dan meyakinkan. Output plain text saja tanpa markdown."
            }
          ]
        },
        "batching": {}
      },
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "typeVersion": 1.9,
      "position": [
        2880,
        384
      ],
      "id": "9e57554a-3b81-46b4-81e4-9a7ca69bbba0",
      "name": "Cover Latter AI"
    },
    {
      "parameters": {
        "jsCode": "// Data job dari node sebelum Cover Letter AI\nconst d = $('Filter Job').item.json;\n\nreturn [{\n  json: {\n    job_title: d.job_title,\n    company: d.company,\n    match_score: d.match_score,\n    recommendation: d.recommendation,\n    reason: d.reason,\n    job_link: d.job_link,\n    cover_letter: $input.first().json.text || '',\n    email: d.email,\n    full_name: d.full_name,\n    cv_improvement: JSON.stringify(d.cv_improvement),\n    status: 'new'\n  }\n}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        3120,
        192
      ],
      "id": "6b29c6a4-753f-4ab9-8ff1-607aab74625d",
      "name": "Final Data"
    },
    {
      "parameters": {
        "tableId": "job_applications",
        "fieldsUi": {
          "fieldValues": [
            {
              "fieldId": "job_title",
              "fieldValue": "={{ $json.job_title }}"
            },
            {
              "fieldId": "company",
              "fieldValue": "={{ $json.company }}"
            },
            {
              "fieldId": "match_score",
              "fieldValue": "={{ $json.match_score }}"
            },
            {
              "fieldId": "recommendation",
              "fieldValue": "={{ $json.recommendation }}"
            },
            {
              "fieldId": "cover_letter",
              "fieldValue": "={{ $json.cover_letter }}"
            },
            {
              "fieldId": "job_link",
              "fieldValue": "={{ $json.job_link }}"
            },
            {
              "fieldId": "submitter_email",
              "fieldValue": "={{ $json.email }}"
            },
            {
              "fieldId": "cv_improvement",
              "fieldValue": "={{ $json.cv_improvement }}"
            },
            {
              "fieldId": "status",
              "fieldValue": "new"
            }
          ]
        }
      },
      "type": "n8n-nodes-base.supabase",
      "typeVersion": 1,
      "position": [
        3232,
        368
      ],
      "id": "863a3967-c012-43fc-be8d-a2edc7e3e7cf",
      "name": "Create a row",
      "credentials": {
        "supabaseApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "model": {
          "__rl": true,
          "value": "cx/gpt-5.5",
          "mode": "list",
          "cachedResultName": "cx/gpt-5.5"
        },
        "builtInTools": {},
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "typeVersion": 1.3,
      "position": [
        16,
        256
      ],
      "id": "26b82b9b-eb2d-4629-ab3c-3c40166bbf93",
      "name": "OpenAI Chat Model",
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "model": {
          "__rl": true,
          "value": "cx/gpt-5.5",
          "mode": "list",
          "cachedResultName": "cx/gpt-5.5"
        },
        "builtInTools": {},
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "typeVersion": 1.3,
      "position": [
        544,
        240
      ],
      "id": "70b78bb8-5bec-4ee6-9beb-7f94712313a3",
      "name": "OpenAI Chat Model1",
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "model": {
          "__rl": true,
          "value": "cx/gpt-5.5",
          "mode": "list",
          "cachedResultName": "cx/gpt-5.5"
        },
        "builtInTools": {},
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "typeVersion": 1.3,
      "position": [
        2416,
        592
      ],
      "id": "107c7377-86f4-4fdc-ab3f-0a75b786e288",
      "name": "OpenAI Chat Model2",
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "model": {
          "__rl": true,
          "value": "cx/gpt-5.5",
          "mode": "list",
          "cachedResultName": "cx/gpt-5.5"
        },
        "builtInTools": {},
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "typeVersion": 1.3,
      "position": [
        2880,
        624
      ],
      "id": "077dbd29-78da-480e-87aa-f0d7ecf43375",
      "name": "OpenAI Chat Model3",
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "promptType": "define",
        "text": "=Generate job search titles for this candidate.\n\nTarget job: \"{{ $json.target_job }}\"\nExperience level: \"{{ $json.candidate_profile.experience_level }}\"\nCandidate skills: {{ $json.candidate_profile.key_skills }}\nCandidate domains: {{ $json.candidate_profile.domains }}\n\nReturn ONLY:\n{\n  \"job_titles\": [\"\", \"\", \"\", \"\", \"\"]\n}\n\nRules:\n- Exactly 5 DIFFERENT titles commonly used on Jobstreet, Glints, LinkedIn Indonesia\n- Title 1 must be the user's target job as-is\n- Titles 2-3: close variations matching the experience level (e.g. add \"Junior\"/\"Associate\" for fresh grads)\n- Titles 4-5: adjacent roles the candidate's skills also qualify for\n- Never invent senior titles for a fresh graduate",
        "messages": {
          "messageValues": [
            {
              "message": "You are an Indonesian job market expert. Return ONLY valid JSON. No text outside JSON."
            }
          ]
        },
        "batching": {}
      },
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "typeVersion": 1.9,
      "position": [
        544,
        0
      ],
      "id": "d2d1cace-04ce-4f9f-aac3-67dc0b1277a9",
      "name": "Generate Job Titles AI"
    },
    {
      "parameters": {
        "jsCode": "const aiOutput = $input.first().json.text || '';\n\nlet cleaned = aiOutput.replace(/\\\\n/g, ' ').replace(/```json/g, '').replace(/```/g, '').trim();\nconst jsonMatch = cleaned.match(/\\{[\\s\\S]*\\}/);\nif (jsonMatch) cleaned = jsonMatch[0];\n\nlet jobTitles = [];\ntry {\n  jobTitles = JSON.parse(cleaned).job_titles || [];\n} catch (e) { /* fallback di bawah */ }\n\nconst prevData = $('Parse Resume').first().json;\nconst targetJob = prevData.target_job || '';\n\nif (jobTitles.length === 0) {\n  jobTitles = [targetJob, `Junior ${targetJob}`, `Associate ${targetJob}`];\n}\n\nprevData.candidate_profile.preferred_job_titles = jobTitles;\n\nreturn [{ json: prevData }];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        880,
        0
      ],
      "id": "f53c8c5e-1ca4-4942-a874-c2f74c8686f1",
      "name": "Parse Job Titles"
    },
    {
      "parameters": {
        "promptType": "define",
        "text": "=Audit this resume against the target job. Be brutally specific.\n\nResume:\n{{ $('Webhook').first().json.body.resume_text }}\n\nTarget job: {{ $('Webhook').first().json.body.target_job }}\n\nReturn ONLY this JSON:\n{\n  \"ats_score\": 0,\n  \"score_breakdown\": {\n    \"format\": 0,\n    \"keywords\": 0,\n    \"experience\": 0,\n    \"skills\": 0,\n    \"achievements\": 0\n  },\n  \"strengths\": [],\n  \"what_to_add\": [\n    {\"item\": \"\", \"reason\": \"\", \"example\": \"\", \"priority\": \"high\"}\n  ],\n  \"what_to_remove\": [\n    {\"item\": \"\", \"reason\": \"\"}\n  ],\n  \"keyword_suggestions\": [],\n  \"rewrite_suggestions\": [\n    {\"original\": \"\", \"improved\": \"\"}\n  ],\n  \"overall_advice\": \"\"\n}\n\nRules:\n- Each breakdown dimension 0-20; ats_score = exact sum (max 100)\n- what_to_add: 3-5 items, each \"example\" must be a ready-to-paste sentence using the candidate's actual data\n- what_to_remove: quote the actual phrases from the resume\n- rewrite_suggestions: 2-4 items, \"original\" = verbatim bullet from resume, \"improved\" = rewritten with a concrete metric\n- keyword_suggestions: ATS keywords for the target job that are MISSING from this resume\n- overall_advice: 2-3 sentences, direct, in Bahasa Indonesia",
        "messages": {
          "messageValues": [
            {
              "message": "You are a senior ATS consultant and recruiter with 10+ years in the Indonesian tech job market. Return ONLY valid JSON. No text outside JSON. Every suggestion MUST reference actual content from the resume \u2014 generic advice is forbidden."
            }
          ]
        },
        "batching": {}
      },
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "typeVersion": 1.9,
      "position": [
        1104,
        0
      ],
      "id": "792bf431-2d24-475b-b25c-dcd3e8daa801",
      "name": "CV Impovement"
    },
    {
      "parameters": {
        "model": {
          "__rl": true,
          "value": "cx/gpt-5.5",
          "mode": "list",
          "cachedResultName": "cx/gpt-5.5"
        },
        "builtInTools": {},
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "typeVersion": 1.3,
      "position": [
        1104,
        256
      ],
      "id": "719ca3ec-cbd4-43c5-a29f-3ea29fd020cb",
      "name": "OpenAI Chat Model4",
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "const allItems = $input.all();\nconst allJobs = [];\nconst seen = new Set();\n\nconst prevData = {\n  candidate_profile: $('Parse Job Titles').first().json.candidate_profile,\n  resume_text: $('Parse Job Titles').first().json.resume_text,\n  target_location: $('Parse Job Titles').first().json.target_location,\n  target_job: $('Parse Job Titles').first().json.target_job,\n  email: $('Parse Job Titles').first().json.email,\n  full_name: $('Parse Job Titles').first().json.full_name,\n  cv_improvement: $('Parse CV Improvement').first().json.cv_improvement\n};\n\nfor (const item of allItems) {\n  const jobs = item.json.jobs_results || [];\n  for (const job of jobs) {\n    const key = job.job_id || (job.title + job.company_name);\n    if (!seen.has(key)) {\n      seen.add(key);\n      allJobs.push(job);\n    }\n  }\n}\n\nif (allJobs.length === 0) {\n  return [{ json: { ...prevData, no_jobs: true } }];\n}\n\nreturn allJobs.slice(0, 30).map(job => ({\n  json: { ...job, ...prevData }\n}));"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2096,
        0
      ],
      "id": "4465e1a4-4260-4f68-a6a4-2f32a5d38b25",
      "name": "Extract Job "
    },
    {
      "parameters": {
        "jsCode": "const data = $input.first().json;\nconst targetJob = data.target_job || '';\nconst location = data.target_location || 'Indonesia';\nconst titles = data.candidate_profile?.preferred_job_titles || [];\n\nconst queries = [\n  `${targetJob} ${location}`,\n  `${titles[1] || targetJob} ${location}`,\n  `${titles[2] || targetJob} ${location}`,\n  `${titles[3] || targetJob} ${location}`,\n  `${titles[4] || 'lowongan ' + targetJob} ${location}`\n];\n\nconst unique = [...new Set(queries.map(q => q.trim()))];\n\nreturn unique.map(q => ({\n  json: { ...data, search_query: q }\n}));"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1696,
        0
      ],
      "id": "8bdc5a96-14d5-40a5-8587-a82b6b2a030b",
      "name": "Generate Queries"
    }
  ],
  "connections": {
    "Webhook": {
      "main": [
        [
          {
            "node": "Resume Screening AI",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Resume Screening AI": {
      "main": [
        [
          {
            "node": "Parse Resume",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Resume": {
      "main": [
        [
          {
            "node": "Generate Job Titles AI",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse CV Improvement": {
      "main": [
        [
          {
            "node": "Generate Queries",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google_jobs search": {
      "main": [
        [
          {
            "node": "Extract Job ",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Loop Over Items": {
      "main": [
        [],
        [
          {
            "node": "Job Scoring AI ",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Job Scoring AI ": {
      "main": [
        [
          {
            "node": "Parse Job Scoring",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Job Scoring": {
      "main": [
        [
          {
            "node": "Filter Job",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter Job": {
      "main": [
        [
          {
            "node": "Cover Latter AI",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Cover Latter AI": {
      "main": [
        [
          {
            "node": "Final Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Final Data": {
      "main": [
        [
          {
            "node": "Create a row",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create a row": {
      "main": [
        [
          {
            "node": "Loop Over Items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "Resume Screening AI",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model1": {
      "ai_languageModel": [
        [
          {
            "node": "Generate Job Titles AI",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model2": {
      "ai_languageModel": [
        [
          {
            "node": "Job Scoring AI ",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model3": {
      "ai_languageModel": [
        [
          {
            "node": "Cover Latter AI",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Generate Job Titles AI": {
      "main": [
        [
          {
            "node": "Parse Job Titles",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Job Titles": {
      "main": [
        [
          {
            "node": "CV Impovement",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "CV Impovement": {
      "main": [
        [
          {
            "node": "Parse CV Improvement",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model4": {
      "ai_languageModel": [
        [
          {
            "node": "CV Impovement",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Extract Job ": {
      "main": [
        [
          {
            "node": "Loop Over Items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate Queries": {
      "main": [
        [
          {
            "node": "Google_jobs search",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1",
    "binaryMode": "separate"
  }
}

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.

Pro

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

About this workflow

ApplyIQ. Uses chainLlm, n8n-nodes-serpapi, supabase, lmChatOpenAi. Webhook trigger; 22 nodes.

Source: https://github.com/rizkynandapr/applyiq-web/blob/main/n8n/ApplyIQ-workflow.json — 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

leads. Uses supabase, gmail, formTrigger, httpRequest. Webhook trigger; 62 nodes.

Supabase, Gmail, Form Trigger +13
AI & RAG

Content Creator. Uses lmChatOpenAi, httpRequest, supabase, outputParserStructured. Webhook trigger; 22 nodes.

OpenAI Chat, HTTP Request, Supabase +3
AI & RAG

Smart Select Multi Tool Agent. Uses git, executeCommand, chainLlm, lmChatOpenAi. Webhook trigger; 21 nodes.

Git, Execute Command, Chain Llm +2
AI & RAG

InsightsLM - Podcast Generation. Uses executeCommand, supabase, chainLlm, lmChatOpenAi. Webhook trigger; 21 nodes.

Execute Command, Supabase, Chain Llm +3
AI & RAG

IA Professor de Espanhol de Tecnologia (Corrigido v2). Uses supabase, crypto, agent, lmChatOpenAi. Webhook trigger; 18 nodes.

Supabase, Crypto, Agent +4