This workflow corresponds to n8n.io template #9316 — we link there as the canonical source.
This workflow follows the Chainllm → HTTP Request 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 →
{
"id": "5qiiLNNCnMfa0ACi",
"name": "Auto-Summarize Blog Posts to Social Media with Gemma and Postiz",
"tags": [],
"nodes": [
{
"id": "4de18e8b-5e69-4635-8f9e-3c4b12ab82e9",
"name": "Postiz (Create Post)",
"type": "n8n-nodes-postiz.postiz",
"disabled": true,
"position": [
4656,
640
],
"parameters": {
"date": "2025-08-06T14:45:00",
"posts": {
"post": [
{
"value": {
"contentItem": [
{
"image": {
"imageItem": [
{
"id": "={{ $('Upload Image to Postiz').item.json.id }}",
"path": "={{ $('Upload Image to Postiz').item.json.path }}"
}
]
},
"content": "={{ $json.text ? $json.text : 'NO_TEXT' }} {{ $json.link ? $json.link : 'NO_LINK' }}"
}
]
},
"integrationId": "cmdt7mm7c0001uq6yoangez5f"
},
{
"value": {
"contentItem": [
{
"image": {
"imageItem": [
{
"id": "={{ $('Upload Image to Postiz').item.json.id }}",
"path": "={{ $('Upload Image to Postiz').item.json.path }}"
}
]
},
"content": "={{ $json.text ? $json.text : 'NO_TEXT' }} {{ $json.link ? $json.link : 'NO_LINK' }}"
}
]
},
"integrationId": "cmdrm2h2w0001mu75dqdghjh3"
},
{
"value": {
"contentItem": [
{
"image": {
"imageItem": [
{
"id": "={{ $('Upload Image to Postiz').item.json.id }}",
"path": "={{ $('Upload Image to Postiz').item.json.path }}"
}
]
},
"content": "={{ $json.text ? $json.text : 'NO_TEXT' }} {{ $json.link ? $json.link : 'NO_LINK' }}"
}
]
},
"integrationId": "cmdt8yk610001ql6kgzaipjy7"
},
{
"value": {
"contentItem": [
{
"image": {
"imageItem": [
{
"id": "={{ $('Upload Image to Postiz').item.json.id }}",
"path": "={{ $('Upload Image to Postiz').item.json.path }}"
}
]
},
"content": "={{ $json.text ? $json.text : 'NO_TEXT' }} {{ $json.link ? $json.link : 'NO_LINK' }}"
}
]
},
"settings": {
"setting": [
{
"key": "post_type",
"stringValue": "post"
},
{
"key": "collaborators",
"stringValue": "[]"
},
{
"key": "media_type",
"stringValue": "IMAGE"
},
{
"key": "shortLink",
"valueType": "boolean"
}
]
},
"integrationId": "cmdt88b790003uq6y4lyk97o0"
}
]
}
},
"executeOnce": false,
"notesInFlow": false,
"retryOnFail": false,
"typeVersion": 1,
"alwaysOutputData": false
},
{
"id": "6f8f2953-bb6d-46f0-8af7-16ffcbf8341f",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
96,
64
],
"parameters": {
"content": "Replace 'Blog's Name' and the URL with your own RSS feed details (e.g., your blog's RSS URL)."
},
"typeVersion": 1
},
{
"id": "3c46789a-12cc-4a29-ab28-68b5a963c8f2",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
448,
48
],
"parameters": {
"content": "This node fetches the RSS feed. Ensure the URL matches your blog\u2014update if needed for custom feeds."
},
"typeVersion": 1
},
{
"id": "dcbe57b4-3866-4053-9da1-874b2b7d6947",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
3472,
48
],
"parameters": {
"width": 256,
"content": "Customize the LLM prompt for your content niche (e.g., change tone, fallback summary, or hashtag style to fit your blog's theme)."
},
"typeVersion": 1
},
{
"id": "93f63cde-e055-42dd-90b4-d66637339258",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
3488,
384
],
"parameters": {
"content": "Select your preferred Ollama model (e.g., gemma3:12b or alternatives like LLaMA). Update credentials with your local Ollama API setup."
},
"typeVersion": 1
},
{
"id": "68bd2325-938e-42c5-88ef-46a8c556871f",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
3216,
48
],
"parameters": {
"content": "Adjust maxChars calculation, hashtag reserve (default 50 chars), or buffers if using different platforms/limits (e.g., increase for longer hashtags)."
},
"typeVersion": 1
},
{
"id": "b2e53420-7251-4a54-b744-b3c2b94aa4e4",
"name": "Sticky Note5",
"type": "n8n-nodes-base.stickyNote",
"position": [
4256,
48
],
"parameters": {
"content": "Update validation logic if your inputs vary (e.g., add checks for custom fields like text length, link format, or image presence)."
},
"typeVersion": 1
},
{
"id": "9387a000-5013-4a4f-8a6e-3a1de3808cb0",
"name": "Sticky Note6",
"type": "n8n-nodes-base.stickyNote",
"position": [
4544,
-160
],
"parameters": {
"width": 288,
"height": 368,
"content": "This node posts to social platforms via Postiz API\u2014crucial for the workflow!\n- Update URL if your Postiz instance differs (e.g., self-hosted endpoint).\n- Set authentication: Add your Postiz API credentials (no hardcoding keys!).\n- Customize jsonBody: Replace integration IDs (e.g., \"cmdt7mm7c0001uq6yoangez5f\" for Facebook) with your own from Postiz dashboard.\n- Adjust platform settings (e.g., \"__type\", \"post_type\") if adding/removing channels.\nTest with a sample post to verify."
},
"typeVersion": 1
},
{
"id": "9454c1b1-4780-44c8-b2fa-a8122fd3d145",
"name": "Sticky Note7",
"type": "n8n-nodes-base.stickyNote",
"position": [
4480,
448
],
"parameters": {
"width": 480,
"height": 400,
"content": "The \"Postiz (Create Post)\" node is deactivated due to a compatibility bug with Instagram's JSON payload in the Postiz-n8n integration (see GitHub issue https://github.com/gitroomhq/postiz-n8n/issues/7), which prevents reliable posting. Instead, the \"HTTP Request\" node directly calls the Postiz API for greater control and workaround flexibility. On one hand, this ensures stable posting across platforms; on the other, it requires manual JSON tweaks, potentially increasing setup complexity for users."
},
"typeVersion": 1
},
{
"id": "885a82ba-0ba1-47c9-99bf-44aeb21f7b78",
"name": "Split RSS Feed URLs into Items",
"type": "n8n-nodes-base.splitOut",
"position": [
384,
192
],
"parameters": {
"options": {},
"fieldToSplitOut": "[\"Blog's Name\"]"
},
"typeVersion": 1
},
{
"id": "eb7a97de-e95e-43f9-81f1-1559e000f7d8",
"name": "Fetch Latest RSS Feed Content",
"type": "n8n-nodes-base.rssFeedRead",
"position": [
576,
192
],
"parameters": {
"url": "https://blogsname.blogspot.com/feeds/posts/default",
"options": {}
},
"typeVersion": 1.1
},
{
"id": "c2c32dda-af3a-4988-bc6c-1a85ebfca720",
"name": "Normalize RSS Fields (Content & Link)",
"type": "n8n-nodes-base.set",
"position": [
3072,
176
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "00d04dc1-3f58-4027-8807-83d9e1f4fdae",
"name": "contentSnippet",
"type": "string",
"value": "={{ $json.contentSnippet }}"
},
{
"id": "1e12c8ec-8364-4523-a0c7-39e73bbed3f2",
"name": "link",
"type": "string",
"value": "={{ $json.link }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "52af44a5-f28a-42c0-8db4-2738959329f3",
"name": "Select Latest RSS Item by Date",
"type": "n8n-nodes-base.code",
"position": [
1584,
176
],
"parameters": {
"jsCode": "const items = $input.all();\nif (items.length === 0) return items;\nconst latestItem = items.sort((a, b) => new Date(b.json.pubDate) - new Date(a.json.pubDate))[0];\nreturn [latestItem];"
},
"typeVersion": 2
},
{
"id": "5fc6a338-fb38-4164-a88c-f9567c699753",
"name": "Generate Summary and Hashtags with LLM",
"type": "@n8n/n8n-nodes-langchain.chainLlm",
"position": [
3488,
176
],
"parameters": {
"text": "={\n \"promptType\": \"define\",\n \"text\": \"[\\n {\\n \\\"role\\\": \\\"system\\\",\\n \\\"content\\\": \\\"You summarize texts strictly under {{ $json.maxChars }} characters in a warm, engaging tone, then append exactly 3 relevant hashtags (e.g., #Tag1 #Tag2 #Tag3), then the link. Truncate if needed. Never exceed the limit. If empty, use fallback summary and tags.\\\"\\n },\\n {\\n \\\"role\\\": \\\"user\\\",\\n \\\"content\\\": \\\"Summarize this in under {{ $json.maxChars }} characters (text only; hashtags and link separate): {{ $json.contentSnippet || 'Discover health and wellbeing tips on our blog!' }}\\\\n\\\\nEnd with: #Hashtag1 #Hashtag2 #Hashtag3 {{ $json.link }}\\\"\\n }\\n]\",\n \"batching\": {}\n}",
"batching": {},
"promptType": "define"
},
"typeVersion": 1.7
},
{
"id": "dc4bfbda-76b8-425f-86c3-4dede50c5b39",
"name": "Configure Local LLM Model (Ollama)",
"type": "@n8n/n8n-nodes-langchain.lmOllama",
"position": [
3696,
448
],
"parameters": {
"model": "gemma3:12b",
"options": {}
},
"typeVersion": 1
},
{
"id": "a1d1e83e-98dd-4fc6-9b81-90519022f2be",
"name": "Calculate Summary Character Limit",
"type": "n8n-nodes-base.code",
"position": [
3296,
176
],
"parameters": {
"jsCode": "return items.map(item => {\n const link = item.json.link;\n const hashtagReserve = 50;\n item.json.maxChars = 280 - link.length - 20 - hashtagReserve;\n item.json.link = link;\n return item;\n});"
},
"typeVersion": 2
},
{
"id": "a400eee2-73f8-42ac-9381-e82043505fda",
"name": "Set RSS Feed URLs",
"type": "n8n-nodes-base.set",
"position": [
160,
192
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "e880cd01-0cc9-46bc-b714-117260be234c",
"name": "Blog's Name",
"type": "string",
"value": "https://blogsname.blogspot.com/feeds/posts/default"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "3ece393b-8584-4f7e-8b4e-ebe59720dd40",
"name": "Read Last Posted Hash from File",
"type": "n8n-nodes-base.code",
"position": [
2016,
176
],
"parameters": {
"jsCode": "const fs = require('fs');\nconst lastPath = '/.n8n/rss_last_posted.txt';\n\nreturn items.map(item => {\n let lastPostedHash = '';\n try {\n if (fs.existsSync(lastPath)) {\n lastPostedHash = fs.readFileSync(lastPath, 'utf8').trim();\n }\n console.log(\"Read lastPostedHash:\", lastPostedHash);\n } catch (error) {\n console.error(\"Failed to read last posted hash:\", error.message);\n }\n item.json.lastPostedHash = lastPostedHash;\n return item;\n});"
},
"typeVersion": 2
},
{
"id": "f1caf122-f0cf-41c4-8869-b875c3d9207f",
"name": "Save Posted Hash to File",
"type": "n8n-nodes-base.code",
"position": [
4928,
176
],
"parameters": {
"jsCode": "const fs = require('fs');\nconst lastPath = '/.n8n/rss_last_posted.txt';\nconst tempPath = '/.n8n/rss_temp_url.txt';\n\nreturn items.map(item => {\n let linkHash = item.json.linkHash || '';\n \n // Fallback: Read from temp file if linkHash is missing\n if (!linkHash && fs.existsSync(tempPath)) {\n try {\n linkHash = fs.readFileSync(tempPath, 'utf8').trim();\n console.log(\"Read linkHash from temp file:\", linkHash);\n } catch (error) {\n console.error(\"Failed to read temp file:\", error.message);\n }\n }\n \n if (linkHash) {\n try {\n fs.writeFileSync(lastPath, linkHash, 'utf8');\n console.log(\"Saved linkHash to rss_last_posted.txt:\", linkHash);\n } catch (error) {\n console.error(\"Failed to save linkHash:\", error.message);\n }\n } else {\n console.log(\"No linkHash available to save.\");\n }\n \n return item;\n});"
},
"typeVersion": 2
},
{
"id": "deece16b-a7fe-4447-a8b0-a8ddd5eca30c",
"name": "Calculate Link Hash for Duplication Check",
"type": "n8n-nodes-base.code",
"position": [
1808,
176
],
"parameters": {
"jsCode": "function simpleHash(str) {\n let hash = 0;\n for (let i = 0; i < str.length; i++) {\n const char = str.charCodeAt(i);\n hash = ((hash << 5) - hash) + char;\n hash = hash & hash; // Convert to 32-bit integer\n }\n return hash.toString(16);\n}\n\nreturn items.map(item => {\n const link = item.json.link || '';\n const linkHash = simpleHash(link.trim()); // Trim to remove trailing spaces\n item.json.linkHash = linkHash;\n console.log(\"Calculated linkHash:\", linkHash);\n return item;\n});"
},
"typeVersion": 2
},
{
"id": "f8608124-757d-479b-ba94-b76c62a7c615",
"name": "Compare Hashes for Duplicate Check",
"type": "n8n-nodes-base.code",
"position": [
2240,
176
],
"parameters": {
"jsCode": "const fs = require('fs');\nconst logPath = '/.n8n/debug_log.txt'; // Path to the debug log file\nconst lastPath = '/.n8n/rss_last_posted.txt';\n\nreturn items.map(item => {\n const linkHash = item.json.linkHash || '';\n let lastPostedHash = '';\n try {\n if (fs.existsSync(lastPath)) {\n lastPostedHash = fs.readFileSync(lastPath, 'utf8').trim();\n console.log(\"Comparison - linkHash:\", linkHash, \"lastPostedHash:\", lastPostedHash, \"File Exists:\", fs.existsSync(lastPath));\n } else {\n console.log(\"Comparison - File does not exist:\", lastPath);\n }\n } catch (error) {\n console.error(\"Failed to read last posted hash:\", error.message);\n }\n const shouldProceed = linkHash !== lastPostedHash;\n item.json.shouldProceed = shouldProceed;\n console.log(\"Comparison - shouldProceed:\", shouldProceed, \"Execution ID:\", $execution.id);\n\n // Log to file\n try {\n const logData = {\n timestamp: new Date().toISOString(),\n linkHash,\n lastPostedHash,\n shouldProceed\n };\n fs.appendFileSync(logPath, JSON.stringify(logData) + '\\n');\n console.log(\"Logged to debug_log.txt\");\n } catch (error) {\n console.error(\"Failed to write to debug_log.txt:\", error.message);\n }\n\n return item;\n});"
},
"typeVersion": 2
},
{
"id": "4fab8e26-a350-46bc-b0ca-d37dbf77533b",
"name": "Conditional Check for New Post",
"type": "n8n-nodes-base.code",
"position": [
2640,
176
],
"parameters": {
"jsCode": "const fs = require('fs');\nconst lastPath = '/.n8n/rss_last_posted.txt';\n\nreturn items.map(item => {\n const linkHash = item.json.linkHash || '';\n let lastPostedHash = '';\n try {\n if (fs.existsSync(lastPath)) {\n lastPostedHash = fs.readFileSync(lastPath, 'utf8').trim();\n console.log(\"Flow Control - linkHash:\", linkHash, \"lastPostedHash:\", lastPostedHash, \"File Exists:\", fs.existsSync(lastPath));\n } else {\n console.log(\"Flow Control - File does not exist:\", lastPath);\n }\n } catch (error) {\n console.error(\"Failed to read last posted hash:\", error.message);\n }\n const shouldProceed = linkHash !== lastPostedHash;\n item.json.shouldProceed = shouldProceed;\n console.log(\"Flow Control - shouldProceed:\", shouldProceed, \"Execution ID:\", $execution.id);\n\n // Only return items if they should proceed\n if (shouldProceed) {\n return item;\n }\n return null; // Null items are filtered out by n8n\n}).filter(item => item !== null);"
},
"typeVersion": 2
},
{
"id": "52765cc4-2f2f-4b75-823b-2ebbcb265fd9",
"name": "Extract Image URL from Post HTML",
"type": "n8n-nodes-base.code",
"position": [
1728,
432
],
"parameters": {
"jsCode": "return items.map(item => {\n let fullImageUrl = null;\n if (item.json.body) {\n const imgMatch = item.json.body.match(/<img[^>]+(?:data-original-height=\"\\d+\"[^>]*|data-original-width=\"\\d+\"[^>]*)*src=[\"'](.*?)[\"']/i);\n if (imgMatch && imgMatch[1]) {\n fullImageUrl = imgMatch[1].replace(/=w\\d+-h\\d+/, ''); // Simplified regex for clarity\n }\n }\n item.json.imageUrl = fullImageUrl || null;\n console.log('Extracted full image URL:', item.json.imageUrl);\n return item;\n});"
},
"typeVersion": 2
},
{
"id": "332fdb2c-4553-4ddd-b796-be1d46c08233",
"name": "Fetch Blog Post HTML Content",
"type": "n8n-nodes-base.httpRequest",
"position": [
1536,
432
],
"parameters": {
"url": "={{ $json.link }}",
"options": {
"response": {
"response": {
"responseFormat": "text",
"outputPropertyName": "body"
}
}
}
},
"typeVersion": 4.2
},
{
"id": "c4240336-7dda-4683-9eb4-fc5ce4f715f4",
"name": "Download Post Image",
"type": "n8n-nodes-base.httpRequest",
"position": [
2080,
432
],
"parameters": {
"url": "={{ $json.imageUrl }}",
"options": {
"response": {
"response": {
"responseFormat": "file"
}
}
}
},
"typeVersion": 4.2
},
{
"id": "4ff2834b-76c7-4522-b234-fb2923f300d5",
"name": "Transform/Resize Image for Upload",
"type": "n8n-nodes-base.editImage",
"position": [
2288,
432
],
"parameters": {
"width": 1080,
"height": 1080,
"options": {
"format": "jpeg",
"fileName": "=blog-image-{{ $execution.id }}.jpeg"
},
"operation": "resize"
},
"typeVersion": 1,
"alwaysOutputData": false
},
{
"id": "2bcb9f51-b0f4-415a-8fa2-4bf3a6a9538b",
"name": "Upload Image to Postiz",
"type": "n8n-nodes-postiz.postiz",
"position": [
2480,
432
],
"parameters": {
"operation": "uploadFile",
"binaryProperty": "={{ $('Transform/Resize Image for Upload').item.binary }}"
},
"typeVersion": 1
},
{
"id": "61deda9e-4fa7-446f-86b3-b7edb84065a4",
"name": "Filter Latest Item for Image Processing",
"type": "n8n-nodes-base.code",
"position": [
1904,
432
],
"parameters": {
"jsCode": "return items\n .filter(item => item.json.imageUrl && item.json.imageUrl !== null) // Ensure valid URL\n .sort((a, b) => new Date(b.json.pubDate) - new Date(a.json.pubDate)) // Sort by pubDate descending\n .slice(0, 1); // Take the latest item"
},
"typeVersion": 2
},
{
"id": "d2501d1e-d607-4585-8fb2-708ea989c389",
"name": "Loop Over RSS Items for Processing",
"type": "n8n-nodes-base.splitInBatches",
"position": [
1184,
384
],
"parameters": {
"options": {}
},
"executeOnce": true,
"typeVersion": 3
},
{
"id": "38beb7d1-53ee-4a95-9d76-e5d7b0d3574d",
"name": "Merge Processed Data Streams",
"type": "n8n-nodes-base.merge",
"position": [
1120,
176
],
"parameters": {
"mode": "combine",
"options": {
"includeUnpaired": true
},
"combineBy": "combineByPosition"
},
"typeVersion": 3.2
},
{
"id": "79a42cb0-45bf-496a-bf4f-b78cb1cbd054",
"name": "Create and Post Content via Postiz API",
"type": "n8n-nodes-base.httpRequest",
"position": [
4640,
176
],
"parameters": {
"url": "https://postiz.selfhosteddomain.net/api/public/v1/posts",
"method": "POST",
"options": {},
"jsonBody": "={\n \"type\": \"now\",\n \"date\": \"{{ new Date().toISOString() }}\",\n \"shortLink\": false,\n \"tags\": [],\n \"posts\": [\n {\n \"integration\": { \"id\": \"cmdt7mm7c0001uq6yoangez5f\" },\n \"value\": [\n {\n \"content\": \"{{ $json.text || 'NO_TEXT' }} {{ $json.link || 'NO_LINK' }} {{ $json.hashtags && Array.isArray($json.hashtags) ? $json.hashtags.join(' ') : '' }}\",\n \"image\": [\n {\n \"id\": \"{{ $('Upload Image to Postiz').item.json.id || '' }}\",\n \"path\": \"{{ $('Upload Image to Postiz').item.json.path || '' }}\",\n \"alt\": null,\n \"thumbnail\": null,\n \"thumbnailTimestamp\": null\n }\n ]\n }\n ],\n \"settings\": {\"__type\": \"facebook\"}\n },\n {\n \"integration\": { \"id\": \"cmdrm2h2w0001mu75dqdghjh3\" },\n \"value\": [\n {\n \"content\": \"{{ $json.text || 'NO_TEXT' }} {{ $json.link || 'NO_LINK' }} {{ $json.hashtags && Array.isArray($json.hashtags) ? $json.hashtags.join(' ') : '' }}\",\n \"image\": [\n {\n \"id\": \"{{ $('Upload Image to Postiz').item.json.id || '' }}\",\n \"path\": \"{{ $('Upload Image to Postiz').item.json.path || '' }}\",\n \"alt\": null,\n \"thumbnail\": null,\n \"thumbnailTimestamp\": null\n }\n ]\n }\n ],\n \"settings\": {\"__type\": \"linkedin-page\"}\n },\n {\n \"integration\": { \"id\": \"cmdt8yk610001ql6kgzaipjy7\" },\n \"value\": [\n {\n \"content\": \"{{ $json.text || 'NO_TEXT' }} {{ $json.link || 'NO_LINK' }} {{ $json.hashtags && Array.isArray($json.hashtags) ? $json.hashtags.join(' ') : '' }}\",\n \"image\": [\n {\n \"id\": \"{{ $('Upload Image to Postiz').item.json.id || '' }}\",\n \"path\": \"{{ $('Upload Image to Postiz').item.json.path || '' }}\",\n \"alt\": null,\n \"thumbnail\": null,\n \"thumbnailTimestamp\": null\n }\n ]\n }\n ],\n \"settings\": {\"__type\": \"x\"}\n },\n {\n \"integration\": { \"id\": \"cmdt88b790003uq6y4lyk97o0\" },\n \"value\": [\n {\n \"content\": \"{{ $json.text || 'NO_TEXT' }} {{ $json.hashtags && Array.isArray($json.hashtags) ? $json.hashtags.join(' ') : '' }} {{ $json.link || 'NO_LINK' }}\",\n \"image\": [\n {\n \"id\": \"{{ $('Upload Image to Postiz').item.json.id || '' }}\",\n \"path\": \"{{ $('Upload Image to Postiz').item.json.path || '' }}\",\n \"alt\": null,\n \"thumbnail\": null,\n \"thumbnailTimestamp\": null\n }\n ]\n }\n ],\n \"settings\": {\n \"post_type\": \"post\",\n \"collaborators\": [],\n \"media_type\": \"IMAGE\",\n \"__type\": \"instagram\"\n }\n }\n ]\n}",
"sendBody": true,
"sendHeaders": true,
"specifyBody": "json",
"authentication": "predefinedCredentialType",
"headerParameters": {
"parameters": [
{
"name": "Content-Type",
"value": "application/json"
}
]
},
"nodeCredentialType": "postizApi"
},
"typeVersion": 4.2
},
{
"id": "f1b0f139-e790-44a7-9365-1263180d7d30",
"name": "Validate Inputs for Postiz API",
"type": "n8n-nodes-base.code",
"position": [
4320,
176
],
"parameters": {
"jsCode": "const item = $input.item.json;\nconst upload = $('Upload Image to Postiz').item.json;\nconsole.log('Input validation:', { text: item.text, link: item.link, imageId: upload.id, imagePath: upload.path });\nif (!item.text || !item.link || !upload.id || !upload.path) {\n throw new Error(`Invalid input: text=${item.text}, link=${item.link}, image.id=${upload.id}, image.path=${upload.path}`);\n}\nreturn $input.item;"
},
"typeVersion": 2
},
{
"id": "bcf94463-572b-4cbd-bf9d-506609e98221",
"name": "Schedule: Check RSS Every 10 Minutes",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
-64,
192
],
"parameters": {
"rule": {
"interval": [
{
"field": "minutes",
"minutesInterval": 10
}
]
}
},
"typeVersion": 1.2
},
{
"id": "6e33f728-63bf-4682-b490-729826927a35",
"name": "Process LLM Output for Postiz (Extract Text/Hashtags/Link)",
"type": "n8n-nodes-base.code",
"position": [
3904,
176
],
"parameters": {
"jsCode": "function simpleHash(str) {\n let hash = 0;\n for (let i = 0; i < str.length; i++) {\n const char = str.charCodeAt(i);\n hash = ((hash << 5) - hash) + char;\n hash = hash & hash;\n }\n return hash.toString(16);\n}\n\nreturn items.map(item => {\n const inputText = item.json.text || \"No summary available\";\n const maxChars = item.json.maxChars || 200;\n let text = inputText;\n let link = item.json.link || \"\";\n let hashtags = [];\n console.log(\"Input text:\", inputText);\n const parts = inputText.split(\" \").filter(part => part.trim());\n const lastPart = parts[parts.length - 1];\n if (lastPart && lastPart.includes(\"http\")) {\n link = lastPart;\n hashtags = parts.slice(-4, -1).filter(part => part.startsWith(\"#\"));\n text = parts.slice(0, -4).join(\" \");\n } else if (parts.length >= 4) { // Fallback if link not detected\n hashtags = parts.slice(-3).filter(part => part.startsWith(\"#\"));\n text = parts.slice(0, -3).join(\" \");\n }\n if (hashtags.length !== 3) {\n console.warn(`Expected 3 hashtags, got ${hashtags.length}. Using defaults if needed.`);\n hashtags = [\"#Wellbeing\", \"#Health\", \"#Inspiration\"]; // Fallback\n }\n text = text.replace(/\\n/g, \" \").replace(/\"/g, '\\\\\"').trim().slice(0, maxChars);\n const linkHash = simpleHash(link);\n console.log(\"Processed - text:\", text, \"hashtags:\", hashtags, \"link:\", link, \"length:\", (text + \" \" + hashtags.join(\" \") + \" \" + link).length);\n return {\n json: {\n text: text,\n hashtags: hashtags,\n link: link,\n linkHash: linkHash,\n title: item.json.title || text.slice(0, 100),\n imageId: item.json.id || null\n }\n };\n});"
},
"typeVersion": 2
},
{
"id": "1852bc12-4f1f-47bd-bdb7-4a12c8f47801",
"name": "Save Temporary Link Hash to File",
"type": "n8n-nodes-base.code",
"position": [
4112,
176
],
"parameters": {
"jsCode": "const fs = require('fs');\nconst tempPath = '/.n8n/rss_temp_url.txt';\n\nreturn items.map(item => {\n const linkHash = item.json.linkHash || '';\n if (linkHash) {\n try {\n fs.writeFileSync(tempPath, linkHash, 'utf8');\n console.log(\"Wrote temp URL hash:\", linkHash);\n } catch (error) {\n console.error(\"Failed to write temp URL hash:\", error.message);\n }\n }\n console.log(\"Before Postiz - item.json:\", JSON.stringify(item.json));\n return item;\n});"
},
"typeVersion": 2
}
],
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "26882586-1d0d-43bc-b4df-78f5e75504a1",
"connections": {
"Set RSS Feed URLs": {
"main": [
[
{
"node": "Split RSS Feed URLs into Items",
"type": "main",
"index": 0
}
]
]
},
"Download Post Image": {
"main": [
[
{
"node": "Transform/Resize Image for Upload",
"type": "main",
"index": 0
}
]
]
},
"Upload Image to Postiz": {
"main": [
[
{
"node": "Loop Over RSS Items for Processing",
"type": "main",
"index": 0
}
]
]
},
"Fetch Blog Post HTML Content": {
"main": [
[
{
"node": "Extract Image URL from Post HTML",
"type": "main",
"index": 0
}
]
]
},
"Merge Processed Data Streams": {
"main": [
[
{
"node": "Select Latest RSS Item by Date",
"type": "main",
"index": 0
}
]
]
},
"Fetch Latest RSS Feed Content": {
"main": [
[
{
"node": "Loop Over RSS Items for Processing",
"type": "main",
"index": 0
},
{
"node": "Merge Processed Data Streams",
"type": "main",
"index": 1
}
]
]
},
"Conditional Check for New Post": {
"main": [
[
{
"node": "Normalize RSS Fields (Content & Link)",
"type": "main",
"index": 0
}
]
]
},
"Select Latest RSS Item by Date": {
"main": [
[
{
"node": "Calculate Link Hash for Duplication Check",
"type": "main",
"index": 0
}
]
]
},
"Split RSS Feed URLs into Items": {
"main": [
[
{
"node": "Fetch Latest RSS Feed Content",
"type": "main",
"index": 0
}
]
]
},
"Validate Inputs for Postiz API": {
"main": [
[
{
"node": "Create and Post Content via Postiz API",
"type": "main",
"index": 0
}
]
]
},
"Read Last Posted Hash from File": {
"main": [
[
{
"node": "Compare Hashes for Duplicate Check",
"type": "main",
"index": 0
}
]
]
},
"Extract Image URL from Post HTML": {
"main": [
[
{
"node": "Filter Latest Item for Image Processing",
"type": "main",
"index": 0
}
]
]
},
"Save Temporary Link Hash to File": {
"main": [
[
{
"node": "Validate Inputs for Postiz API",
"type": "main",
"index": 0
}
]
]
},
"Calculate Summary Character Limit": {
"main": [
[
{
"node": "Generate Summary and Hashtags with LLM",
"type": "main",
"index": 0
}
]
]
},
"Transform/Resize Image for Upload": {
"main": [
[
{
"node": "Upload Image to Postiz",
"type": "main",
"index": 0
}
]
]
},
"Compare Hashes for Duplicate Check": {
"main": [
[
{
"node": "Conditional Check for New Post",
"type": "main",
"index": 0
}
]
]
},
"Configure Local LLM Model (Ollama)": {
"ai_languageModel": [
[
{
"node": "Generate Summary and Hashtags with LLM",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Loop Over RSS Items for Processing": {
"main": [
[
{
"node": "Merge Processed Data Streams",
"type": "main",
"index": 0
}
],
[
{
"node": "Fetch Blog Post HTML Content",
"type": "main",
"index": 0
}
]
]
},
"Schedule: Check RSS Every 10 Minutes": {
"main": [
[
{
"node": "Set RSS Feed URLs",
"type": "main",
"index": 0
}
]
]
},
"Normalize RSS Fields (Content & Link)": {
"main": [
[
{
"node": "Calculate Summary Character Limit",
"type": "main",
"index": 0
}
]
]
},
"Create and Post Content via Postiz API": {
"main": [
[
{
"node": "Save Posted Hash to File",
"type": "main",
"index": 0
}
]
]
},
"Generate Summary and Hashtags with LLM": {
"main": [
[
{
"node": "Process LLM Output for Postiz (Extract Text/Hashtags/Link)",
"type": "main",
"index": 0
}
]
]
},
"Filter Latest Item for Image Processing": {
"main": [
[
{
"node": "Download Post Image",
"type": "main",
"index": 0
}
]
]
},
"Calculate Link Hash for Duplication Check": {
"main": [
[
{
"node": "Read Last Posted Hash from File",
"type": "main",
"index": 0
}
]
]
},
"Process LLM Output for Postiz (Extract Text/Hashtags/Link)": {
"main": [
[
{
"node": "Save Temporary Link Hash to File",
"type": "main",
"index": 0
}
]
]
}
}
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This workflow automates fetching the latest post from a Blogspot RSS feed, summarizes it with an LLM (e.g., Gemma via Ollama), extracts and uploads an image, generates three relevant hashtags, and posts to Facebook, LinkedIn, X (Twitter), and Instagram via the Postiz API.
Source: https://n8n.io/workflows/9316/ — 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.
Automatically scan major financial newswires for biotech catalyst events, score them with AI sentiment analysis, and surface ranked trade candidates — all without manual monitoring.
YOUTUBE GUIDE 📣 This template generates up to 2,000 AI-based stock images per day for under $4. It includes prompt generation, image creation, metadata enrichment, upload to Google Drive, and error lo
Categories Content Creation AI Automation Publishing Social Media
This n8n workflow automates the process of fetching, processing, and storing tech news articles from RSS feeds into a Notion database. It retrieves articles from The Verge and TechCrunch, processes th
This workflow is designed for Japanese-speaking professionals, and learners who want to efficiently stay up to date with practical productivity, lifehack, and efficiency-related insights from Japanese