Automate resume screening with AI-powered analysis that scores candidates, summarizes fit, and provides structured insights.
Streamline your recruitment process with this CV screening workflow. It downloads resumes from URLs, extracts text from PDFs, and uses OpenAI's structured output to analyze candidate fit against job descriptions. Returns a matching percentage, summary of suitability, and detailed reasons why candidates do or don't fit the role - perfect for HR teams handling high volumes of applications.
{
"meta": {
"instanceId": "6a2a7715680b8313f7cb4676321c5baa46680adfb913072f089f2766f42e43bd"
},
"nodes": [
{
"parameters": {
"content": "## Template by Harshith Vaddiparthy\n\n\n**Learn to Build AI Automations**\nMaster n8n, AI agents, and no-code automation in my comprehensive course.\n→ harshith.com/vibecode\n\n\n**Content Automation Consulting**\nI help businesses automate video creation, social media, blogs, and newsletters.\n→ harshith.com/meet\n\n\n**Connect with me**\n→ linkedin.com/in/harshith-vaddiparthy",
"height": 310,
"width": 260,
"color": 5
},
"id": "promo-sticky-note",
"name": "Sticky Note - Credits",
"type": "n8n-nodes-base.stickyNote",
"position": [
-800,
-500
],
"typeVersion": 1
},
{
"id": "0f3b39af-2802-462c-ac54-a7bccf5b78c5",
"name": "Extract Document PDF",
"type": "n8n-nodes-base.extractFromFile",
"position": [
520,
400
],
"parameters": {
"options": {},
"operation": "pdf"
},
"typeVersion": 1,
"alwaysOutputData": false
},
{
"id": "6f76e3a6-a3be-4f9f-a0db-3f002eafc2ad",
"name": "Download File",
"type": "n8n-nodes-base.httpRequest",
"position": [
340,
400
],
"parameters": {
"url": "={{ $json.file_url }}",
"options": {}
},
"typeVersion": 4.2
},
{
"id": "2c4e0b0f-28c7-48f5-b051-6e909ac878d2",
"name": "When clicking 'Test workflow'",
"type": "n8n-nodes-base.manualTrigger",
"position": [
-20,
400
],
"parameters": {},
"typeVersion": 1
},
{
"id": "a70d972b-ceb4-4f4d-8737-f0be624d6234",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
120,
280
],
"parameters": {
"width": 187,
"height": 80,
"content": "**Add direct link to CV and Job description**"
},
"typeVersion": 1
},
{
"id": "9fdff1be-14cf-4167-af2d-7c5e60943831",
"name": "Sticky Note - Setup",
"type": "n8n-nodes-base.stickyNote",
"position": [
-500,
140
],
"parameters": {
"color": 7,
"width": 280,
"height": 300,
"content": "### Setup\n\n1. **Download File**: Fetch the CV using its direct URL.\n2. **Extract Data**: Use N8N's PDF extraction to retrieve text from the CV.\n3. **Send to OpenAI**: POST to OpenAI's API with CV data and job description using JSON Schema for structured response.\n4. **Parse Results**: Extract the structured analysis for further use."
},
"typeVersion": 1
},
{
"id": "051d8cb0-2557-4e35-9045-c769ec5a34f9",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
660,
280
],
"parameters": {
"width": 187,
"height": 80,
"content": "**Replace OpenAI connection**"
},
"typeVersion": 1
},
{
"id": "865f4f69-e13d-49c1-8bb4-9f98facbf75c",
"name": "OpenAI - Analyze CV",
"type": "n8n-nodes-base.httpRequest",
"position": [
700,
400
],
"parameters": {
"url": "=https://api.openai.com/v1/chat/completions",
"method": "POST",
"options": {},
"jsonBody": "={\n \"model\": \"gpt-4o-mini\",\n \"messages\": [\n {\n \"role\": \"system\",\n \"content\": \"{{ $('Set Variables').item.json.prompt }}\"\n },\n {\n \"role\": \"user\",\n \"content\": {{ JSON.stringify(encodeURIComponent($json.text))}}\n }\n ],\n \"response_format\":{ \"type\": \"json_schema\", \"json_schema\": {{ $('Set Variables').item.json.json_schema }}\n\n }\n }",
"sendBody": true,
"specifyBody": "json",
"authentication": "predefinedCredentialType",
"nodeCredentialType": "openAiApi"
},
"credentials": {
"openAiApi": {
"id": "YOUR_OPENAI_CREDENTIAL_ID",
"name": "OpenAI"
}
},
"typeVersion": 4.2
},
{
"id": "68b7fc08-506d-4816-9a8f-db7ab89e4589",
"name": "Set Variables",
"type": "n8n-nodes-base.set",
"position": [
160,
400
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "83274f6f-c73e-4d5e-946f-c6dfdf7ed1c4",
"name": "file_url",
"type": "string",
"value": "YOUR_CV_FILE_URL"
},
{
"id": "6e44f3e5-a0df-4337-9f7e-7cfa91b3cc37",
"name": "job_description",
"type": "string",
"value": "Paste your job description here. Include requirements, responsibilities, and ideal candidate profile."
},
{
"id": "c597c502-9a3c-48e6-a5f5-8a2a8be7282c",
"name": "prompt",
"type": "string",
"value": "You are a recruiter at a recruiting agency. You are strict and pay extra attention to details in a resume. You assess any resume attentively and critically. If the candidate is a job hopper, you notice that and flag it. Return 4 things: 1. Percentage (10% step) of matching candidate resume with job. 2. Short summary - use simple language and be concise. Provide final decision based on matching percentage and candidate skills vs job requirements. 3. Summary of why this candidate suits this job. 4. Summary of why this candidate doesn't suit this job."
},
{
"id": "1884eed1-9111-4ce1-8d07-ed176611f2d8",
"name": "json_schema",
"type": "string",
"value": "{ \"name\": \"candidate_evaluation\", \"description\": \"Structured data for evaluating a candidate based on experience and fit\", \"strict\": true, \"schema\": { \"type\": \"object\", \"properties\": { \"percentage\": { \"type\": \"integer\", \"description\": \"Overall suitability percentage score for the candidate\" }, \"summary\": { \"type\": \"string\", \"description\": \"A brief summary of the candidate's experience, personality, and any notable strengths or concerns\" }, \"reasons-suit\": { \"type\": \"array\", \"items\": { \"type\": \"object\", \"properties\": { \"name\": { \"type\": \"string\", \"description\": \"Title of the strength or reason for suitability\" }, \"text\": { \"type\": \"string\", \"description\": \"Description of how this experience or skill matches the job requirements\" } }, \"required\": [\"name\", \"text\"], \"additionalProperties\": false }, \"description\": \"List of reasons why the candidate is suitable for the position\" }, \"reasons-notsuit\": { \"type\": \"array\", \"items\": { \"type\": \"object\", \"properties\": { \"name\": { \"type\": \"string\", \"description\": \"Title of the concern or reason for unsuitability\" }, \"text\": { \"type\": \"string\", \"description\": \"Description of how this factor may not align with the job requirements\" } }, \"required\": [\"name\", \"text\"], \"additionalProperties\": false }, \"description\": \"List of reasons why the candidate may not be suitable for the position\" } }, \"required\": [\"percentage\", \"summary\", \"reasons-suit\", \"reasons-notsuit\"], \"additionalProperties\": false } }"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "22dedac7-c44b-430f-b9c7-57d0c55328fa",
"name": "Parsed JSON",
"type": "n8n-nodes-base.set",
"position": [
880,
400
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "83274f6f-c73e-4d5e-946f-c6dfdf7ed1c4",
"name": "json_parsed",
"type": "object",
"value": "={{ JSON.parse($json.choices[0].message.content) }}"
}
]
}
},
"typeVersion": 3.4
}
],
"pinData": {},
"connections": {
"Download File": {
"main": [
[
{
"node": "Extract Document PDF",
"type": "main",
"index": 0
}
]
]
},
"Set Variables": {
"main": [
[
{
"node": "Download File",
"type": "main",
"index": 0
}
]
]
},
"OpenAI - Analyze CV": {
"main": [
[
{
"node": "Parsed JSON",
"type": "main",
"index": 0
}
]
]
},
"Extract Document PDF": {
"main": [
[
{
"node": "OpenAI - Analyze CV",
"type": "main",
"index": 0
}
]
]
},
"When clicking 'Test workflow'": {
"main": [
[
{
"node": "Set Variables",
"type": "main",
"index": 0
}
]
]
}
}
}Copy this JSON and import it into n8n via Settings → Import from File/URL → Paste JSON