This workflow follows the Agent → Anthropic 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 →
{
"updatedAt": "2026-06-03T10:11:59.136Z",
"createdAt": "2026-05-25T13:51:11.721Z",
"id": "olgL8wb7nrJumkct",
"name": "Jobby - LinkedIn 2 Notion",
"description": null,
"active": true,
"isArchived": false,
"nodes": [
{
"parameters": {
"promptType": "define",
"text": "=Company: {{ $('CV Factory').item.json.query.company }}\njon title : {{ $('CV Factory').item.json.query.job_title }}\njob Url: {{ $('CV Factory').item.json.query.job_url }}\nDescription: {{ $('CV Factory').item.json.query.job_description }}\n",
"options": {
"systemMessage": "=# Tu es Jobby 3.0\nL'assistant strat\u00e9gique de recherche d'imploi pour Julien. \n\n## Identity & Tone\nTon ton est neutre, analytique et orient\u00e9 r\u00e9sultats, comme un coach en recrutement senior. Ta valeur ajout\u00e9e r\u00e9side dans la d\u00e9tection pr\u00e9cise des \u00e9carts techniques et organisationnels.\n\n## Purpose\n\u00c9valuer l'ad\u00e9quation entre le profil de Julien (Solutions Engineer, expert automation/IA) et une offre d'emploi sp\u00e9cifique, puis g\u00e9n\u00e9rer le CV Markdown optimal pour maximiser le score ATS.\n\n## Context & Data\nPour r\u00e9aliser cette analyse et cette g\u00e9n\u00e9ration, voici les donn\u00e9es consolid\u00e9es issues du syst\u00e8me :\n\n## 1. Fiche de Poste Aspir\u00e9e (LinkedIn)\n{{ $json.job_description }}\n\n## 2. Directives de Positionnement (La Graine)\n- Baseline attendue : {{ $json.seed_baseline }}\n- Consignes de filtrage : {{ $json.seed_directives }}\n\n## 3. Graphe de Comp\u00e9tences & Exp\u00e9riences (CV Atomique)\n{{ $json.cv_master_payload }}\n\n# Evaluation Criteria\n1. Score (1-10) : Bas\u00e9 strictement sur l'ad\u00e9quation technique, l'exp\u00e9rience pass\u00e9e et le niveau de s\u00e9niorit\u00e9 requis.\n2. Gap Analysis : Identifier les technologies ou m\u00e9thodologies manquantes sans fioritures.\n3. Reskilling & Tailoring : S\u00e9lectionner uniquement les 4 derni\u00e8res activit\u00e9s du CV Atomique et adapter subtilement les puces d'impact en utilisant les mots-cl\u00e9s de la fiche de poste et l'orientation de la Graine.\n\n**CRITICAL NOTION LIMIT**: Le texte dans `\"generated_cv_markdown\"` doit \u00eatre concis et synth\u00e9tique. Chaque section `(Summary, Exp\u00e9rience, etc.)`` doit \u00eatre s\u00e9par\u00e9e par le caract\u00e8re \"|\" pour nous permettre de d\u00e9couper le texte apr\u00e8s coup et \u00e9viter de d\u00e9passer la limite de 2000 caract\u00e8res par bloc impos\u00e9e par l'API Notion.\n\n# Output Format (STRICT JSON)\nR\u00e9ponds exclusivement par un objet JSON valide. Le CV au format Markdown et en anglais doit \u00eatre enti\u00e8rement encapsul\u00e9 dans la cl\u00e9 \"generated_cv_markdown\". Ne mets pas de balises de code (comme `markdown`) \u00e0 l'int\u00e9rieur du JSON.\n\n```{\n \"domain\": \"string (ex: Generative AI, Automation, API Management)\",\n \"job_title\": \"string (Titre exact)\",\n \"company\": \"string\",\n \"match_score\": number,\n \"quick_summary\": \"string (MAX 150 caract\u00e8res)\",\n \"analysis_pros\": \"string (Points forts techniques et m\u00e9tier - Max 800 caract\u00e8res)\",\n \"analysis_cons\": \"string (Points de friction et manques - Max 800 caract\u00e8res)\",\n \"action_plan\": \"string (Conseil imm\u00e9diat pour la candidature - Max 400 caract\u00e8res)\",\n \"generated_cv_markdown\": \"string (Le CV V2.0 complet en Markdown, structur\u00e9 avec l'Aside de d\u00e9part contenant la baseline, puis les 4 derniers jobs adapt\u00e9s aux crit\u00e8res ATS)\"\n}"
}
},
"type": "@n8n/n8n-nodes-langchain.agent",
"typeVersion": 3.1,
"position": [
352,
48
],
"id": "b28e3fb0-c3bf-42f4-9a63-a95c5c8d4055",
"name": "AI Agent",
"onError": "continueErrorOutput"
},
{
"parameters": {
"modelName": "models/gemini-2.5-flash-lite",
"options": {}
},
"type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
"typeVersion": 1.1,
"position": [
352,
320
],
"id": "c09c542b-80ca-4d47-a542-15fc14eabccd",
"name": "Google Gemini Chat Model",
"credentials": {
"googlePalmApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"model": {
"__rl": true,
"mode": "list",
"value": "claude-sonnet-4-6",
"cachedResultName": "Claude Sonnet 4.6"
},
"options": {}
},
"type": "@n8n/n8n-nodes-langchain.lmChatAnthropic",
"typeVersion": 1.4,
"position": [
-544,
384
],
"id": "29dd6f16-98a6-48f5-ad0b-7a76b5eb335a",
"name": "Anthropic Chat Model",
"credentials": {
"anthropicApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"jsCode": "// 1. On r\u00e9cup\u00e8re le texte g\u00e9n\u00e9r\u00e9 par l'Agent\nconst text = $json.output || \"\"; \nconst match = text.match(/\\{[\\s\\S]*\\}/);\n\nif (match) {\n try {\n // On parse uniquement le bloc JSON trouv\u00e9\n const data = JSON.parse(match);\n\n // Helper pour les tableaux Notion (Multi-select)\n const toSimpleArray = (val) => {\n if (!val) return [];\n const rawItems = Array.isArray(val) ? val : val.toString().split(/[|,\\/&]|\\band\\b/);\n return rawItems.map(i => i.trim()).filter(i => i.length > 1);\n };\n\n // 2. On reconstruit l'objet propre pour alimenter le n\u0153ud \"Update Notion\"\n return [{\n json: {\n domain: toSimpleArray(data.domain),\n category: toSimpleArray(data.category || data.job_title),\n job_title: data.job_title || \"Position inconnue\",\n company: data.company || \"Entreprise inconnue\",\n score: parseInt(data.match_score) || 0,\n status: \"To review\",\n summary: data.quick_summary || \"Analyse termin\u00e9e\",\n analysis_pros: data.analysis_pros || \"N/A\",\n analysis_cons: data.analysis_cons || \"N/A\",\n action_plan: data.action_plan || \"N/A\",\n generated_cv_markdown: data.generated_cv_markdown || \"\",\n response_date: new Date().toISOString().split('T')\n }\n }];\n\n } catch (e) {\n return [{ json: { error: \"JSON Parsing Error\", message: e.message, raw: text.substring(0, 200) } }];\n }\n}\n\nreturn [{ json: { error: \"No JSON found in AI output\", raw: text.substring(0, 100) } }];"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
704,
-48
],
"id": "bc6d9e53-7c47-4b19-97f4-e78868ea7cdd",
"name": "JSON Cleaner",
"onError": "continueErrorOutput"
},
{
"parameters": {
"resource": "database",
"databaseId": {
"__rl": true,
"value": "5ea1407d-50b4-4527-bd86-21f3c58535fa",
"mode": "list",
"cachedResultName": "Complete Resume DB",
"cachedResultUrl": "https://www.notion.so/5ea1407d50b44527bd8621f3c58535fa"
}
},
"type": "n8n-nodes-base.notion",
"typeVersion": 2.2,
"position": [
-320,
48
],
"id": "98b735c7-3087-4ff3-83a7-c749cba35b8b",
"name": "Get CV data",
"credentials": {
"notionApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"resource": "database",
"databaseId": {
"__rl": true,
"value": "642d04c9-1c1f-4c01-a4d3-89822f02556b",
"mode": "list",
"cachedResultName": "CV Seeds",
"cachedResultUrl": "https://www.notion.so/642d04c91c1f4c01a4d389822f02556b"
}
},
"type": "n8n-nodes-base.notion",
"typeVersion": 2.2,
"position": [
-96,
48
],
"id": "1c3e6440-cbf2-472c-ab63-959a496a7e6f",
"name": "CV Seed",
"credentials": {
"notionApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"resource": "databasePage",
"databaseId": {
"__rl": true,
"value": "127bad1f-b25a-4b6b-8eec-7b342e3aa504",
"mode": "list",
"cachedResultName": "Linked Detector",
"cachedResultUrl": "https://www.notion.so/127bad1fb25a4b6b8eec7b342e3aa504"
},
"title": "LinkedIn Detector",
"simple": false,
"propertiesUi": {
"propertyValues": [
{
"key": "Job Title|title",
"title": "={{ $json.job_title || \"Nouvelle offre LinkedIn (Titre non extrait)\" }}\n"
},
{
"key": "category|multi_select",
"multiSelectValue": "={{ $json.category }}"
},
{
"key": "URL|url",
"urlValue": "={{ $('CV Factory').item.json.query.job_url }}"
},
{
"key": "Match Score|number",
"numberValue": "={{ $json.score }}"
},
{
"key": "Status|status",
"statusValue": "={{ $json.status }}"
},
{
"key": "Company|select",
"selectValue": "={{ $json.company }}"
},
{
"key": "domain|multi_select",
"multiSelectValue": "={{ $json.domain }}S"
},
{
"key": "analysis|rich_text",
"textContent": "={{ $json.summary }}"
}
]
},
"blockUi": {
"blockValues": [
{
"type": "heading_1",
"textContent": "Analyse compl\u00e8te"
},
{
"textContent": "={{ $json.summary }}"
},
{
"type": "heading_2",
"textContent": "Pros"
},
{
"textContent": "={{ $json.analysis_pros }}"
},
{
"type": "heading_2",
"textContent": "Cons"
},
{
"textContent": "={{ $json.analysis_cons }}"
},
{
"type": "heading_2",
"textContent": "Action Plan"
},
{
"textContent": "={{ $json.action_plan }}"
},
{
"type": "heading_1",
"textContent": "Raw job description "
},
{
"type": "toggle",
"textContent": "=About the job"
},
{
"textContent": "={{ $('CV Factory').item.json.query.job_description }}"
}
]
},
"options": {
"iconType": "emoji",
"icon": "\ud83c\udd95"
}
},
"type": "n8n-nodes-base.notion",
"typeVersion": 2.2,
"position": [
928,
-48
],
"id": "a801be3c-190f-4c32-a564-050e9ba194f2",
"name": "update prospect",
"retryOnFail": false,
"executeOnce": false,
"credentials": {
"notionApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"path": "cv-factory",
"authentication": "headerAuth",
"options": {
"responseData": "{\"status\": \"processing\"}"
}
},
"type": "n8n-nodes-base.webhook",
"typeVersion": 2.1,
"position": [
-544,
48
],
"id": "4f70d8ad-1003-4506-b630-04d85c94d2e1",
"name": "CV Factory",
"credentials": {
"httpHeaderAuth": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"jsCode": "// 1. R\u00e9cup\u00e9ration des lignes du CV Atomique\nlet cvRows = [];\ntry {\n cvRows = $('Get CV data').all();\n} catch (e) {\n cvRows = [];\n}\n\n// Extraction universelle pour le CV\nconst cleanExperiences = cvRows.map((row, index) => {\n const props = row.json?.properties || {};\n \n // Fonction helper pour extraire le texte brut d'une propri\u00e9t\u00e9 Notion, quel que soit son type (title ou rich_text)\n const extractText = (propObj) => {\n if (!propObj) return \"\";\n const arr = propObj.rich_text || propObj.title || [];\n return arr?.plain_text || propObj.value || \"\";\n };\n\n // On scanne dynamiquement les variantes de noms de colonnes possibles\n const entreprise = extractText(props.Entreprise) || extractText(props.Company) || \"Entreprise \" + (index + 1);\n const poste = extractText(props.Poste) || extractText(props.Role) || \"Solutions Engineer\";\n const description = extractText(props.Description) || \"\";\n const dates = extractText(props.Dates) || extractText(props.Date) || \"\";\n\n return `### ${poste} chez ${entreprise} (${dates})\\n${description}`;\n}).join(\"\\n\\n\");\n\n// 2. R\u00e9cup\u00e9ration et isolation de la Graine UNIQUE\nlet seedBaseline = \"Solutions Engineer\";\nlet seedDirectives = \"Standard tailoring\";\n\ntry {\n const allSeeds = $('CV Seed').all();\n // On cherche la graine active via la checkbox, sinon on prend la premi\u00e8re disponible\n const selectedSeedItem = allSeeds.find(item => {\n const props = item.json?.properties || {};\n // G\u00e8re la checkbox Notion (qu'elle s'appelle Active ou active)\n const checkObj = props.Active || props.active;\n return checkObj?.checkbox === true;\n }) || allSeeds;\n\n if (selectedSeedItem && selectedSeedItem.json?.properties) {\n const sProps = selectedSeedItem.json.properties;\n \n const extractSeedText = (propObj) => {\n if (!propObj) return null;\n const arr = propObj.title || propObj.rich_text || [];\n return arr?.plain_text || null;\n };\n\n seedBaseline = extractSeedText(sProps.Baseline) || extractSeedText(sProps.baseline) || seedBaseline;\n seedDirectives = extractSeedText(sProps.Directives) || extractSeedText(sProps.directives) || seedDirectives;\n }\n} catch (e) {\n // En cas de probl\u00e8me de lecture de la graine, on garde les valeurs par d\u00e9faut pour ne pas bloquer le flux\n}\n\n// 3. Payload plat final garanti sans crash\nreturn [{\n json: {\n job_description: $json.job_description || \"Pas de description\",\n seed_baseline: seedBaseline,\n seed_directives: seedDirectives,\n cv_master_payload: cleanExperiences || \"CV Master vide\"\n }\n}];"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
128,
48
],
"id": "6fc7730a-c6d3-48db-919d-c700c1c6bed1",
"name": "Clean CV"
},
{
"parameters": {
"errorMessage": "={{ $('AI Agent').item.json.error }}"
},
"type": "n8n-nodes-base.stopAndError",
"typeVersion": 1,
"position": [
704,
144
],
"id": "0334fb31-bc67-410f-89bc-7e0de9ccaa43",
"name": "Stop and Error"
}
],
"connections": {
"Google Gemini Chat Model": {
"ai_languageModel": [
[
{
"node": "AI Agent",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"AI Agent": {
"main": [
[
{
"node": "JSON Cleaner",
"type": "main",
"index": 0
}
],
[
{
"node": "Stop and Error",
"type": "main",
"index": 0
}
]
]
},
"Anthropic Chat Model": {
"ai_languageModel": [
[]
]
},
"JSON Cleaner": {
"main": [
[
{
"node": "update prospect",
"type": "main",
"index": 0
}
],
[]
]
},
"Get CV data": {
"main": [
[
{
"node": "CV Seed",
"type": "main",
"index": 0
}
]
]
},
"CV Seed": {
"main": [
[
{
"node": "Clean CV",
"type": "main",
"index": 0
}
]
]
},
"update prospect": {
"main": [
[],
[]
]
},
"CV Factory": {
"main": [
[
{
"node": "Get CV data",
"type": "main",
"index": 0
}
]
]
},
"Clean CV": {
"main": [
[
{
"node": "AI Agent",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1",
"binaryMode": "separate",
"timeSavedMode": "fixed",
"timezone": "Europe/Paris",
"callerPolicy": "workflowsFromSameOwner",
"availableInMCP": false
},
"staticData": null,
"meta": {
"templateCredsSetupCompleted": true
},
"versionId": "1f38b6c8-cab7-4bb2-a645-f6c092f23ca5",
"activeVersionId": "1f38b6c8-cab7-4bb2-a645-f6c092f23ca5",
"versionCounter": 167,
"triggerCount": 1,
"shared": [
{
"updatedAt": "2026-05-25T13:51:11.748Z",
"createdAt": "2026-05-25T13:51:11.748Z",
"role": "workflow:owner",
"workflowId": "olgL8wb7nrJumkct",
"projectId": "GfFdmZTqGEJQkrXG",
"project": {
"updatedAt": "2026-05-11T09:44:44.757Z",
"createdAt": "2026-05-11T09:34:45.695Z",
"id": "GfFdmZTqGEJQkrXG",
"name": "\u00c9ole Wind <megazef@gmail.com>",
"type": "personal",
"icon": null,
"description": null,
"creatorId": "2792484d-cba3-4156-adba-fbc49134eb55"
}
}
],
"tags": [
{
"updatedAt": "2026-05-29T11:31:39.972Z",
"createdAt": "2026-05-29T11:31:39.972Z",
"id": "5zynHpPHQi9PRMyD",
"name": "jobby"
},
{
"updatedAt": "2026-05-11T12:19:25.326Z",
"createdAt": "2026-05-11T12:19:25.326Z",
"id": "8yiCAJZW8fFXfFqI",
"name": "notion"
},
{
"updatedAt": "2026-05-29T11:33:37.867Z",
"createdAt": "2026-05-29T11:33:37.867Z",
"id": "oVl5DgcCQROKFX7w",
"name": "AI"
},
{
"updatedAt": "2026-05-29T11:33:25.261Z",
"createdAt": "2026-05-29T11:33:25.261Z",
"id": "sTPsdvgfTYjdu5g7",
"name": "live"
}
],
"activeVersion": {
"updatedAt": "2026-06-03T10:12:33.000Z",
"createdAt": "2026-06-03T10:11:59.138Z",
"versionId": "1f38b6c8-cab7-4bb2-a645-f6c092f23ca5",
"workflowId": "olgL8wb7nrJumkct",
"nodes": [
{
"parameters": {
"promptType": "define",
"text": "=Company: {{ $('CV Factory').item.json.query.company }}\njon title : {{ $('CV Factory').item.json.query.job_title }}\njob Url: {{ $('CV Factory').item.json.query.job_url }}\nDescription: {{ $('CV Factory').item.json.query.job_description }}\n",
"options": {
"systemMessage": "=# Tu es Jobby 3.0\nL'assistant strat\u00e9gique de recherche d'imploi pour Julien. \n\n## Identity & Tone\nTon ton est neutre, analytique et orient\u00e9 r\u00e9sultats, comme un coach en recrutement senior. Ta valeur ajout\u00e9e r\u00e9side dans la d\u00e9tection pr\u00e9cise des \u00e9carts techniques et organisationnels.\n\n## Purpose\n\u00c9valuer l'ad\u00e9quation entre le profil de Julien (Solutions Engineer, expert automation/IA) et une offre d'emploi sp\u00e9cifique, puis g\u00e9n\u00e9rer le CV Markdown optimal pour maximiser le score ATS.\n\n## Context & Data\nPour r\u00e9aliser cette analyse et cette g\u00e9n\u00e9ration, voici les donn\u00e9es consolid\u00e9es issues du syst\u00e8me :\n\n## 1. Fiche de Poste Aspir\u00e9e (LinkedIn)\n{{ $json.job_description }}\n\n## 2. Directives de Positionnement (La Graine)\n- Baseline attendue : {{ $json.seed_baseline }}\n- Consignes de filtrage : {{ $json.seed_directives }}\n\n## 3. Graphe de Comp\u00e9tences & Exp\u00e9riences (CV Atomique)\n{{ $json.cv_master_payload }}\n\n# Evaluation Criteria\n1. Score (1-10) : Bas\u00e9 strictement sur l'ad\u00e9quation technique, l'exp\u00e9rience pass\u00e9e et le niveau de s\u00e9niorit\u00e9 requis.\n2. Gap Analysis : Identifier les technologies ou m\u00e9thodologies manquantes sans fioritures.\n3. Reskilling & Tailoring : S\u00e9lectionner uniquement les 4 derni\u00e8res activit\u00e9s du CV Atomique et adapter subtilement les puces d'impact en utilisant les mots-cl\u00e9s de la fiche de poste et l'orientation de la Graine.\n\n**CRITICAL NOTION LIMIT**: Le texte dans `\"generated_cv_markdown\"` doit \u00eatre concis et synth\u00e9tique. Chaque section `(Summary, Exp\u00e9rience, etc.)`` doit \u00eatre s\u00e9par\u00e9e par le caract\u00e8re \"|\" pour nous permettre de d\u00e9couper le texte apr\u00e8s coup et \u00e9viter de d\u00e9passer la limite de 2000 caract\u00e8res par bloc impos\u00e9e par l'API Notion.\n\n# Output Format (STRICT JSON)\nR\u00e9ponds exclusivement par un objet JSON valide. Le CV au format Markdown et en anglais doit \u00eatre enti\u00e8rement encapsul\u00e9 dans la cl\u00e9 \"generated_cv_markdown\". Ne mets pas de balises de code (comme `markdown`) \u00e0 l'int\u00e9rieur du JSON.\n\n```{\n \"domain\": \"string (ex: Generative AI, Automation, API Management)\",\n \"job_title\": \"string (Titre exact)\",\n \"company\": \"string\",\n \"match_score\": number,\n \"quick_summary\": \"string (MAX 150 caract\u00e8res)\",\n \"analysis_pros\": \"string (Points forts techniques et m\u00e9tier - Max 800 caract\u00e8res)\",\n \"analysis_cons\": \"string (Points de friction et manques - Max 800 caract\u00e8res)\",\n \"action_plan\": \"string (Conseil imm\u00e9diat pour la candidature - Max 400 caract\u00e8res)\",\n \"generated_cv_markdown\": \"string (Le CV V2.0 complet en Markdown, structur\u00e9 avec l'Aside de d\u00e9part contenant la baseline, puis les 4 derniers jobs adapt\u00e9s aux crit\u00e8res ATS)\"\n}"
}
},
"type": "@n8n/n8n-nodes-langchain.agent",
"typeVersion": 3.1,
"position": [
352,
48
],
"id": "b28e3fb0-c3bf-42f4-9a63-a95c5c8d4055",
"name": "AI Agent",
"onError": "continueErrorOutput"
},
{
"parameters": {
"modelName": "models/gemini-2.5-flash-lite",
"options": {}
},
"type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
"typeVersion": 1.1,
"position": [
352,
320
],
"id": "c09c542b-80ca-4d47-a542-15fc14eabccd",
"name": "Google Gemini Chat Model",
"credentials": {
"googlePalmApi": {
"id": "QZGttnIQoPa4rsAg",
"name": "Google Gemini(PaLM) Api account"
}
}
},
{
"parameters": {
"model": {
"__rl": true,
"mode": "list",
"value": "claude-sonnet-4-6",
"cachedResultName": "Claude Sonnet 4.6"
},
"options": {}
},
"type": "@n8n/n8n-nodes-langchain.lmChatAnthropic",
"typeVersion": 1.4,
"position": [
-544,
384
],
"id": "29dd6f16-98a6-48f5-ad0b-7a76b5eb335a",
"name": "Anthropic Chat Model",
"credentials": {
"anthropicApi": {
"id": "ZLxe6Yv6rEgDYs00",
"name": "Anthropic account"
}
}
},
{
"parameters": {
"jsCode": "// 1. On r\u00e9cup\u00e8re le texte g\u00e9n\u00e9r\u00e9 par l'Agent\nconst text = $json.output || \"\"; \nconst match = text.match(/\\{[\\s\\S]*\\}/);\n\nif (match) {\n try {\n // On parse uniquement le bloc JSON trouv\u00e9\n const data = JSON.parse(match);\n\n // Helper pour les tableaux Notion (Multi-select)\n const toSimpleArray = (val) => {\n if (!val) return [];\n const rawItems = Array.isArray(val) ? val : val.toString().split(/[|,\\/&]|\\band\\b/);\n return rawItems.map(i => i.trim()).filter(i => i.length > 1);\n };\n\n // 2. On reconstruit l'objet propre pour alimenter le n\u0153ud \"Update Notion\"\n return [{\n json: {\n domain: toSimpleArray(data.domain),\n category: toSimpleArray(data.category || data.job_title),\n job_title: data.job_title || \"Position inconnue\",\n company: data.company || \"Entreprise inconnue\",\n score: parseInt(data.match_score) || 0,\n status: \"To review\",\n summary: data.quick_summary || \"Analyse termin\u00e9e\",\n analysis_pros: data.analysis_pros || \"N/A\",\n analysis_cons: data.analysis_cons || \"N/A\",\n action_plan: data.action_plan || \"N/A\",\n generated_cv_markdown: data.generated_cv_markdown || \"\",\n response_date: new Date().toISOString().split('T')\n }\n }];\n\n } catch (e) {\n return [{ json: { error: \"JSON Parsing Error\", message: e.message, raw: text.substring(0, 200) } }];\n }\n}\n\nreturn [{ json: { error: \"No JSON found in AI output\", raw: text.substring(0, 100) } }];"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
704,
-48
],
"id": "bc6d9e53-7c47-4b19-97f4-e78868ea7cdd",
"name": "JSON Cleaner",
"onError": "continueErrorOutput"
},
{
"parameters": {
"resource": "database",
"databaseId": {
"__rl": true,
"value": "5ea1407d-50b4-4527-bd86-21f3c58535fa",
"mode": "list",
"cachedResultName": "Complete Resume DB",
"cachedResultUrl": "https://www.notion.so/5ea1407d50b44527bd8621f3c58535fa"
}
},
"type": "n8n-nodes-base.notion",
"typeVersion": 2.2,
"position": [
-320,
48
],
"id": "98b735c7-3087-4ff3-83a7-c749cba35b8b",
"name": "Get CV data",
"credentials": {
"notionApi": {
"id": "KYrsxF0plfLkPpqW",
"name": "Notion LinkedIn Auto"
}
}
},
{
"parameters": {
"resource": "database",
"databaseId": {
"__rl": true,
"value": "642d04c9-1c1f-4c01-a4d3-89822f02556b",
"mode": "list",
"cachedResultName": "CV Seeds",
"cachedResultUrl": "https://www.notion.so/642d04c91c1f4c01a4d389822f02556b"
}
},
"type": "n8n-nodes-base.notion",
"typeVersion": 2.2,
"position": [
-96,
48
],
"id": "1c3e6440-cbf2-472c-ab63-959a496a7e6f",
"name": "CV Seed",
"credentials": {
"notionApi": {
"id": "KYrsxF0plfLkPpqW",
"name": "Notion LinkedIn Auto"
}
}
},
{
"parameters": {
"resource": "databasePage",
"databaseId": {
"__rl": true,
"value": "127bad1f-b25a-4b6b-8eec-7b342e3aa504",
"mode": "list",
"cachedResultName": "Linked Detector",
"cachedResultUrl": "https://www.notion.so/127bad1fb25a4b6b8eec7b342e3aa504"
},
"title": "LinkedIn Detector",
"simple": false,
"propertiesUi": {
"propertyValues": [
{
"key": "Job Title|title",
"title": "={{ $json.job_title || \"Nouvelle offre LinkedIn (Titre non extrait)\" }}\n"
},
{
"key": "category|multi_select",
"multiSelectValue": "={{ $json.category }}"
},
{
"key": "URL|url",
"urlValue": "={{ $('CV Factory').item.json.query.job_url }}"
},
{
"key": "Match Score|number",
"numberValue": "={{ $json.score }}"
},
{
"key": "Status|status",
"statusValue": "={{ $json.status }}"
},
{
"key": "Company|select",
"selectValue": "={{ $json.company }}"
},
{
"key": "domain|multi_select",
"multiSelectValue": "={{ $json.domain }}S"
},
{
"key": "analysis|rich_text",
"textContent": "={{ $json.summary }}"
}
]
},
"blockUi": {
"blockValues": [
{
"type": "heading_1",
"textContent": "Analyse compl\u00e8te"
},
{
"textContent": "={{ $json.summary }}"
},
{
"type": "heading_2",
"textContent": "Pros"
},
{
"textContent": "={{ $json.analysis_pros }}"
},
{
"type": "heading_2",
"textContent": "Cons"
},
{
"textContent": "={{ $json.analysis_cons }}"
},
{
"type": "heading_2",
"textContent": "Action Plan"
},
{
"textContent": "={{ $json.action_plan }}"
},
{
"type": "heading_1",
"textContent": "Raw job description "
},
{
"type": "toggle",
"textContent": "=About the job"
},
{
"textContent": "={{ $('CV Factory').item.json.query.job_description }}"
}
]
},
"options": {
"iconType": "emoji",
"icon": "\ud83c\udd95"
}
},
"type": "n8n-nodes-base.notion",
"typeVersion": 2.2,
"position": [
928,
-48
],
"id": "a801be3c-190f-4c32-a564-050e9ba194f2",
"name": "update prospect",
"retryOnFail": false,
"executeOnce": false,
"credentials": {
"notionApi": {
"id": "KYrsxF0plfLkPpqW",
"name": "Notion LinkedIn Auto"
}
}
},
{
"parameters": {
"path": "cv-factory",
"authentication": "headerAuth",
"options": {
"responseData": "{\"status\": \"processing\"}"
}
},
"type": "n8n-nodes-base.webhook",
"typeVersion": 2.1,
"position": [
-544,
48
],
"id": "4f70d8ad-1003-4506-b630-04d85c94d2e1",
"name": "CV Factory",
"webhookId": "44786c94-5bac-493e-a778-8d065668d8b2",
"credentials": {
"httpHeaderAuth": {
"id": "QDm4dLNTsiXmLpmM",
"name": "Header Auth account"
}
}
},
{
"parameters": {
"jsCode": "// 1. R\u00e9cup\u00e9ration des lignes du CV Atomique\nlet cvRows = [];\ntry {\n cvRows = $('Get CV data').all();\n} catch (e) {\n cvRows = [];\n}\n\n// Extraction universelle pour le CV\nconst cleanExperiences = cvRows.map((row, index) => {\n const props = row.json?.properties || {};\n \n // Fonction helper pour extraire le texte brut d'une propri\u00e9t\u00e9 Notion, quel que soit son type (title ou rich_text)\n const extractText = (propObj) => {\n if (!propObj) return \"\";\n const arr = propObj.rich_text || propObj.title || [];\n return arr?.plain_text || propObj.value || \"\";\n };\n\n // On scanne dynamiquement les variantes de noms de colonnes possibles\n const entreprise = extractText(props.Entreprise) || extractText(props.Company) || \"Entreprise \" + (index + 1);\n const poste = extractText(props.Poste) || extractText(props.Role) || \"Solutions Engineer\";\n const description = extractText(props.Description) || \"\";\n const dates = extractText(props.Dates) || extractText(props.Date) || \"\";\n\n return `### ${poste} chez ${entreprise} (${dates})\\n${description}`;\n}).join(\"\\n\\n\");\n\n// 2. R\u00e9cup\u00e9ration et isolation de la Graine UNIQUE\nlet seedBaseline = \"Solutions Engineer\";\nlet seedDirectives = \"Standard tailoring\";\n\ntry {\n const allSeeds = $('CV Seed').all();\n // On cherche la graine active via la checkbox, sinon on prend la premi\u00e8re disponible\n const selectedSeedItem = allSeeds.find(item => {\n const props = item.json?.properties || {};\n // G\u00e8re la checkbox Notion (qu'elle s'appelle Active ou active)\n const checkObj = props.Active || props.active;\n return checkObj?.checkbox === true;\n }) || allSeeds;\n\n if (selectedSeedItem && selectedSeedItem.json?.properties) {\n const sProps = selectedSeedItem.json.properties;\n \n const extractSeedText = (propObj) => {\n if (!propObj) return null;\n const arr = propObj.title || propObj.rich_text || [];\n return arr?.plain_text || null;\n };\n\n seedBaseline = extractSeedText(sProps.Baseline) || extractSeedText(sProps.baseline) || seedBaseline;\n seedDirectives = extractSeedText(sProps.Directives) || extractSeedText(sProps.directives) || seedDirectives;\n }\n} catch (e) {\n // En cas de probl\u00e8me de lecture de la graine, on garde les valeurs par d\u00e9faut pour ne pas bloquer le flux\n}\n\n// 3. Payload plat final garanti sans crash\nreturn [{\n json: {\n job_description: $json.job_description || \"Pas de description\",\n seed_baseline: seedBaseline,\n seed_directives: seedDirectives,\n cv_master_payload: cleanExperiences || \"CV Master vide\"\n }\n}];"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
128,
48
],
"id": "6fc7730a-c6d3-48db-919d-c700c1c6bed1",
"name": "Clean CV"
},
{
"parameters": {
"errorMessage": "={{ $('AI Agent').item.json.error }}"
},
"type": "n8n-nodes-base.stopAndError",
"typeVersion": 1,
"position": [
704,
144
],
"id": "0334fb31-bc67-410f-89bc-7e0de9ccaa43",
"name": "Stop and Error"
}
],
"connections": {
"Google Gemini Chat Model": {
"ai_languageModel": [
[
{
"node": "AI Agent",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"AI Agent": {
"main": [
[
{
"node": "JSON Cleaner",
"type": "main",
"index": 0
}
],
[
{
"node": "Stop and Error",
"type": "main",
"index": 0
}
]
]
},
"Anthropic Chat Model": {
"ai_languageModel": [
[]
]
},
"JSON Cleaner": {
"main": [
[
{
"node": "update prospect",
"type": "main",
"index": 0
}
],
[]
]
},
"Get CV data": {
"main": [
[
{
"node": "CV Seed",
"type": "main",
"index": 0
}
]
]
},
"CV Seed": {
"main": [
[
{
"node": "Clean CV",
"type": "main",
"index": 0
}
]
]
},
"update prospect": {
"main": [
[],
[]
]
},
"CV Factory": {
"main": [
[
{
"node": "Get CV data",
"type": "main",
"index": 0
}
]
]
},
"Clean CV": {
"main": [
[
{
"node": "AI Agent",
"type": "main",
"index": 0
}
]
]
}
},
"authors": "\u00c9ole Wind",
"name": "Version 1f38b6c8",
"description": "Authorization",
"autosaved": true,
"workflowPublishHistory": [
{
"createdAt": "2026-06-03T10:12:33.619Z",
"id": 208,
"workflowId": "olgL8wb7nrJumkct",
"versionId": "1f38b6c8-cab7-4bb2-a645-f6c092f23ca5",
"event": "activated",
"userId": "2792484d-cba3-4156-adba-fbc49134eb55"
}
]
}
}
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.
anthropicApigooglePalmApihttpHeaderAuthnotionApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Jobby - LinkedIn 2 Notion. Uses agent, lmChatGoogleGemini, lmChatAnthropic, notion. Webhook trigger; 10 nodes.
Source: https://github.com/gnueole/jobby-md2html/blob/main/n8n/jobby-linkedin-2-notion.json — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
LinkedIn auto - old (GDocs). Uses agent, lmChatGoogleGemini, notion, stopAndError. Webhook trigger; 8 nodes.
LinkedIn auto Claude. Uses agent, lmChatGoogleGemini, notion, googleDocs. Webhook trigger; 8 nodes.
⏺ 🚀 How it works
Are you drowning in daily operational chaos, desperately trying to juggle sales, projects, content, and client communication? Imagine an AI brain that handles it all, freeing you to lead your business
Resume Screening & Behavioral Interviews with Gemini, Elevenlabs, & Notion ATS copy. Uses outputParserStructured, chainLlm, googleDrive, stickyNote. Webhook trigger; 67 nodes.