Automatisation de la création de contenu pour blog et LinkedIn
Ceci est unContent Creation, Multimodal AIworkflow d'automatisation du domainecontenant 28 nœuds.Utilise principalement des nœuds comme If, Set, Code, Cron, Gmail. Utiliser OpenAI et Replicate AI image pour automatiser la création de contenu pour blog et LinkedIn
- •Compte Google et informations d'identification Gmail API
- •Clé API Notion
- •Informations d'identification LinkedIn API
- •Peut nécessiter les informations d'identification d'authentification de l'API cible
- •Clé API OpenAI
Nœuds utilisés (28)
Catégorie
{
"meta": {
"instanceId": "f930580f475173640cf75bd5e1dc94fd2a589d21917d2c231c8fd90eb205f9b82",
"templateCredsSetupCompleted": true
},
"nodes": [
{
"id": "45e081e9-db15-4808-9c26-6f1089f23a0e",
"name": "Cron (Planification)",
"type": "n8n-nodes-base.cron",
"position": [
-1648,
-304
],
"parameters": {
"triggerTimes": {
"item": [
{
"hour": 19
}
]
}
},
"typeVersion": 1
},
{
"id": "7e72fddb-7c81-4bf3-bd96-b02c3ebb53efa",
"name": "Set (Configurations)",
"type": "n8n-nodes-base.set",
"position": [
-1424,
-304
],
"parameters": {
"values": {
"string": [
{
"name": "NOTION_DB_ID",
"value": "25496301-7675-81fa-9d31-cedcc7f452c6a"
},
{
"name": "NOTION_PAGE_PARENT",
"value": "XXXXXXXXXXXXXXXXXXXXXXXXXXX"
},
{
"name": "LINKEDIN_PERSON_URN",
"value": "urn:li:person:XXXXXXXX"
},
{
"name": "OPENAI_MODEL",
"value": "gpt-4.1-mini"
},
{
"name": "EMAIL_TO",
"value": "test@mail.com"
}
],
"boolean": [
{
"name": "LINKEDIN_PUBLISH",
"value": true
}
]
},
"options": {},
"keepOnlySet": true
},
"typeVersion": 2
},
{
"id": "648ff7d2-a55e-4e0c-8b12-d3634d1f1b958",
"name": "Notion → Interroger la Base d'Idées (toutes)",
"type": "n8n-nodes-base.notion",
"position": [
-1200,
-304
],
"parameters": {
"simple": false,
"options": {
"sort": {
"sortValue": [
{
"key": "created_time",
"direction": "ascending",
"timestamp": true
}
]
}
},
"resource": "databasePage",
"operation": "getAll",
"returnAll": true,
"databaseId": {
"__rl": true,
"mode": "id",
"value": "={{ $json.NOTION_DB_ID }}"
},
"filterJson": "={\n \"property\": \"published\",\n \"checkbox\": { \"equals\": false }\n}",
"filterType": "json"
},
"credentials": {
"notionApi": {
"id": "AU61TARrYLYMxTj9",
"name": "Notion account"
}
},
"typeVersion": 2
},
{
"id": "c964ef88-6dea-4ea1-ad6c-2eef99b483646",
"name": "IF (Éligible ?)",
"type": "n8n-nodes-base.if",
"position": [
-1200,
0
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 1,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "d6c0245f-b296-4a04-861d-84c42736aa997",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
},
"leftValue": "={{ $json.eligible_count > 0 }}",
"rightValue": ""
}
]
}
},
"typeVersion": 2
},
{
"id": "e3a428a0-c52e-47f6-9281-1063f84e587c3",
"name": "Diviser en Lots (1)",
"type": "n8n-nodes-base.splitInBatches",
"position": [
-656,
-304
],
"parameters": {
"options": {},
"batchSize": 1
},
"typeVersion": 2
},
{
"id": "017d6b4c-52f8-4238-abf1-95f44d08b182b",
"name": "Déclencheur d'Erreur (Si un Nœud Échoue)",
"type": "n8n-nodes-base.errorTrigger",
"position": [
-1520,
2272
],
"parameters": {},
"typeVersion": 1
},
{
"id": "219ddd0a-9ad8-4555-acf1-b002406738346",
"name": "Compter les Éligibles",
"type": "n8n-nodes-base.code",
"position": [
-1424,
0
],
"parameters": {
"jsCode": "// Emit a single item with the eligible count for IF routing\nreturn [{ json: { eligible_count: items.length } }];"
},
"typeVersion": 2
},
{
"id": "7d00232e-be9d-4cdc-b072-eedc64dd79e3c",
"name": "Filtrer Non Publiés + Mapper",
"type": "n8n-nodes-base.code",
"position": [
-976,
-304
],
"parameters": {
"jsCode": "/* Filter unpublished + map fields safely */\nconst out = [];\nfor (const item of items) {\n const page = item.json;\n const id = page.id;\n const p = page.properties || {};\n const g = (prop) => {\n if (!prop) return '';\n if (prop.type === 'title' && prop.title?.length) return prop.title.map(t=>t.plain_text).join('');\n if (prop.type === 'rich_text' && prop.rich_text?.length) return prop.rich_text.map(t=>t.plain_text).join('');\n if (prop.type === 'url') return prop.url || '';\n if (prop.type === 'checkbox') return !!prop.checkbox;\n if (prop.type === 'multi_select') return prop.multi_select.map(o=>o.name);\n if (prop.type === 'select') return prop.select?.name || '';\n if (prop.type === 'date') return prop.date?.start || '';\n return '';\n };\n const isPublished = p.published ? !!p.published.checkbox : false;\n if (isPublished) continue;\n\n const title = g(p.title) || page.properties?.Name?.title?.[0]?.plain_text || '';\n const angle = g(p.angle);\n const tags = p.tags ? (p.tags.type === 'multi_select' ? p.tags.multi_select.map(o=>o.name) : g(p.tags)) : '';\n const primary_link = g(p.primary_link);\n const reference_links = g(p.reference_links);\n const images = g(p.images);\n const notes = g(p.notes);\n const target_audience = g(p.target_audience);\n const canonical_url = g(p.canonical_url);\n const language = g(p.language);\n const slug = g(p.slug);\n\n out.push({ json: {\n notion_page_id: id,\n title,\n angle,\n tags,\n primary_link,\n reference_links,\n images,\n notes,\n target_audience,\n canonical_url,\n language,\n slug\n }});\n}\nreturn out;\n"
},
"typeVersion": 2
},
{
"id": "40b826f5-b1ef-490b-b208-f1754c1972d81",
"name": "Envoyer un message",
"type": "n8n-nodes-base.gmail",
"position": [
-976,
0
],
"webhookId": "60e2a23b-9c59-485b-a5d3-9c61b2f39a45",
"parameters": {
"sendTo": "={{ $('Set (Configs)').item.json.EMAIL_TO }}",
"message": "=No rows found in {{ $('Set (Configs)').item.json.NOTION_DB_ID }} with published != true at {{$now}}.",
"options": {},
"subject": "Blog Pipeline: No Eligible Notion Rows!",
"emailType": "text"
},
"credentials": {
"gmailOAuth2": {
"id": "g6m2gV1BtMtEggjm",
"name": "Gmail account"
}
},
"typeVersion": 2.1
},
{
"id": "87a55a66-d609-47d2-a177-eddb4a7d9d560",
"name": "Analyser & Valider JSON",
"type": "n8n-nodes-base.code",
"position": [
144,
-304
],
"parameters": {
"jsCode": "/**\n * Node 11 — Function (Parse & Validate JSON from OpenAI)\n * Soft-handles safety_flags (warnings) instead of throwing.\n */\n\n// ---------- 1) Extract message.content ----------\nconst input = items[0].json;\n\nfunction extractContent(nodeOut) {\n // n8n OpenAI nodes vary; support a few shapes:\n\n // A) Array of { message: { content } }\n if (Array.isArray(nodeOut) && nodeOut[0]?.message?.content !== undefined) {\n return nodeOut[0].message.content;\n }\n // B) Chat Completions\n if (nodeOut?.data?.choices?.[0]?.message?.content !== undefined) {\n return nodeOut.data.choices[0].message.content;\n }\n // C) OpenAI node returning raw string JSON at top level\n if (typeof nodeOut === \"string\") {\n return nodeOut;\n }\n // D) Flattened shape\n if (nodeOut?.message?.content !== undefined) {\n return nodeOut.message.content;\n }\n // E) Sometimes models already return parsed object\n if (nodeOut?.content !== undefined) {\n return nodeOut.content;\n }\n throw new Error(\"Node11: could not locate message.content from OpenAI output\");\n}\n\nlet content = extractContent(input);\n\n// ---------- 2) Parse to object ----------\nlet parsed;\nif (content && typeof content === \"object\") {\n parsed = content;\n} else if (typeof content === \"string\") {\n let txt = content.trim();\n if (txt.startsWith(\"```\")) {\n txt = txt.replace(/^```(?:json)?\\s*/i, \"\").replace(/\\s*```$/i, \"\");\n }\n txt = txt\n .replace(/[\\u2018\\u2019]/g, \"'\")\n .replace(/[\\u201C\\u201D]/g, '\"')\n .replace(/[\\u0000-\\u0008\\u000B\\u000C\\u000E-\\u001F]/g, \" \")\n .replace(/,\\s*([}\\]])/g, \"$1\");\n\n // escape raw newlines inside strings\n (function escapeNewlinesInStrings() {\n let out = \"\", inStr = false, esc = false;\n for (let i = 0; i < txt.length; i++) {\n const ch = txt[i];\n if (!inStr) { if (ch === '\"') inStr = true; out += ch; continue; }\n if (esc) { out += ch; esc = false; continue; }\n if (ch === \"\\\\\") { out += ch; esc = true; continue; }\n if (ch === '\"') { inStr = false; out += ch; continue; }\n if (ch === \"\\n\" || ch === \"\\r\") { out += \"\\\\n\"; continue; }\n out += ch;\n }\n txt = out;\n })();\n\n try {\n parsed = JSON.parse(txt);\n } catch (e) {\n throw new Error(\"Node11: JSON.parse failed after repair: \" + e.message);\n }\n} else {\n throw new Error(\"Node11: message.content is neither object nor string\");\n}\n\n// ---------- 3) Validate + normalize ----------\nconst errs = [];\nconst warn = [];\nconst isNonEmpty = (s) => typeof s === \"string\" && s.trim().length > 0;\nconst arrOfStr = (a) => Array.isArray(a) ? a.map(x => String(x)).filter(Boolean) : [];\n\nif (!parsed.blog) errs.push(\"blog missing\");\nelse {\n if (!isNonEmpty(parsed.blog.title)) errs.push(\"blog.title missing\");\n if (!isNonEmpty(parsed.blog.slug)) errs.push(\"blog.slug missing\");\n if (!isNonEmpty(parsed.blog.markdown)) errs.push(\"blog.markdown missing\");\n if (parsed.blog.slug && parsed.blog.slug.length > 100) errs.push(\"blog.slug > 100 chars\");\n parsed.blog.keywords = arrOfStr(parsed.blog.keywords);\n parsed.blog.image_alt_texts = arrOfStr(parsed.blog.image_alt_texts);\n if (\n parsed.blog.canonical_url !== null &&\n parsed.blog.canonical_url !== undefined &&\n typeof parsed.blog.canonical_url !== \"string\"\n ) errs.push(\"blog.canonical_url must be string or null\");\n}\n\nif (!parsed.linkedin) errs.push(\"linkedin missing\");\nelse {\n if (!isNonEmpty(parsed.linkedin.final_text)) errs.push(\"linkedin.final_text missing\");\n // hashtags soft window\n parsed.linkedin.hashtags = arrOfStr(parsed.linkedin.hashtags);\n if (parsed.linkedin.hashtags.length > 8) {\n parsed.linkedin.hashtags = parsed.linkedin.hashtags.slice(0, 8);\n }\n // char guard\n let ft = String(parsed.linkedin.final_text || \"\");\n if (ft.length > 1200) {\n let cut = ft.slice(0, 1180);\n const lastBreak = Math.max(cut.lastIndexOf(\"\\n\"), cut.lastIndexOf(\".\"));\n if (lastBreak > 800) cut = cut.slice(0, lastBreak + 1);\n parsed.linkedin.final_text = cut;\n warn.push(\"linkedin.final_text truncated to 1200 chars\");\n }\n}\n\n// Safety flags: treat as warnings (expose downstream)\nif (!Array.isArray(parsed.safety_flags)) parsed.safety_flags = [];\nif (parsed.safety_flags.length) {\n warn.push(\"safety_flags present: \" + parsed.safety_flags.join(\", \"));\n}\n\n// Hard errors?\nif (errs.length) {\n throw new Error(\"Node11 validation failed: \" + errs.join(\"; \"));\n}\n\n// ---------- 4) Merge with Normalize Arrays (Node 9), return ----------\nlet norm = {};\ntry {\n const n = $items(\"Function (Normalize Arrays)\", 0, $runIndex);\n if (Array.isArray(n) && n[0] && n[0].json) norm = n[0].json;\n} catch (_) {}\n\nreturn [{\n json: {\n ...norm,\n openai: parsed,\n warnings: warn\n }\n}];\n"
},
"typeVersion": 2
},
{
"id": "3ab2103a-a358-415c-a4d1-1df7c3cb14f5",
"name": "Normaliser les Tableaux",
"type": "n8n-nodes-base.code",
"position": [
-432,
-304
],
"parameters": {
"jsCode": "// Normalize arrays + carry configs\nfunction toArray(v){\n if (Array.isArray(v)) return v;\n if (typeof v === 'string'){\n const s = v.trim();\n if (!s) return [];\n try { const parsed = JSON.parse(s); if (Array.isArray(parsed)) return parsed; } catch(e) {}\n return s.split(',').map(x=>x.trim()).filter(Boolean);\n }\n return [];\n}\n\n// Pull config from the Set (Configs) node\n// Simple form:\nconst cfg = $node[\"Set (Configs)\"].json;\n// Robust form (if you prefer):\n// const cfg = $items(\"Set (Configs)\", 0, $runIndex)[0].json;\n\nconst i = items[0].json;\n\nreturn [{\n json: {\n NOTION_DB_ID: cfg.NOTION_DB_ID,\n NOTION_PAGE_PARENT: cfg.NOTION_PAGE_PARENT,\n LINKEDIN_PERSON_URN: cfg.LINKEDIN_PERSON_URN,\n OPENAI_MODEL: cfg.OPENAI_MODEL,\n EMAIL_TO: cfg.EMAIL_TO,\n\n notion_page_id: i.notion_page_id,\n title: i.title || '',\n angle: i.angle || '',\n tags: toArray(i.tags),\n primary_link: i.primary_link || '',\n reference_links: toArray(i.reference_links),\n images: toArray(i.images),\n notes: i.notes || '',\n target_audience: i.target_audience || '',\n canonical_url: i.canonical_url || '',\n language: i.language || '',\n slug: i.slug || ''\n }\n}];\n"
},
"typeVersion": 2
},
{
"id": "52a1ad9c-cc6a-49a1-ab7f-9b3a8a2e8c2b",
"name": "Créer un post",
"type": "n8n-nodes-base.linkedIn",
"position": [
1872,
-432
],
"parameters": {
"text": "={{ $('Content Creator').item.json.message.content.linkedin.final_text }}",
"person": "k47kCb899q",
"additionalFields": {
"title": "={{ $('Content Creator').item.json.message.content.blog.title }}",
"visibility": "PUBLIC"
},
"binaryPropertyName": "=data",
"shareMediaCategory": "IMAGE"
},
"credentials": {
"linkedInOAuth2Api": {
"id": "DzG9q9KGhJCP5FSt",
"name": "LinkedIn account"
}
},
"typeVersion": 1
},
{
"id": "128ee066-dca2-4c19-830b-621e3eafbbc0",
"name": "Créer une Page de Base de Données d'Article",
"type": "n8n-nodes-base.notion",
"position": [
432,
-304
],
"parameters": {
"title": "={{ $json.openai.blog.title }}",
"simple": false,
"options": {},
"resource": "databasePage",
"databaseId": {
"__rl": true,
"mode": "list",
"value": "25496301-7675-81bc-b023-c7e012094120",
"cachedResultUrl": "https://www.notion.so/25496301767581bcb023c7e012094120",
"cachedResultName": "Articles"
},
"propertiesUi": {
"propertyValues": [
{
"key": "title|title",
"title": "={{ $json.openai.blog.title }}"
},
{
"key": "slug|rich_text",
"text": {
"text": [
{
"text": "={{ $json.openai.blog.slug }}",
"annotationUi": {}
}
]
},
"richText": true
},
{
"key": "excerpt|rich_text",
"text": {
"text": [
{
"text": "={{ $json.openai.blog.excerpt }}",
"annotationUi": {}
}
]
},
"richText": true
},
{
"key": "keywords|multi_select",
"multiSelectValue": "={{ $json.openai.blog.keywords }}"
},
{
"key": "canonical_url|url",
"urlValue": "={{ $json.openai.blog.canonical_url || '' }}",
"ignoreIfEmpty": true
},
{
"key": "suggested_cover_caption|rich_text",
"text": {
"text": [
{
"text": "={{ $json.openai.blog.suggested_cover_caption }}",
"annotationUi": {}
}
]
},
"richText": true
},
{
"key": "image_alt_texts|rich_text",
"text": {
"text": [
{
"text": "={{ $json.openai.blog.image_alt_texts.join(', ') }}",
"annotationUi": {}
}
]
},
"richText": true
},
{
"key": "language|select",
"selectValue": "={{ $('Split In Batches (1)').item.json.language || 'en' }}"
},
{
"key": "tags|multi_select",
"multiSelectValue": "={{ $json.openai.linkedin.hashtags }}"
},
{
"key": "status|select",
"selectValue": "Published"
},
{
"key": "published_at|date",
"date": "={{ $now }}",
"timezone": "Asia/Kathmandu"
},
{
"key": "source_idea|relation",
"relationValue": [
"={{ $('Split In Batches (1)').item.json.notion_page_id }}"
]
},
{
"key": "linkedin_draft|rich_text",
"text": {
"text": [
{
"text": "={{ $json.openai.linkedin.final_text }}",
"annotationUi": {}
}
]
},
"richText": true
}
]
}
},
"credentials": {
"notionApi": {
"id": "AU61TARrYLYMxTj9",
"name": "Notion account"
}
},
"typeVersion": 2.2
},
{
"id": "6160be76-97f5-4f4c-bfa6-5e480080d854",
"name": "Brouillon d'E-mail",
"type": "n8n-nodes-base.gmail",
"position": [
1120,
-80
],
"webhookId": "4a91eae9-a78f-4246-bdf2-faaf10f3afdd",
"parameters": {
"sendTo": "={{ $('Set (Configs)').item.json.EMAIL_TO }}",
"message": "=Title: {{ $json.properties.title.title[0].text.content }}\nDraft: {{ $json.properties.linkedin_draft.rich_text[0].text.content }}",
"options": {},
"subject": "LinkedIn Draft Ready",
"emailType": "text"
},
"credentials": {
"gmailOAuth2": {
"id": "g6m2gV1BtMtEggjm",
"name": "Gmail account"
}
},
"typeVersion": 2.1
},
{
"id": "a1a7482f-3868-402c-a05b-2535b8443ad7",
"name": "E-mail de Publication",
"type": "n8n-nodes-base.gmail",
"position": [
2096,
-432
],
"webhookId": "f2d6603d-058d-43dd-8d67-aaed9476c825",
"parameters": {
"sendTo": "mail@budhathokisagar.com.np",
"message": "=Published: {{ $('Create a Article Database Page').item.json.properties.title.title[0].text.content }}\nSlug: {{ $('Create a Article Database Page').item.json.properties.slug.rich_text[0].text.content }}\nLinkedIn: posted as person.\nIdea Page: {{ $('Create a Article Database Page').item.json.id }}",
"options": {},
"subject": "LinkedIn Post Published!",
"emailType": "text"
},
"credentials": {
"gmailOAuth2": {
"id": "g6m2gV1BtMtEggjm",
"name": "Gmail account"
}
},
"typeVersion": 2.1
},
{
"id": "a7b80170-9832-46fb-85ba-8b87c5bd9da4",
"name": "Brouillon de Mise à Jour de Base de Données",
"type": "n8n-nodes-base.notion",
"position": [
1344,
-80
],
"parameters": {
"pageId": {
"__rl": true,
"mode": "id",
"value": "={{ $('Create a Article Database Page').item.json.id }}"
},
"simple": false,
"options": {},
"resource": "databasePage",
"operation": "update",
"propertiesUi": {
"propertyValues": [
{
"key": "status|select",
"selectValue": "Draft"
}
]
}
},
"credentials": {
"notionApi": {
"id": "AU61TARrYLYMxTj9",
"name": "Notion account"
}
},
"typeVersion": 2.2
},
{
"id": "4e43c32b-407c-4a62-8a0d-2b5eea10c615",
"name": "Mettre à jour une page de base de données",
"type": "n8n-nodes-base.notion",
"position": [
2320,
-432
],
"parameters": {
"pageId": {
"__rl": true,
"mode": "id",
"value": "={{ $('Create a Article Database Page').item.json.id }}"
},
"simple": false,
"options": {},
"resource": "databasePage",
"operation": "update",
"propertiesUi": {
"propertyValues": [
{
"key": "status|select",
"selectValue": "Published"
}
]
}
},
"credentials": {
"notionApi": {
"id": "AU61TARrYLYMxTj9",
"name": "Notion account"
}
},
"typeVersion": 2.2
},
{
"id": "c3dfe348-0a68-45ee-b538-2f72fdbffaa9",
"name": "Télécharger l'Image",
"type": "n8n-nodes-base.httpRequest",
"position": [
1648,
-432
],
"parameters": {
"url": "={{ $json.output[0] }}",
"options": {}
},
"typeVersion": 4.2
},
{
"id": "4b21b649-4087-4ef2-aa8d-9ee53c5db581",
"name": "Replicate Prédiction d'Image",
"type": "n8n-nodes-base.httpRequest",
"position": [
1424,
-432
],
"parameters": {
"url": "https://api.replicate.com/v1/models/black-forest-labs/flux-schnell/predictions",
"method": "POST",
"options": {
"response": {
"response": {
"responseFormat": "json"
}
}
},
"jsonBody": "={\n \"input\": {\n \"prompt\": \"{{ $json.message.content }}\",\n \"aspect_ratio\": \"16:9\"\n }\n}",
"sendBody": true,
"sendHeaders": true,
"specifyBody": "json",
"authentication": "genericCredentialType",
"genericAuthType": "httpBearerAuth",
"headerParameters": {
"parameters": [
{
"name": "Prefer",
"value": "wait"
},
{
"name": "Content-Type",
"value": "application/json"
}
]
}
},
"credentials": {
"httpBearerAuth": {
"id": "UMvkuuToRy2C4VYfo",
"name": "Bearer Auth Replicate"
}
},
"typeVersion": 4.2
},
{
"id": "2dd65c1f-d859-4809-857b-7f8b6e535306",
"name": "Créateur de Contenu",
"type": "@n8n/n8n-nodes-langchain.openAi",
"position": [
-208,
-304
],
"parameters": {
"modelId": {
"__rl": true,
"mode": "list",
"value": "gpt-5-mini",
"cachedResultName": "GPT-5-MINI"
},
"options": {},
"messages": {
"values": [
{
"content": "=You are a senior technical writer and LinkedIn ghostwriter for a Nepal-based DevOps/CloudOps/SysOps/Python developer who also loves AI/ML. \nYour job is to take one Notion row and turn it into:\n\n1) A polished, human-readable blog article for Hashnode (Markdown only).\n2) A LinkedIn post that feels authentic, insightful, and share-worthy, and most-importantly simpler english.\n\nYour voice should feel like a real engineer sharing something useful:\n- Informative but conversational\n- Confident but humble\n- Sometimes witty, but never forced\n- Includes actionable value (tips, insights, commands, lessons)\n- Occasionally adds light Nepali flavor naturally if language=\"ne\"\n\n---\n### INPUT\n- title: {{ $json.title }}\n- angle: {{ $json.angle }}\n- tags: {{ $json.tags }}\n- primary_link: {{ $json.primary_link }}\n- reference_links: {{ $json.reference_links }}\n- images: {{ $json.images }}\n- notes: {{ $json.notes }}\n- target_audience: {{ $json.target_audience }}\n- canonical_url: {{ $json.canonical_url }}\n- language: {{ $json.language }}\n- slug: {{ $json.slug }}\n\n---\n### PREFERENCES\n- LinkedIn posts ≤ 1200 characters\n- Blog word count:\n - Rich notes/tags: 900–1400 words\n - Sparse notes/tags: 600–900 words\n- Include at least one specific example, command, or actionable tip\n- Only one link allowed in LinkedIn text (if primary_link exists)\n\n---\n### STYLE TARGETS\nFor LinkedIn, pick the most natural style automatically:\n- **Story:** Small anecdote or lesson\n- **Industry Take:** Commentary with reflection\n- **Tech Breakdown:** Clear step-by-step with code/tips\n- **Basics:** Foundational guidance in checklist format\n- **Humor List:** Funny but relatable \"few techs\" overwhelm joke\n- **Optimization/Win:** Real-world result or improvement shared\n\n---\n### BLOG REQUIREMENTS\n- Markdown only, no frontmatter\n- Structure:\n - Hook intro (2–4 lines)\n - Clear sections with H2/H3\n - Include steps, code snippets, or bullet lists\n - Add “Sharp edges & gotchas” with realistic pitfalls\n - Include a mini case/example\n - End with actionable “Key Takeaways” (3–6 bullets)\n- Include:\n - SEO: slug, excerpt, keywords (5–10)\n - Suggested cover caption\n - Alt text suggestions for images\n - Canonical URL if provided\n\n---\n### LINKEDIN REQUIREMENTS\n- Start with a strong HOOK (1–2 lines), do not mention word itself like 'hook' or similar\n- Use short, human paragraphs\n- Include at least one actionable tip or fact\n- Invite engagement with a closing question or CTA\n- Add 5–10 hashtags, a mix of broad (#DevOps #Cloud) and niche (#AWS #Kubernetes #Observability)\n\n---\n### RULES\n- Never invent unknown facts\n- Prioritize clear, human language\n- Favor real-world examples over generic advice\n- Use emojis sparingly and purposefully (max 3)\n\n---\n### OUTPUT SCHEMA\n{\n \"blog\": {\n \"title\": \"string\",\n \"slug\": \"string\",\n \"excerpt\": \"string\",\n \"keywords\": [\"string\", \"...\"],\n \"canonical_url\": \"string|null\",\n \"suggested_cover_caption\": \"string\",\n \"image_alt_texts\": [\"string\", \"...\"],\n \"markdown\": \"string\"\n },\n \"linkedin\": {\n \"style_used\": \"story|industry_take|tech_breakdown|basics|humor_list|optimization\",\n \"final_text\": \"string\",\n \"alt_titles\": [\"string\",\"string\",\"string\"]\n },\n \"safety_flags\": []\n}"
}
]
},
"simplify": "={{ true }}",
"jsonOutput": true
},
"credentials": {
"openAiApi": {
"id": "1JMlq9LFlvNZ4n7z",
"name": "OpenAi account"
}
},
"typeVersion": 1.8
},
{
"id": "17809fd9-84d8-458b-a904-b497549c10dd",
"name": "Générateur de Prompt d'Image",
"type": "@n8n/n8n-nodes-langchain.openAi",
"position": [
1072,
-432
],
"parameters": {
"modelId": {
"__rl": true,
"mode": "list",
"value": "gpt-4.1-mini",
"cachedResultName": "GPT-4.1-MINI"
},
"options": {},
"messages": {
"values": [
{
"content": "={\n \"title\": \"{{$json.properties?.title?.title?.[0]?.plain_text || ''}}\",\n \"excerpt\": \"{{$json.properties?.excerpt?.rich_text?.[0]?.plain_text || ''}}\",\n \"linkedin_draft\": \"{{$json.properties?.linkedin_draft?.rich_text?.[0]?.plain_text || ''}}\",\n \"alt\": \"{{$json.properties?.image_alt_texts?.rich_text?.[0]?.plain_text || ''}}\",\n \"keywords\": \"{{$json.properties?.keywords?.multi_select?.map(k => k.name).join(', ') || ''}}\"\n}\n"
},
{
"role": "system",
"content": "You generate a single, realistic text-to-image prompt for the Replicate model black-forest-labs/flux-schnell, based on details from a LinkedIn post.\n\nRULES:\n- Output only the prompt as plain text, no JSON, no commentary.\n- Make the scene look photorealistic but clean and professional — perfect for LinkedIn.\n- Focus on key objects, actions, and environment described in the post (title, excerpt, alt, keywords).\n- Include subtle realistic elements (lighting, depth, perspective, color) but keep the layout minimal and balanced.\n- Never include any legible text, logos, watermarks, brand names, or faces.\n- Use soft professional lighting, shallow depth of field, and natural tones.\n- Keep it under ~900 characters.\n- Default to a 16:9 aspect ratio.\n"
}
]
}
},
"credentials": {
"openAiApi": {
"id": "1JMlq9LFlvNZ4n7z",
"name": "OpenAi account"
}
},
"typeVersion": 1.8
},
{
"id": "20246ca2-9171-4ba8-8009-f43a43296c59",
"name": "Message d'Échec",
"type": "n8n-nodes-base.gmail",
"position": [
-1232,
2272
],
"webhookId": "3fd774cb-ed1a-4d99-9680-46fed3bdeb82",
"parameters": {
"sendTo": "={{$json.execution?.error?.workflow?.data?.startData?.runData?.['Set (Configs)']?.[0]?.json?.EMAIL_TO || 'test@mail.com'}}",
"message": "=Node: {{$json.execution?.error?.node?.name}}\\nMessage: {{$json.execution?.error?.message}}\\nStack: {{$json.execution?.error?.stack}}\\nLast Payload: {{JSON.stringify($json.execution?.error?.node?.data, null, 2).slice(0,5000)}}",
"options": {},
"subject": "=Blog Pipeline ERROR: {{$json.execution?.error?.message || 'Unknown error'}}",
"emailType": "text"
},
"credentials": {
"gmailOAuth2": {
"id": "g6m2gV1BtMtEggjm",
"name": "Gmail account"
}
},
"typeVersion": 2.1
},
{
"id": "efd5db98-aa5e-46e4-9d6c-4708b8db08a4",
"name": "Note Adhésive",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1712,
-624
],
"parameters": {
"color": 4,
"width": 960,
"height": 832,
"content": "# INITIALIZATION & DATA COLLECTION\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n- Cron triggers daily at 7 PM\n- Set configs (DB IDs, email, LinkedIn settings)\n- Query Notion for unpublished ideas\n- Filter & clean the data\n- Count eligible posts\n\nIf no posts found → Send \"nothing to do\" email"
},
"typeVersion": 1
},
{
"id": "0c0f92c8-d1b4-4e11-86cf-dc32022e984b",
"name": "Note Adhésive1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-720,
-624
],
"parameters": {
"color": 4,
"width": 1024,
"height": 832,
"content": "# CONTENT PROCESSING & AI GENERATION\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n- Process ideas one by one (batch size: 1)\n- Normalize data for AI prompt\n- OpenAI creates:\n - Full blog post (Markdown)\n - LinkedIn post with hashtags\n - SEO keywords & metadata\n- Validate & parse AI output\n\nQuality control ensures perfect formatting"
},
"typeVersion": 1
},
{
"id": "69e0c3a8-1239-4283-8c64-7c8aa8c3ec4e",
"name": "If LinkedIn Vérification de Publication",
"type": "n8n-nodes-base.if",
"position": [
640,
-304
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "58a827f7-5153-4641-afbd-9bdf3d62ee2c",
"operator": {
"type": "boolean",
"operation": "equals"
},
"leftValue": "={{ $('Set (Configs)').item.json.LINKEDIN_PUBLISH || false }}",
"rightValue": true
}
]
}
},
"typeVersion": 2.2,
"alwaysOutputData": false
},
{
"id": "b3f96e1b-73d8-4153-84ef-952fd9785888",
"name": "Note Adhésive2",
"type": "n8n-nodes-base.stickyNote",
"position": [
336,
-624
],
"parameters": {
"color": 5,
"width": 608,
"height": 832,
"content": "# CONTENT STORAGE & PUBLISH DECISION\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n- Save AI content to Articles database\n- Check LINKEDIN_PUBLISH setting\n\nTwo paths:\nPUBLISH = TRUE → Auto-publish flow\nPUBLISH = FALSE → Draft review flow\n\nAll content safely stored in Notion first"
},
"typeVersion": 1
},
{
"id": "c663ee05-545d-4c1e-995d-26ed92ecba6d",
"name": "Note Adhésive3",
"type": "n8n-nodes-base.stickyNote",
"position": [
976,
-624
],
"parameters": {
"color": 5,
"width": 1536,
"height": 832,
"content": ""
},
"typeVersion": 1
},
{
"id": "995fee04-6be5-4b7b-ad46-6a0965696e5c",
"name": "Note Adhésive4",
"type": "n8n-nodes-base.stickyNote",
"position": [
1920,
-144
],
"parameters": {
"color": 5,
"width": 592,
"height": 352,
"content": "# PUBLISHING & COMPLETION\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\nAUTO-PUBLISH PATH:\n- Generate image prompt → Create image\n- Post to LinkedIn with image\n- Send success email\n- Mark as \"Published\"\n\nDRAFT PATH:\n- Email draft for review\n- Mark as \"Draft\"\n\nBoth paths ensure proper status tracking"
},
"typeVersion": 1
}
],
"pinData": {},
"connections": {
"6160be76-97f5-4f4c-bfa6-5e480080d854": {
"main": [
[
{
"node": "a7b80170-9832-46fb-85ba-8b87c5bd9da4",
"type": "main",
"index": 0
}
]
]
},
"52a1ad9c-cc6a-49a1-ab7f-9b3a8a2e8c2b": {
"main": [
[
{
"node": "a1a7482f-3868-402c-a05b-2535b8443ad7",
"type": "main",
"index": 0
}
]
]
},
"7e72fddb-7c81-4bf3-bd96-b02c3ebb53efa": {
"main": [
[
{
"node": "648ff7d2-a55e-4e0c-8b12-d3634d1f1b958",
"type": "main",
"index": 0
}
]
]
},
"219ddd0a-9ad8-4555-acf1-b002406738346": {
"main": [
[
{
"node": "c964ef88-6dea-4ea1-ad6c-2eef99b483646",
"type": "main",
"index": 0
}
]
]
},
"c3dfe348-0a68-45ee-b538-2f72fdbffaa9": {
"main": [
[
{
"node": "52a1ad9c-cc6a-49a1-ab7f-9b3a8a2e8c2b",
"type": "main",
"index": 0
}
]
]
},
"40b826f5-b1ef-490b-b208-f1754c1972d81": {
"main": [
[]
]
},
"2dd65c1f-d859-4809-857b-7f8b6e535306": {
"main": [
[
{
"node": "87a55a66-d609-47d2-a177-eddb4a7d9d560",
"type": "main",
"index": 0
}
]
]
},
"45e081e9-db15-4808-9c26-6f1089f23a0e": {
"main": [
[
{
"node": "7e72fddb-7c81-4bf3-bd96-b02c3ebb53efa",
"type": "main",
"index": 0
}
]
]
},
"a1a7482f-3868-402c-a05b-2535b8443ad7": {
"main": [
[
{
"node": "4e43c32b-407c-4a62-8a0d-2b5eea10c615",
"type": "main",
"index": 0
}
]
]
},
"3ab2103a-a358-415c-a4d1-1df7c3cb14f5": {
"main": [
[
{
"node": "2dd65c1f-d859-4809-857b-7f8b6e535306",
"type": "main",
"index": 0
}
]
]
},
"c964ef88-6dea-4ea1-ad6c-2eef99b483646": {
"main": [
[],
[
{
"node": "40b826f5-b1ef-490b-b208-f1754c1972d81",
"type": "main",
"index": 0
}
]
]
},
"e3a428a0-c52e-47f6-9281-1063f84e587c3": {
"main": [
[
{
"node": "3ab2103a-a358-415c-a4d1-1df7c3cb14f5",
"type": "main",
"index": 0
}
]
]
},
"87a55a66-d609-47d2-a177-eddb4a7d9d560": {
"main": [
[
{
"node": "128ee066-dca2-4c19-830b-621e3eafbbc0",
"type": "main",
"index": 0
}
]
]
},
"17809fd9-84d8-458b-a904-b497549c10dd": {
"main": [
[
{
"node": "4b21b649-4087-4ef2-aa8d-9ee53c5db581",
"type": "main",
"index": 0
}
]
]
},
"4e43c32b-407c-4a62-8a0d-2b5eea10c615": {
"main": [
[]
]
},
"7d00232e-be9d-4cdc-b072-eedc64dd79e3c": {
"main": [
[
{
"node": "e3a428a0-c52e-47f6-9281-1063f84e587c3",
"type": "main",
"index": 0
},
{
"node": "219ddd0a-9ad8-4555-acf1-b002406738346",
"type": "main",
"index": 0
}
]
]
},
"4b21b649-4087-4ef2-aa8d-9ee53c5db581": {
"main": [
[
{
"node": "c3dfe348-0a68-45ee-b538-2f72fdbffaa9",
"type": "main",
"index": 0
}
]
]
},
"69e0c3a8-1239-4283-8c64-7c8aa8c3ec4e": {
"main": [
[
{
"node": "17809fd9-84d8-458b-a904-b497549c10dd",
"type": "main",
"index": 0
}
],
[
{
"node": "6160be76-97f5-4f4c-bfa6-5e480080d854",
"type": "main",
"index": 0
}
]
]
},
"128ee066-dca2-4c19-830b-621e3eafbbc0": {
"main": [
[
{
"node": "69e0c3a8-1239-4283-8c64-7c8aa8c3ec4e",
"type": "main",
"index": 0
}
]
]
},
"017d6b4c-52f8-4238-abf1-95f44d08b182b": {
"main": [
[
{
"node": "20246ca2-9171-4ba8-8009-f43a43296c59",
"type": "main",
"index": 0
}
]
]
},
"648ff7d2-a55e-4e0c-8b12-d3634d1f1b958": {
"main": [
[
{
"node": "7d00232e-be9d-4cdc-b072-eedc64dd79e3c",
"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é - Création de contenu, 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
Sagar Budhathoki
@sbmagar13A DevOps and AI Engineer with a passion for automation, infrastructure as code, building resilient systems, and exploring AI agents & MCP technologies.
Partager ce workflow