Comparaison des profils LinkedIn avec les descriptions de postes via Groq AI et GhostGenius
Ceci est unMiscellaneous, AI Summarization, Multimodal AIworkflow d'automatisation du domainecontenant 17 nœuds.Utilise principalement des nœuds comme If, Set, Code, Merge, Webhook. Comparer l'adéquation entre un profil LinkedIn et une offre d'emploi avec Groq AI et GhostGenius
- •Point de terminaison HTTP Webhook (généré automatiquement par n8n)
- •Peut nécessiter les informations d'identification d'authentification de l'API cible
Nœuds utilisés (17)
Catégorie
{
"meta": {
"instanceId": "834bc6c387a1c56d0622a24b912577f9e6d66c5873f4e6426166054eb488d8fc",
"templateCredsSetupCompleted": true
},
"nodes": [
{
"id": "99132e0e-7083-49c2-822f-2cb10ac289b7",
"name": "Modèle de chat Groq4",
"type": "@n8n/n8n-nodes-langchain.lmChatGroq",
"position": [
3200,
-360
],
"parameters": {
"model": "moonshotai/kimi-k2-instruct",
"options": {
"temperature": 0.5
}
},
"credentials": {
"groqApi": {
"id": "MObjm2yYpur8db8w",
"name": "Groq account 3"
}
},
"typeVersion": 1
},
{
"id": "09193e72-e51f-450d-bc0a-d6a8367f66ec",
"name": "Obtenir les détails du profil",
"type": "n8n-nodes-base.httpRequest",
"position": [
1780,
-700
],
"parameters": {
"url": "https://api.ghostgenius.fr/v2/profile",
"options": {},
"sendQuery": true,
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"queryParameters": {
"parameters": [
{
"name": "url",
"value": "={{ $json.body.LinkedIn_CV }}"
}
]
}
},
"credentials": {
"httpBasicAuth": {
"id": "MvNMvU3oWO5seyjn",
"name": "linkedin-proof-of-concept-tool-CV"
},
"httpHeaderAuth": {
"id": "StvB6gMppbwtX437",
"name": "linkedin"
}
},
"typeVersion": 4.2
},
{
"id": "c3ec14e5-245f-4624-890d-a958d1d05f86",
"name": "Obtenir les détails du poste",
"type": "n8n-nodes-base.httpRequest",
"position": [
1780,
-460
],
"parameters": {
"url": "https://api.ghostgenius.fr/v2/job",
"options": {},
"sendQuery": true,
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"queryParameters": {
"parameters": [
{
"name": "url",
"value": "={{ $json.body.LinkedIn_JD }}"
}
]
}
},
"credentials": {
"httpBasicAuth": {
"id": "MvNMvU3oWO5seyjn",
"name": "linkedin-proof-of-concept-tool-CV"
},
"httpHeaderAuth": {
"id": "StvB6gMppbwtX437",
"name": "linkedin"
}
},
"typeVersion": 4.2
},
{
"id": "8c262246-2fc0-4d89-890f-aa7e7c3cd53f",
"name": "Webhook (GET Détails du formulaire)",
"type": "n8n-nodes-base.webhook",
"position": [
940,
-560
],
"webhookId": "fb607944-5e45-4dab-b805-7d0701e5eaa9",
"parameters": {
"path": "linkedin",
"options": {
"allowedOrigins": "*"
},
"httpMethod": "POST",
"responseMode": "responseNode",
"authentication": "basicAuth"
},
"credentials": {
"httpBasicAuth": {
"id": "MvNMvU3oWO5seyjn",
"name": "linkedin-proof-of-concept-tool-CV"
}
},
"typeVersion": 2
},
{
"id": "760b8a86-745c-47c6-8bea-1a9f8ec11da1",
"name": "Construire le CV",
"type": "n8n-nodes-base.set",
"position": [
2060,
-700
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "622960b0-c560-43c1-acac-d690fe74c8e4",
"name": "headline",
"type": "string",
"value": "={{ $json.headline }}"
},
{
"id": "301956ad-6219-4d8a-9a00-e45cb4a8c941",
"name": "is_premium",
"type": "boolean",
"value": "={{ $json.is_premium }}"
},
{
"id": "01f8fa3c-75c6-4b57-9950-3d8a95fe1082",
"name": "is_creator",
"type": "boolean",
"value": "={{ $json.is_creator }}"
},
{
"id": "9a17e0b8-958e-40cf-ba05-665f1c5e418e",
"name": "geo",
"type": "object",
"value": "={{ $json.geo }}"
},
{
"id": "b77401d1-9ab1-41e2-870c-f8f43c4e141e",
"name": "is_hiring",
"type": "boolean",
"value": "={{ $json.is_hiring }}"
},
{
"id": "4a394eb9-8073-4e82-b65d-bd234ebec960",
"name": "summary",
"type": "string",
"value": "={{ $json.summary }}"
},
{
"id": "73f33e27-2803-43c3-ac79-c1f9c700bc54",
"name": "languages",
"type": "array",
"value": "={{ $json.languages }}"
},
{
"id": "f1628de0-e39a-4862-9732-7f65bb844216",
"name": "experiences",
"type": "array",
"value": "={{ $json.experiences }}"
},
{
"id": "6289a835-92b9-48a7-bce9-04abab217080",
"name": "skills",
"type": "array",
"value": "={{ $json.skills }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "cdba39fe-360b-4076-b1ba-295a7d8a7425",
"name": "Combiner_CV",
"type": "n8n-nodes-base.aggregate",
"position": [
2340,
-660
],
"parameters": {
"options": {},
"aggregate": "aggregateAllItemData",
"destinationFieldName": "CV"
},
"typeVersion": 1
},
{
"id": "1e7eb8b8-e895-4022-84a0-ce23cdfee286",
"name": "Construire l'offre d'emploi",
"type": "n8n-nodes-base.set",
"position": [
2040,
-460
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "8f021bed-f1bb-44ec-b9ec-f5a69f30e25d",
"name": "title",
"type": "string",
"value": "={{ $json.title }}"
},
{
"id": "7438183a-4fac-4b3a-b33a-13872c23bc4b",
"name": "description",
"type": "string",
"value": "={{ $json.description }}"
},
{
"id": "db24b36e-3e74-408f-87f2-f8c2af088167",
"name": "work_remote_allowed",
"type": "boolean",
"value": "={{ $json.work_remote_allowed }}"
},
{
"id": "0f954876-3608-46c3-85ac-c1808b04e056",
"name": "work_place",
"type": "string",
"value": "={{ $json.work_place }}"
},
{
"id": "3c32fe75-1777-49c7-b7c7-003f8a788644",
"name": "listed_at_date",
"type": "string",
"value": "={{ $json.listed_at_date }}"
},
{
"id": "28fc6507-acd1-4e85-a636-4d3b0a6a81e4",
"name": "contract_type",
"type": "string",
"value": "={{ $json.contract_type }}"
},
{
"id": "79d00697-99df-4503-8029-c65c52109cd4",
"name": "company",
"type": "object",
"value": "={{ $json.company }}"
},
{
"id": "374fba18-00d0-4cef-a7dc-018aad986754",
"name": "apply_method.company_apply_url",
"type": "string",
"value": "={{ $json.apply_method.company_apply_url }}"
},
{
"id": "fc5a8073-ea1f-4b36-94bb-6bab1f9203fd",
"name": "hiringTeam",
"type": "string",
"value": "={{ $json.hiringTeam }}"
},
{
"id": "0f3a24dc-7a06-47ef-be43-3aa7b8293609",
"name": "location",
"type": "string",
"value": "={{ $json.location }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "fdeb23f6-f2d7-42cf-b582-2a8dea61d370",
"name": "Combiner_JD",
"type": "n8n-nodes-base.aggregate",
"position": [
2340,
-500
],
"parameters": {
"options": {},
"aggregate": "aggregateAllItemData",
"destinationFieldName": "JD"
},
"typeVersion": 1
},
{
"id": "f4968f34-f4c4-4480-85bc-52c5d60dfe55",
"name": "Comparaison ATS",
"type": "n8n-nodes-base.set",
"position": [
2940,
-600
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "eb3cb6e0-8bac-476a-ae4f-e76c87a1cf6f",
"name": "CV",
"type": "array",
"value": "={{ $json.CV }}"
},
{
"id": "84f7795e-ba27-4982-b6b4-f40676846153",
"name": "JD",
"type": "array",
"value": "={{ $json.JD }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "4cba76a8-a973-4450-8b82-34ccde324f96",
"name": "Fusionner2",
"type": "n8n-nodes-base.merge",
"position": [
2660,
-600
],
"parameters": {
"mode": "combine",
"options": {},
"combineBy": "combineAll"
},
"typeVersion": 3
},
{
"id": "bb684bd3-d9a1-4f01-acd7-a82d977c08ad",
"name": "Répondre à Webhook",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
3980,
-620
],
"parameters": {
"options": {},
"respondWith": "json",
"responseBody": "={{ $json }}"
},
"typeVersion": 1.1
},
{
"id": "56cde4ed-dcaa-4b8b-8432-77304a208867",
"name": "Vérification recruteur",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
3260,
-620
],
"parameters": {
"text": "=Job Description JSON:\n{{ $json.JD.toJsonString()}}\n\nCandidate CV JSON:\n{{ $json.CV.toJsonString()}}\n---\n\nOutput ONLY one JSON object that conforms exactly to the Match_Result schema. All arrays must be included, even if empty. All string values must be in double quotes.",
"options": {
"systemMessage": "=You are an expert ATS evaluator, recruitment assistant, and career advisor. \nYour ONLY task is to analyze the given Job Description (JD) JSON and Candidate CV JSON, \ncompare them, and output a structured JSON matching the `Match_Result` schema below.\n\nImportant Output Rules:\n- Return ONLY valid JSON (nothing else, no prose, no markdown).\n- Always include ALL fields in the schema. If no matches, return an empty array for that field.\n- Use canonicalized keyword tokens for \"matched_keywords\", \"missing_keywords_required\", and \"missing_keywords_nice_to_have\".\n- When a candidate’s CV provides evidence for a skill or requirement but phrases it differently, return the canonical keyword **followed by parentheses** with the CV’s actual wording.\n - Example: `\"Quota carrying experience (Achieved 120% of sales targets as SDR)\"`.\n- Reasoning should be factual ATS‑style notes (explain what is matched/missing).\n- Recommendation = one clear action statement.\n- Optimization tips must be **CV-focused, practical actions** the candidate can take.\n\n---\n\nSchema (must always be returned exactly like this, with all keys):\n\n{\n \"status\": \"core_match | good_match | mismatch\",\n \"reasoning\": [\"string\"],\n \"recommendation\": \"string\",\n \"matched_keywords\": [\"string\"],\n \"missing_keywords_required\": [\"string\"],\n \"missing_keywords_nice_to_have\": [\"string\"],\n \"optimization_tips\": [\"string\"],\n \"location_match\" : [\"boolean\"]\n}\n\n---\n\nDefinitions:\n- \"mismatch\": Candidate fails at least 1 bare minimum requirement from JD (e.g., location, required language, quota-carrying).\n- \"core_match\": Candidate meets all minimums but does not exceed them.\n- \"good_match\": Candidate meets all minimums and shows extra strengths (additional experience, languages, certifications, strong metrics).\n\n---"
},
"promptType": "define",
"hasOutputParser": true
},
"typeVersion": 1.7
},
{
"id": "64629a52-6d90-4068-879b-268001080e7f",
"name": "Si",
"type": "n8n-nodes-base.if",
"position": [
1180,
-560
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "4c3cb62d-3070-4105-8155-d05a08667548",
"operator": {
"type": "string",
"operation": "contains"
},
"leftValue": "={{ $json.body.LinkedIn_CV }}",
"rightValue": "linkedin.com/"
},
{
"id": "ff692e0f-21eb-45fa-96e7-3171588f5e90",
"operator": {
"type": "string",
"operation": "contains"
},
"leftValue": "={{ $json.body.LinkedIn_JD }}",
"rightValue": "linkedin.com/"
}
]
}
},
"typeVersion": 2.2
},
{
"id": "25678030-b9a8-461a-80cb-d26ebd19cc34",
"name": "Nœud d'erreur",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
1560,
-280
],
"parameters": {
"options": {},
"respondWith": "json",
"responseBody": "={\n \"thankYouMessage\": \"<div class='flex flex-col items-center justify-center text-center space-y-4 p-4'><h2 class='text-xl font-bold text-red-600'>Invalid URL</h2><p>The URL you submitted appears to be incorrect or inaccessible.</p><p>Please double-check the link and try again.</p></div>\"\n}"
},
"typeVersion": 1.1
},
{
"id": "d02f55f3-adf4-4219-8b13-4b40d46ea773",
"name": "Message de remerciement",
"type": "n8n-nodes-base.code",
"position": [
3660,
-600
],
"parameters": {
"jsCode": "return items.map(item => {\n let parsed = {};\n\n try {\n // Parse the \"output\" field which is a JSON string\n parsed = JSON.parse(item.json.output);\n } catch (error) {\n parsed = { error: 'Invalid JSON in output field', details: error.message };\n }\n\n function makeList(arr) {\n if (!arr || arr.length === 0) return \"<li>None</li>\";\n return arr.map(x => `<li>${x}</li>`).join(\"\");\n }\n\n const html = `\n <div class=\"flex flex-col items-start justify-start text-left space-y-4 p-4\">\n <h2 class=\"text-xl font-bold\">Analysis Result</h2>\n <p><strong>Status:</strong> ${parsed.status ?? ''}</p>\n <div class=\"text-sm space-y-2\">\n <p><strong>Reasoning:</strong></p>\n <ul class=\"list-disc list-inside text-left\">${makeList(parsed.reasoning)}</ul>\n </div>\n <p><strong>Recommendation:</strong> ${parsed.recommendation ?? ''}</p>\n <div class=\"text-sm space-y-2\">\n <p><strong>Matched Keywords:</strong></p>\n <ul class=\"list-disc list-inside text-left\">${makeList(parsed.matched_keywords)}</ul>\n </div>\n <div class=\"text-sm space-y-2\">\n <p><strong>Missing (Required):</strong></p>\n <ul class=\"list-disc list-inside text-left\">${makeList(parsed.missing_keywords_required)}</ul>\n </div>\n <div class=\"text-sm space-y-2\">\n <p><strong>Missing (Nice to have):</strong></p>\n <ul class=\"list-disc list-inside text-left\">${makeList(parsed.missing_keywords_nice_to_have)}</ul>\n </div>\n <div class=\"text-sm space-y-2\">\n <p><strong>Optimization Tips:</strong></p>\n <ul class=\"list-disc list-inside text-left\">${makeList(parsed.optimization_tips)}</ul>\n </div>\n </div>`;\n\n return {\n json: {\n thankYouMessage: html\n }\n };\n});"
},
"typeVersion": 2
},
{
"id": "d8f8bbeb-3199-43e2-8375-846d657b5ba5",
"name": "Description du workflow (Note adhésive)1",
"type": "n8n-nodes-base.stickyNote",
"position": [
420,
-1160
],
"parameters": {
"width": 440,
"height": 920,
"content": "## 📌 Workflow Description\n\nThis workflow automates **CV vs JD matching** using LinkedIn profile data, job descriptions, and an AI recruiter check. It evaluates a candidate’s CV against a job posting, highlights strengths and gaps, and provides an ATS-style analysis report.\n\n### ✅ Who’s it for\nRecruiters, hiring managers, and job seekers who want an **AI-powered Applicant Tracking System (ATS)** analysis to quickly evaluate the fit between a CV and a job description.\n\n### ⚙️ How it works\n1. The **Webhook** captures the LinkedIn CV and JD URLs.\n2. Two **HTTP Request nodes** fetch profile and job description details.\n3. The workflow **builds structured CV and JD JSON objects** using Set + Aggregate nodes.\n4. A **Merge + ATS Compare** step aligns the CV and JD.\n5. The **Recruiter Check (LLM)** analyzes the alignment using a defined schema.\n6. The **Code node** cleans this JSON, formats it, and generates the ready-to-render HTML summary.\n7. Finally, the **Respond to Webhook** node sends the result back.\n\n### 🔧 Requirements\n* A valid LinkedIn CV/JD scraper API (via GhostGenius here).\n* A Groq account for the LLM step (no keys are hardcoded).\n* An n8n instance (cloud or self-hosted).\n\n### 🎨 How to Customize\n* Adjust the LLM prompt for more specific ATS scoring rules.\n* Change the Code node template to reformat results in plain text, Slack blocks, or PDF.\n* Add integrations (Slack, Gmail, Notion) to automatically distribute candidate/job match reports.\n\n⚠️ Credential Reminder: Do not hardcode sensitive API keys in nodes—always store them securely in n8n credentials."
},
"typeVersion": 1
},
{
"id": "2dc1eb5a-c00f-4039-a317-8cea1880aa68",
"name": "Résultat de l'analyse (Note adhésive)",
"type": "n8n-nodes-base.stickyNote",
"position": [
4240,
-1080
],
"parameters": {
"width": 920,
"height": 940,
"content": "## 📝 Analysis Result\n\n**Status:** mismatch\n\n### Reasoning\n- Candidate location is United States; JD explicitly requires residence in the Netherlands.\n- JD mandates Dutch language fluency; languages array is empty in CV.\n- JD asks for 3-5 years closing sales experience; CV shows 12+ years (exceeds upper bound but not disqualifying).\n\n**Recommendation:** Do not proceed with application until candidate can relocate to the Netherlands and demonstrate Dutch fluency.\n\n### ✅ Matched Keywords\n- Quota carrying experience (10x President’s Club)\n- Closing Sales experience (Account Executive III)\n- Sales experience (Enterprise Account Executive)\n- Consultative selling (Growth Consultant @ HubSpot)\n- Pipeline management (accurate forecasting implied by President’s Club)\n- High performer (10x President’s Club)\n\n### ❌ Missing (Required)\n- Dutch fluency\n- Netherlands residence\n\n### ⚠️ Missing (Nice to have)\n- Mid-market sales experience\n- Inside sales model\n- Inbound selling strategies\n- SMB focus\n\n### 💡 Optimization Tips\n- Add Dutch language proficiency and CEFR level in the Languages section.\n- Change geo location to Amsterdam, Netherlands.\n- Insert a bullet under each sales role specifying inbound/inside sales and mid-market/SMB focus.\n- Include quantified mid-market quota achievements (ARR, number of deals)."
},
"typeVersion": 1
}
],
"pinData": {},
"connections": {
"64629a52-6d90-4068-879b-268001080e7f": {
"main": [
[
{
"node": "09193e72-e51f-450d-bc0a-d6a8367f66ec",
"type": "main",
"index": 0
},
{
"node": "c3ec14e5-245f-4624-890d-a958d1d05f86",
"type": "main",
"index": 0
}
],
[
{
"node": "25678030-b9a8-461a-80cb-d26ebd19cc34",
"type": "main",
"index": 0
}
]
]
},
"4cba76a8-a973-4450-8b82-34ccde324f96": {
"main": [
[
{
"node": "f4968f34-f4c4-4480-85bc-52c5d60dfe55",
"type": "main",
"index": 0
}
]
]
},
"760b8a86-745c-47c6-8bea-1a9f8ec11da1": {
"main": [
[
{
"node": "cdba39fe-360b-4076-b1ba-295a7d8a7425",
"type": "main",
"index": 0
}
]
]
},
"1e7eb8b8-e895-4022-84a0-ce23cdfee286": {
"main": [
[
{
"node": "fdeb23f6-f2d7-42cf-b582-2a8dea61d370",
"type": "main",
"index": 0
}
]
]
},
"cdba39fe-360b-4076-b1ba-295a7d8a7425": {
"main": [
[
{
"node": "4cba76a8-a973-4450-8b82-34ccde324f96",
"type": "main",
"index": 0
}
]
]
},
"fdeb23f6-f2d7-42cf-b582-2a8dea61d370": {
"main": [
[
{
"node": "4cba76a8-a973-4450-8b82-34ccde324f96",
"type": "main",
"index": 1
}
]
]
},
"25678030-b9a8-461a-80cb-d26ebd19cc34": {
"main": [
[]
]
},
"f4968f34-f4c4-4480-85bc-52c5d60dfe55": {
"main": [
[
{
"node": "56cde4ed-dcaa-4b8b-8432-77304a208867",
"type": "main",
"index": 0
}
]
]
},
"56cde4ed-dcaa-4b8b-8432-77304a208867": {
"main": [
[
{
"node": "d02f55f3-adf4-4219-8b13-4b40d46ea773",
"type": "main",
"index": 0
}
]
]
},
"99132e0e-7083-49c2-822f-2cb10ac289b7": {
"ai_languageModel": [
[
{
"node": "56cde4ed-dcaa-4b8b-8432-77304a208867",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"d02f55f3-adf4-4219-8b13-4b40d46ea773": {
"main": [
[
{
"node": "bb684bd3-d9a1-4f01-acd7-a82d977c08ad",
"type": "main",
"index": 0
}
]
]
},
"c3ec14e5-245f-4624-890d-a958d1d05f86": {
"main": [
[
{
"node": "1e7eb8b8-e895-4022-84a0-ce23cdfee286",
"type": "main",
"index": 0
}
]
]
},
"09193e72-e51f-450d-bc0a-d6a8367f66ec": {
"main": [
[
{
"node": "760b8a86-745c-47c6-8bea-1a9f8ec11da1",
"type": "main",
"index": 0
}
]
]
},
"8c262246-2fc0-4d89-890f-aa7e7c3cd53f": {
"main": [
[
{
"node": "64629a52-6d90-4068-879b-268001080e7f",
"type": "main",
"index": 0
}
]
]
}
}
}Comment utiliser ce workflow ?
Copiez le code de configuration JSON ci-dessus, créez un nouveau workflow dans votre instance n8n et sélectionnez "Importer depuis le JSON", collez la configuration et modifiez les paramètres d'authentification selon vos besoins.
Dans quelles scénarios ce workflow est-il adapté ?
Avancé - Divers, Résumé IA, IA Multimodale
Est-ce payant ?
Ce workflow est entièrement gratuit et peut être utilisé directement. Veuillez noter que les services tiers utilisés dans le workflow (comme l'API OpenAI) peuvent nécessiter un paiement de votre part.
Workflows recommandés
Stephan Koning
@reklaimAccount Executive by day , Noco builder for fun at night and always a proud dad of Togo the Samoyed.
Partager ce workflow