Ghost Automated Blog System
Shared 11/23/2025
45 views
Visual Workflow
JSON Code
{
"meta": {
"instanceId": "16c94fc796f6fcebddc18ce2c5341407b495e2eab83e587fdaffb79601db3c8c"
},
"nodes": [
{
"id": "f2bdbd53-f9d0-4242-98d0-1774d7c5caca",
"name": "Schedule: Daily 09:00",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
0,
304
],
"parameters": {
"rule": {
"interval": [
{
"triggerAtHour": 9
}
]
}
},
"typeVersion": 1.2
},
{
"id": "0d09bc85-243b-4893-b594-52865168973e",
"name": "RSS Feed Source",
"type": "n8n-nodes-base.rssFeedRead",
"onError": "continueErrorOutput",
"position": [
304,
304
],
"parameters": {
"url": "https://techcrunch.com/feed/",
"options": {}
},
"retryOnFail": true,
"typeVersion": 1
},
{
"id": "074e3e54-29f2-439c-a460-72636a83d5cf",
"name": "NewsAPI Source",
"type": "n8n-nodes-base.httpRequest",
"onError": "continueErrorOutput",
"position": [
304,
512
],
"parameters": {
"url": "https://newsapi.org/v2/everything",
"options": {},
"sendQuery": true,
"queryParameters": {
"parameters": [
{
"name": "apiKey",
"value": "YOUR_NEWSAPI_KEY_HERE"
},
{
"name": "q",
"value": "(Technology OR AI OR Webdev)"
},
{
"name": "language",
"value": "en"
},
{
"name": "sortBy",
"value": "publishedAt"
},
{
"name": "from",
"value": "={{ new Date(Date.now() - 172800000).toISOString().split('T')[0] }}"
}
]
}
},
"typeVersion": 4.2
},
{
"id": "c355e27e-e881-4306-aca7-11d18248d0f4",
"name": "Filter Recent (48h)",
"type": "n8n-nodes-base.code",
"position": [
560,
304
],
"parameters": {
"jsCode": "// ============= 48 HOUR FILTER =============\n// Filters out articles older than 48 hours to ensure freshness\n\nconst now = new Date();\nconst cutoffTime = new Date(now.getTime() - (48 * 60 * 60 * 1000));\n\nconst kept = [];\n\nfor (const item of $input.all()) {\n const data = item.json;\n let dateString = data.pubDate || data.isoDate || data.published || data.date || data.updated || data.publishedAt;\n \n if (!dateString) continue;\n \n try {\n const articleDate = new Date(dateString);\n if (articleDate >= cutoffTime) {\n kept.push(item);\n }\n } catch (error) {}\n}\n\nreturn kept;"
},
"typeVersion": 2
},
{
"id": "45b90042-b885-4ce6-8ee9-cd7461ded61a",
"name": "Normalize NewsAPI",
"type": "n8n-nodes-base.code",
"position": [
560,
512
],
"parameters": {
"jsCode": "const now = new Date();\nconst scrapedAt = now.toISOString();\n\nconst newsData = $input.item.json;\n\nif (!newsData.articles || !Array.isArray(newsData.articles)) {\n return [];\n}\n\nconst normalizedArticles = newsData.articles.map(article => {\n return {\n title: article.title || '',\n url: article.url || '',\n pubDate: article.publishedAt || '',\n source: article.source?.name || '',\n summary: article.description || '',\n scrapedAt: scrapedAt\n };\n});\n\nreturn normalizedArticles.map(article => ({ json: article }));"
},
"typeVersion": 2
},
{
"id": "89886a77-e781-428f-8117-158b2037b41c",
"name": "Merge Sources",
"type": "n8n-nodes-base.merge",
"position": [
832,
400
],
"parameters": {},
"typeVersion": 3.2
},
{
"id": "fe23c2ed-2da2-4879-8b23-483e45410ae0",
"name": "Remove Duplicates",
"type": "n8n-nodes-base.code",
"position": [
1040,
400
],
"parameters": {
"jsCode": "// ============= DUPLICATE REMOVER =============\n// Removes exact duplicates and similar titles using fuzzy matching\n\nfunction similarity(s1, s2) {\n if (!s1 || !s2) return 0;\n const a = s1.toLowerCase();\n const b = s2.toLowerCase();\n if (a === b) return 100;\n if (a.includes(b) || b.includes(a)) return 90;\n return 0;\n}\n\nconst articles = $input.all();\nconst uniqueArticles = [];\nconst seenUrls = new Set();\nconst seenTitles = []; \n\nfor (const item of articles) {\n const article = item.json;\n const url = (article.url || article.link || '').trim();\n const title = (article.title || '').trim();\n\n if (!title || !url) continue;\n\n if (seenUrls.has(url)) continue;\n\n let isDuplicate = false;\n for (const seenTitle of seenTitles) {\n if (similarity(title, seenTitle) > 80) {\n isDuplicate = true;\n break;\n }\n }\n\n if (!isDuplicate) {\n seenUrls.add(url);\n seenTitles.push(title);\n uniqueArticles.push(item);\n }\n}\n\nreturn uniqueArticles;"
},
"typeVersion": 2
},
{
"id": "9aa015f6-72f2-4cef-b982-12b1de974f17",
"name": "Get Topic History",
"type": "n8n-nodes-base.airtable",
"position": [
1280,
624
],
"parameters": {
"base": {
"__rl": true,
"mode": "list",
"value": "appXXXXXXXXXXXXXX",
"cachedResultUrl": "https://airtable.com/",
"cachedResultName": "YOUR_BASE_NAME"
},
"table": {
"__rl": true,
"mode": "list",
"value": "tblXXXXXXXXXXXXXX",
"cachedResultUrl": "https://airtable.com/",
"cachedResultName": "YOUR_TABLE_NAME"
},
"options": {},
"operation": "search"
},
"credentials": {
"airtableTokenApi": {
"id": "LsOadaN5biaN8NBc",
"name": "Airtable Personal Access Token account"
}
},
"typeVersion": 2
},
{
"id": "6d901dd7-64f4-4b77-ac43-70f77f9898ce",
"name": "Prepare Data for AI",
"type": "n8n-nodes-base.code",
"position": [
1280,
400
],
"parameters": {
"jsCode": "// ============= PREPARE CONTEXT FOR AI =============\n\nconst allItems = $input.all();\n\n// 1. Extract History\nconst historyItem = allItems.find(item => item.json.history_string !== undefined);\nconst blogHistory = historyItem ? historyItem.json.history_string : \"No previous articles.\";\n\n// 2. Clean and Format News\nconst newsArticles = allItems\n .filter(item => {\n const data = item.json;\n if (data.history_string !== undefined) return false;\n if (data.timestamp) return false;\n if (!data.title) return false;\n return true;\n })\n .map(item => {\n const data = item.json;\n \n let summary = \n data.contentSnippet || \n data.summary || \n data.description || \n data['content:encodedSnippet'] || \n \"\";\n\n if (!summary && (data.content || data['content:encoded'])) {\n const rawContent = data.content || data['content:encoded'];\n summary = rawContent.replace(/<[^>]*>?/gm, '').substring(0, 400) + \"...\";\n }\n\n const url = data.link || data.url || data.guid;\n\n return {\n title: data.title,\n url: url,\n summary: summary ? summary.substring(0, 600) : \"No description available\",\n source: extractSource(url)\n };\n });\n\nfunction extractSource(url) {\n if (!url) return \"Unknown\";\n try {\n return new URL(url).hostname.replace('www.', '');\n } catch (e) { return \"Unknown\"; }\n}\n\nreturn [{\n json: {\n news_articles: newsArticles,\n blog_history: blogHistory,\n article_count: newsArticles.length\n }\n}];"
},
"typeVersion": 2
},
{
"id": "8eb9971e-0a2f-4ff2-a87f-19f4cceeb26d",
"name": "Merge News & History",
"type": "n8n-nodes-base.merge",
"position": [
1520,
480
],
"parameters": {},
"typeVersion": 3
},
{
"id": "a1eb5361-227f-487b-aff7-00e6ea515141",
"name": "Format Context",
"type": "n8n-nodes-base.code",
"position": [
1744,
480
],
"parameters": {
"jsCode": "// ============= FINAL CONTEXT MERGE =============\n\nconst allItems = $input.all();\n\nlet finalNewsList = [];\nlet historyTitles = [];\n\nfor (const item of allItems) {\n const data = item.json;\n\n if (data.news_articles && Array.isArray(data.news_articles)) {\n finalNewsList = data.news_articles;\n continue;\n }\n\n if (data.id && (data.title || data.Title || data.Titel)) {\n historyTitles.push(data.title || data.Title || data.Titel);\n continue;\n }\n}\n\nconst historyString = historyTitles.length > 0 \n ? historyTitles.join(\", \") \n : \"No previous articles.\";\n\nreturn [{\n json: {\n news_articles: finalNewsList,\n blog_history: historyString,\n stats: `Analyzing ${finalNewsList.length} articles against ${historyTitles.length} history items`\n }\n}];"
},
"typeVersion": 2
},
{
"id": "b9dc1f9c-d9ad-4509-afdb-3f03f4332a19",
"name": "Agent 1: Topic Scout",
"type": "@n8n/n8n-nodes-langchain.agent",
"maxTries": 3,
"position": [
2128,
480
],
"parameters": {
"text": "=ROLE:\nYou are an expert SEO Strategist and Content Scout.\n\nGOAL:\nAnalyze the provided news articles and select the single best topic for a high-traffic blog post.\n\nINPUTS:\n1. Available News: {{ JSON.stringify($json.news_articles) }}\n2. ALREADY COVERED TOPICS (DO NOT REPEAT): {{ $json.blog_history }}\n\nRULES:\n- Do NOT select a topic that is semantically identical to the \"Already Covered\" list.\n- Focus on high-impact topics (AI, Performance, Tools, Major Updates).\n- Look for \"Pain Points\" or \"Solutions\" (e.g., instead of \"New Astro Version\", choose \"Why your site is slow\").\n\nOUTPUT JSON:\n- title: SEO-optimized working title.\n- description: Brief context of why this matters now.\n- keywords: Array of 3-5 high-volume keywords.\n- source_urls: Array of URLs used for research.",
"options": {
"systemMessage": "You are an SEO expert. Think in terms of 'Search Intent' and 'User Problems', not just news headlines."
},
"promptType": "define",
"hasOutputParser": true
},
"retryOnFail": true,
"typeVersion": 1.7
},
{
"id": "9fa8a6c2-3051-4a09-994e-24f1d2a5cafc",
"name": "Gemini Pro (Topic)",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenRouter",
"position": [
2064,
704
],
"parameters": {
"model": "google/gemini-3-pro-preview",
"options": {}
},
"credentials": {
"openRouterApi": {
"id": "CErK3KqUFAxPvsBg",
"name": "AIAGENTKEY"
}
},
"typeVersion": 1
},
{
"id": "b93225e8-5ffe-477b-97bc-f8d3458dce9a",
"name": "Topic Parser",
"type": "@n8n/n8n-nodes-langchain.outputParserStructured",
"position": [
2192,
704
],
"parameters": {
"autoFix": true,
"schemaType": "manual",
"inputSchema": "{\n \"type\": \"object\",\n \"properties\": {\n \"title\": { \"type\": \"string\" },\n \"description\": { \"type\": \"string\" },\n \"keywords\": { \"type\": \"array\", \"items\": { \"type\": \"string\" } },\n \"source_urls\": { \"type\": \"array\", \"items\": { \"type\": \"string\" } }\n }\n}"
},
"typeVersion": 1.2
},
{
"id": "712a9f57-6d93-4ca9-b16a-b32719e95cfc",
"name": "Agent 2: Ghost Writer",
"type": "@n8n/n8n-nodes-langchain.agent",
"maxTries": 3,
"position": [
2592,
480
],
"parameters": {
"text": "=WRITE A BLOG POST ABOUT:\nTitle: {{ $json.output.title }}\nContext: {{ $json.output.description }}\nKeywords: {{ $json.output.keywords.join(', ') }}\n\nā ļø PRIMARY RULE: YOU ARE NOT A CHATBOT. YOU ARE A CMS OPERATOR.\nYOUR GOAL IS TO EXECUTE THE `Create Post` TOOL. ONLY THEN IS THE JOB DONE.\n\nPROCESS (Step-by-Step):\n\n1. RESEARCH (Perplexity Tool) - MANDATORY:\nFind hard facts, stats, and studies.\n- Search for: \"Benchmarks 2025\", \"Stats\", \"Costs of...\"\n\n2. THE \"HOOK\" (Engaging & Witty):\nStart with a bang. Be professional but approachable.\n- Example: \"Still using [Old Tech]? That's like bringing a knife to a laser fight.\"\n\n3. BODY CONTENT (Structured):\n- **The Problem:** Empathize with the reader's pain points.\n- **The Solution:** Explain the new tech/solution simply.\n- **Evidence:** Use the facts found via Perplexity.\n\n4. CITATIONS (IMPORTANT):\nLink directly to sources in the text.\nFormat: `...as seen in <a href=\"SOURCE_URL\">this study</a>.`\n\n5. FORMATTING (STRICT):\n- NO Markdown blocks. Pure HTML tags (<h2>, <p>, <ul>).\n- Use standard hyphens (-), never em-dashes.\n\n6. PUBLISH (Ghost Tool) - FINALE:\nUse the `Create Post` tool immediately:\n- Title: Click-worthy title (Max 60 chars).\n- Content: Your HTML text.\n- Meta Info: Filled out for SEO.\n\nDO NOT RETURN TEXT TO ME. EXECUTE THE TOOL.",
"options": {
"systemMessage": "You are a Senior Tech Blogger. \nSTYLE:\n- Smart, witty, but professional.\n- Data-driven (you love stats).\n- Helpful and clear.\n\nRULES:\n1. Use HTML for formatting.\n2. Cite your sources with hyperlinks.\n3. USE THE GHOST TOOL TO SAVE."
},
"promptType": "define",
"hasOutputParser": true
},
"retryOnFail": true,
"typeVersion": 1.7
},
{
"id": "b38d5de9-770d-46d9-bbf3-dd5d9e5b072c",
"name": "Perplexity Research",
"type": "n8n-nodes-base.perplexityTool",
"position": [
2672,
720
],
"parameters": {
"options": {},
"messages": {
"message": [
{
"content": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('message0_Text', ``, 'string') }}"
}
]
},
"simplify": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Simplify_Output', ``, 'boolean') }}",
"requestOptions": {}
},
"credentials": {
"perplexityApi": {
"id": "SzbdkunqZ8JO1GFv",
"name": "Perplexity account"
}
},
"typeVersion": 1
},
{
"id": "07881b33-f0c0-4c4d-bf7f-3f35575da751",
"name": "Create Post",
"type": "n8n-nodes-base.ghostTool",
"position": [
2816,
720
],
"parameters": {
"title": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Title', ``, 'string') }}",
"source": "adminApi",
"content": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Content', ``, 'string') }}",
"operation": "create",
"additionalFields": {
"status": "draft",
"meta_title": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Meta_Title', ``, 'string') }}",
"meta_description": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Meta_Description', `Focus on very good SEO`, 'string') }}"
}
},
"credentials": {
"ghostAdminApi": {
"id": "uQZxY3Tst7oKZFVx",
"name": "Ghost Admin account"
}
},
"typeVersion": 1
},
{
"id": "1a545970-c854-4342-b630-31b6cd7e96ed",
"name": "Post Output Parser",
"type": "@n8n/n8n-nodes-langchain.outputParserStructured",
"position": [
2752,
624
],
"parameters": {
"autoFix": true,
"schemaType": "manual",
"inputSchema": "{\n \"type\": \"object\",\n \"properties\": {\n \"title\": { \"type\": \"string\" },\n \"id\": { \"type\": \"string\", \"description\": \"Ghost Post ID\" },\n \"updated_at\": { \"type\": \"string\", \"description\": \"Ghost updated_at timestamp\" },\n \"content_html\": { \"type\": \"string\" },\n \"meta_description\": { \"type\": \"string\" }\n }\n}"
},
"typeVersion": 1.2
},
{
"id": "7bf516ad-af92-4d5a-84b2-80b95b0e0ca7",
"name": "Save to History",
"type": "n8n-nodes-base.airtable",
"position": [
3072,
240
],
"parameters": {
"base": {
"__rl": true,
"mode": "list",
"value": "appXXXXXXXXXXXXXX",
"cachedResultUrl": "https://airtable.com/",
"cachedResultName": "YOUR_BASE_NAME"
},
"table": {
"__rl": true,
"mode": "list",
"value": "tblXXXXXXXXXXXXXX",
"cachedResultUrl": "https://airtable.com/",
"cachedResultName": "YOUR_TABLE_NAME"
},
"columns": {
"value": {
"title": "={{ $json.output.title }}",
"summary": "={{ $json.output.meta_description }}"
},
"schema": [
{
"id": "title",
"type": "string",
"display": true,
"removed": false,
"readOnly": false,
"required": false,
"displayName": "title",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "summary",
"type": "string",
"display": true,
"removed": false,
"readOnly": false,
"required": false,
"displayName": "summary",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "create"
},
"credentials": {
"airtableTokenApi": {
"id": "LsOadaN5biaN8NBc",
"name": "Airtable Personal Access Token account"
}
},
"typeVersion": 2
},
{
"id": "78c0cea3-96c7-46e1-b605-d960d110d585",
"name": "Agent 3: Image Prompter",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
3072,
672
],
"parameters": {
"text": "=ROLE:\nYou are a Minimalist Art Director for a Tech Blog.\n\nTASK:\nCreate an image generation prompt based on the blog post title.\n\nINPUT:\nTITLE: {{ $json.output.title }}\n\nINSTRUCTIONS:\n1. **Visual Metaphor:** Abstract geometry, physics, glass, metal. No people.\n2. **Typography:** Incorporate a key word from the title on a physical object in the scene (e.g. embossed on metal).\n3. **Vibe:** Dark mode, premium, cinematic lighting, 8k resolution, unreal engine render.\n\nOUTPUT:\nWrite ONLY the English image prompt.",
"options": {},
"promptType": "define",
"hasOutputParser": true
},
"typeVersion": 3
},
{
"id": "6f950b47-4dac-466e-a2e9-9c997977694b",
"name": "Gemini Flash (Fast)",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenRouter",
"position": [
3088,
880
],
"parameters": {
"model": "google/gemini-2.5-flash",
"options": {}
},
"credentials": {
"openRouterApi": {
"id": "CErK3KqUFAxPvsBg",
"name": "AIAGENTKEY"
}
},
"typeVersion": 1
},
{
"id": "620f5b72-f03c-4b25-8697-d91ad277c98e",
"name": "Submit to Flux/Fal.ai",
"type": "n8n-nodes-base.httpRequest",
"position": [
3552,
672
],
"parameters": {
"url": "https://queue.fal.run/fal-ai/nano-banana-pro",
"method": "POST",
"options": {},
"sendBody": true,
"sendHeaders": true,
"bodyParameters": {
"parameters": [
{
"name": "prompt",
"value": "={{ $json.output }}"
},
{
"name": "num_images",
"value": "1"
},
{
"name": "aspect_ratio",
"value": "16:9"
},
{
"name": "resolution",
"value": "4K"
},
{
"name": "output_format",
"value": "png"
}
]
},
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "Key YOUR_FAL_AI_KEY_HERE"
}
]
}
},
"typeVersion": 4.2
},
{
"id": "d795880e-f535-4e21-a93b-cfdece91e015",
"name": "Wait 5s",
"type": "n8n-nodes-base.wait",
"position": [
3744,
672
],
"webhookId": "wait-initial-5s",
"parameters": {},
"typeVersion": 1.1
},
{
"id": "7acb7ea8-c7f7-4f4b-aebb-29ba07bbd195",
"name": "Check Status",
"type": "n8n-nodes-base.httpRequest",
"position": [
3936,
672
],
"parameters": {
"url": "=https://queue.fal.run/fal-ai/nano-banana-pro/requests/{{ $json.request_id }}/status",
"options": {
"response": {
"response": {
"neverError": true
}
}
},
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "Key YOUR_FAL_AI_KEY_HERE"
}
]
}
},
"typeVersion": 4.2,
"alwaysOutputData": true
},
{
"id": "7255f42a-8f00-4cd1-b507-aabaf78c0cb4",
"name": "Is Completed?",
"type": "n8n-nodes-base.if",
"position": [
4128,
672
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "87c816eb-48f6-4f37-9095-199b237a6fb8",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.status }}",
"rightValue": "COMPLETED"
}
]
}
},
"typeVersion": 2.2
},
{
"id": "db8f7213-2700-4ab5-b8b4-4dc9d13b4606",
"name": "Retry Wait",
"type": "n8n-nodes-base.wait",
"position": [
4128,
864
],
"webhookId": "wait-retry-3s",
"parameters": {
"amount": 3
},
"typeVersion": 1.1
},
{
"id": "7702d521-f248-45b8-b745-63ed7c9a1e41",
"name": "Get Result",
"type": "n8n-nodes-base.httpRequest",
"position": [
4352,
672
],
"parameters": {
"url": "=https://queue.fal.run/fal-ai/nano-banana-pro/requests/{{ $json.request_id }}",
"options": {},
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "Key YOUR_FAL_AI_KEY_HERE"
}
]
}
},
"typeVersion": 4.2
},
{
"id": "ce967214-5311-4886-9b31-82a0a2bbc176",
"name": "Split Images",
"type": "n8n-nodes-base.splitOut",
"position": [
4544,
672
],
"parameters": {
"options": {},
"fieldToSplitOut": "images"
},
"typeVersion": 1
},
{
"id": "cd670982-2967-4e3f-9790-6855c463be8a",
"name": "Download Image",
"type": "n8n-nodes-base.httpRequest",
"position": [
4752,
672
],
"parameters": {
"url": "={{ $json.url }}",
"options": {
"response": {
"response": {
"responseFormat": "file"
}
}
}
},
"typeVersion": 4.2
},
{
"id": "1422a835-eccc-47a9-b8f2-eb4ec8959b51",
"name": "Upload to Ghost",
"type": "n8n-nodes-base.httpRequest",
"position": [
4944,
672
],
"parameters": {
"url": "https://YOUR-GHOST-BLOG.com/ghost/api/admin/images/upload/",
"method": "POST",
"options": {
"response": {
"response": {
"responseFormat": "json"
}
}
},
"sendBody": true,
"contentType": "multipart-form-data",
"authentication": "predefinedCredentialType",
"bodyParameters": {
"parameters": [
{
"name": "file",
"parameterType": "formBinaryData",
"inputDataFieldName": "data"
},
{
"name": "purpose",
"value": "image"
},
{
"name": "ref",
"value": "={{ $('Agent 2: Ghost Writer').item.json.output.id }}"
}
]
},
"nodeCredentialType": "ghostAdminApi"
},
"credentials": {
"ghostAdminApi": {
"id": "uQZxY3Tst7oKZFVx",
"name": "Ghost Admin account"
}
},
"typeVersion": 4.2,
"alwaysOutputData": true
},
{
"id": "e922118c-84e8-435b-983e-dc7bee8ad868",
"name": "Update Post with Image",
"type": "n8n-nodes-base.httpRequest",
"position": [
5168,
672
],
"parameters": {
"url": "={{ 'https://YOUR-GHOST-BLOG.com/ghost/api/admin/posts/' + $('Agent 2: Ghost Writer').item.json.output.id + '/' }}",
"method": "PUT",
"options": {
"response": {
"response": {
"responseFormat": "json"
}
}
},
"jsonBody": "={\n \"posts\": [{\n \"feature_image\": \"{{ $json.images[0].url }}\",\n \"updated_at\": \"{{ $('Agent 2: Ghost Writer').item.json.output.updated_at }}\"\n }]\n}",
"sendBody": true,
"specifyBody": "json",
"authentication": "predefinedCredentialType",
"nodeCredentialType": "ghostAdminApi"
},
"credentials": {
"ghostAdminApi": {
"id": "uQZxY3Tst7oKZFVx",
"name": "Ghost Admin account"
}
},
"typeVersion": 4.2,
"alwaysOutputData": true
},
{
"id": "07aa7c94-7ecf-4a07-ba61-5e8c01f949ad",
"name": "Sticky Note: Intro",
"type": "n8n-nodes-base.stickyNote",
"position": [
-608,
112
],
"parameters": {
"color": 5,
"width": 480,
"height": 432,
"content": "### š Start Here: Setup Instructions\n\n**1. News Sources:**\nConfigure the RSS Node with your favorite Feed URL. Configure the NewsAPI Node with your API Key.\n\n**2. AI Models:**\nEnsure you have an OpenRouter or OpenAI credential set up in the AI Agent nodes.\n\n**3. Ghost & Airtable:**\nAdd your Ghost Admin Credentials and Airtable Token. \n\n*Goal: This workflow automatically finds trending topics, checks your history to avoid duplicates, writes a full article, and generates a matching cover image.*"
},
"typeVersion": 1
},
{
"id": "fa8f855a-5dbd-4bff-b76f-b4377b3a126f",
"name": "Sticky Note: Sources",
"type": "n8n-nodes-base.stickyNote",
"position": [
240,
-16
],
"parameters": {
"color": 4,
"width": 484,
"height": 804,
"content": "### š° Step 1: News Sources\n\nGet data from RSS and NewsAPI.\n\n**Action Required:**\n- Enter your NewsAPI Key in the `NewsAPI Source` node.\n- Enter your Feed URL in the `RSS Feed Source` node."
},
"typeVersion": 1
},
{
"id": "63abb65c-2933-4c7c-8e37-6d6fcffc024a",
"name": "Sticky Note: Scout",
"type": "n8n-nodes-base.stickyNote",
"position": [
2016,
208
],
"parameters": {
"color": 3,
"width": 444,
"height": 704,
"content": "### š§ Step 2: Topic Scout\n\nThis AI Agent compares new news against your Airtable history.\n\n**Model:** Gemini 3 Pro (Review).\n**Logic:** Finds the best SEO opportunity that you haven't written about yet."
},
"typeVersion": 1
},
{
"id": "0a4dc56b-2cf5-4152-925e-05683f5919e5",
"name": "Sticky Note: Writer",
"type": "n8n-nodes-base.stickyNote",
"position": [
2496,
208
],
"parameters": {
"color": 2,
"width": 508,
"height": 704,
"content": "### āļø Step 3: Ghost Writer\n\nDrafts the full article using Perplexity for facts.\n\n**Model:** Claude 3.5 Sonnet / GPT-5.\n**Tools:** Perplexity (Research), Ghost (Create Draft)."
},
"typeVersion": 1
},
{
"id": "d47f31a4-ec61-4119-82fa-11d4cc9d7b31",
"name": "Sticky Note: Art",
"type": "n8n-nodes-base.stickyNote",
"position": [
3040,
480
],
"parameters": {
"color": 6,
"width": 676,
"height": 528,
"content": "### šØ Step 4: Art Director\n\nGenerates a prompt, creates the image via Fal.ai, and uploads it to Ghost.\n\n**Model:** Gemini Flash (Fast).\n**Action:** Add your Fal.ai Key in the HTTP nodes."
},
"typeVersion": 1
},
{
"id": "45f439a1-bbae-4cc5-b8b6-9575e72193d8",
"name": "Claude Sonnet 4.5 (Writer)",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenRouter",
"position": [
2544,
720
],
"parameters": {
"model": "anthropic/claude-sonnet-4.5",
"options": {
"topP": 1,
"maxTokens": -1,
"temperature": 0.7,
"presencePenalty": 0,
"frequencyPenalty": 0
}
},
"credentials": {
"openRouterApi": {
"id": "CErK3KqUFAxPvsBg",
"name": "AIAGENTKEY"
}
},
"typeVersion": 1
},
{
"id": "75d0b341-3f7b-49a6-af13-186c1a3a5928",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
4704,
400
],
"parameters": {
"width": 704,
"height": 464,
"content": "### š¼ļø Image Pipeline & Ghost Upload\n\nSince Ghost does not automatically import images from external URLs, the upload process requires 3 specific steps:\n\n1. **Download:** Retrieves the generated image from Fal.ai as a binary file. \n2. **Upload:** Sends the binary data to the Ghost API (/images/upload). Ghost returns the internal file path. \n3. **Update:** Updates the previously drafted post via a PUT request, setting the feature_image to the new local path."
},
"typeVersion": 1
}
],
"pinData": {},
"connections": {
"Wait 5s": {
"main": [
[
{
"node": "Check Status",
"type": "main",
"index": 0
}
]
]
},
"Get Result": {
"main": [
[
{
"node": "Split Images",
"type": "main",
"index": 0
}
]
]
},
"Retry Wait": {
"main": [
[
{
"node": "Check Status",
"type": "main",
"index": 0
}
]
]
},
"Create Post": {
"ai_tool": [
[
{
"node": "Agent 2: Ghost Writer",
"type": "ai_tool",
"index": 0
}
]
]
},
"Check Status": {
"main": [
[
{
"node": "Is Completed?",
"type": "main",
"index": 0
}
]
]
},
"Split Images": {
"main": [
[
{
"node": "Download Image",
"type": "main",
"index": 0
}
]
]
},
"Topic Parser": {
"ai_outputParser": [
[
{
"node": "Agent 1: Topic Scout",
"type": "ai_outputParser",
"index": 0
}
]
]
},
"Is Completed?": {
"main": [
[
{
"node": "Get Result",
"type": "main",
"index": 0
}
],
[
{
"node": "Retry Wait",
"type": "main",
"index": 0
}
]
]
},
"Merge Sources": {
"main": [
[
{
"node": "Filter Recent (48h)",
"type": "main",
"index": 0
}
]
]
},
"Download Image": {
"main": [
[
{
"node": "Upload to Ghost",
"type": "main",
"index": 0
}
]
]
},
"Format Context": {
"main": [
[
{
"node": "Agent 1: Topic Scout",
"type": "main",
"index": 0
}
]
]
},
"NewsAPI Source": {
"main": [
[
{
"node": "Normalize NewsAPI",
"type": "main",
"index": 0
}
]
]
},
"RSS Feed Source": {
"main": [
[
{
"node": "Merge Sources",
"type": "main",
"index": 0
}
]
]
},
"Upload to Ghost": {
"main": [
[
{
"node": "Update Post with Image",
"type": "main",
"index": 0
}
]
]
},
"Get Topic History": {
"main": [
[
{
"node": "Merge News & History",
"type": "main",
"index": 1
}
]
]
},
"Normalize NewsAPI": {
"main": [
[
{
"node": "Merge Sources",
"type": "main",
"index": 1
}
]
]
},
"Remove Duplicates": {
"main": [
[
{
"node": "Prepare Data for AI",
"type": "main",
"index": 0
},
{
"node": "Get Topic History",
"type": "main",
"index": 0
}
]
]
},
"Gemini Pro (Topic)": {
"ai_languageModel": [
[
{
"node": "Agent 1: Topic Scout",
"type": "ai_languageModel",
"index": 0
},
{
"node": "Topic Parser",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Post Output Parser": {
"ai_outputParser": [
[
{
"node": "Agent 2: Ghost Writer",
"type": "ai_outputParser",
"index": 0
}
]
]
},
"Filter Recent (48h)": {
"main": [
[
{
"node": "Remove Duplicates",
"type": "main",
"index": 0
}
]
]
},
"Gemini Flash (Fast)": {
"ai_languageModel": [
[
{
"node": "Agent 3: Image Prompter",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Perplexity Research": {
"ai_tool": [
[
{
"node": "Agent 2: Ghost Writer",
"type": "ai_tool",
"index": 0
}
]
]
},
"Prepare Data for AI": {
"main": [
[
{
"node": "Merge News & History",
"type": "main",
"index": 0
}
]
]
},
"Agent 1: Topic Scout": {
"main": [
[
{
"node": "Agent 2: Ghost Writer",
"type": "main",
"index": 0
}
]
]
},
"Merge News & History": {
"main": [
[
{
"node": "Format Context",
"type": "main",
"index": 0
}
]
]
},
"Agent 2: Ghost Writer": {
"main": [
[
{
"node": "Save to History",
"type": "main",
"index": 0
},
{
"node": "Agent 3: Image Prompter",
"type": "main",
"index": 0
}
]
]
},
"Schedule: Daily 09:00": {
"main": [
[
{
"node": "RSS Feed Source",
"type": "main",
"index": 0
},
{
"node": "NewsAPI Source",
"type": "main",
"index": 0
}
]
]
},
"Submit to Flux/Fal.ai": {
"main": [
[
{
"node": "Wait 5s",
"type": "main",
"index": 0
}
]
]
},
"Agent 3: Image Prompter": {
"main": [
[
{
"node": "Submit to Flux/Fal.ai",
"type": "main",
"index": 0
}
]
]
},
"Claude Sonnet 4.5 (Writer)": {
"ai_languageModel": [
[
{
"node": "Agent 2: Ghost Writer",
"type": "ai_languageModel",
"index": 0
},
{
"node": "Post Output Parser",
"type": "ai_languageModel",
"index": 0
}
]
]
}
}
}