This workflow corresponds to n8n.io template #13103 — we link there as the canonical source.
This workflow follows the Notion → OpenAI 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": "Rq90UFhzDszsXRyyx5SgZ",
"name": "Generate weekly content calendar with AI from RSS feeds",
"tags": [],
"nodes": [
{
"id": "b44f2fe5-42ee-4950-a1ba-7e669b78ca91",
"name": "Weekly Monday 9AM",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
1088,
560
],
"parameters": {
"rule": {
"interval": [
{
"field": "weeks",
"triggerAtDay": [
1
],
"triggerAtHour": 9
}
]
}
},
"typeVersion": 1.2
},
{
"id": "2544fab0-093b-4d42-bc2b-1148f5b2f00d",
"name": "RSS Feed - Tech News",
"type": "n8n-nodes-base.rssFeedRead",
"position": [
1312,
464
],
"parameters": {
"url": "https://techcrunch.com/feed/",
"options": {}
},
"typeVersion": 1
},
{
"id": "cd4ab05f-e858-4b72-a586-ef01cc4dc556",
"name": "RSS Feed - Biz & IT",
"type": "n8n-nodes-base.rssFeedRead",
"position": [
1312,
656
],
"parameters": {
"url": "https://feeds.arstechnica.com/arstechnica/technology-lab",
"options": {}
},
"typeVersion": 1
},
{
"id": "d5887fcb-ed45-4c73-9044-7caf86e47fbd",
"name": "RSS Feed - MIT Science & Tech",
"type": "n8n-nodes-base.rssFeedRead",
"position": [
1312,
864
],
"parameters": {
"url": "https://news.mit.edu/rss/topic/science-technology-and-society",
"options": {}
},
"typeVersion": 1
},
{
"id": "2ea32e74-4006-4a67-8719-0c2aa271dc0d",
"name": "Combine All Articles",
"type": "n8n-nodes-base.merge",
"position": [
1744,
640
],
"parameters": {
"numberInputs": 3
},
"typeVersion": 3
},
{
"id": "2192d450-36c0-4b24-a84a-edf5aebbe6a1",
"name": "Filter and Format Articles",
"type": "n8n-nodes-base.code",
"position": [
1968,
656
],
"parameters": {
"jsCode": "/*\n * Filter and Format Articles for AI\n * ==================================\n * Purpose: Filters recent articles and formats them as a numbered list\n * for AI prompt consumption.\n * \n * Input: Array of article items from merged RSS feeds\n * Output: Object with articleCount, articlesList (formatted), rawArticles\n * \n * To customize: Change the UPPERCASE values below\n */\n\n// \u2699\ufe0f CONFIGURATION - Edit these to customize behavior\nconst DAYS_BACK = 7; // Number of days to look back for articles\nconst MAX_ARTICLES = 20; // Maximum number of articles to send to AI\nconst SNIPPET_LENGTH = 150; // Maximum characters for article description preview\n\n// ==================== CODE START ====================\n\n// Create a date object for the cutoff point (7 days ago)\nconst cutoffDate = new Date();\n// Subtract DAYS_BACK days from today's date to get the oldest allowed date\ncutoffDate.setDate(cutoffDate.getDate() - DAYS_BACK);\n\n// Get all items from the previous node (Merge) and extract just the JSON data\n// $input.all() returns all items as array, .map() extracts the .json property from each\nconst allArticles = $input.all().map(item => item.json);\n\n// Filter, sort, and limit the articles\nconst processedArticles = allArticles\n // Keep only articles that have a pubDate AND were published after the cutoff\n .filter(article => {\n // Skip articles without a publication date\n if (!article.pubDate) return false;\n // Compare article date with cutoff - keep if newer than cutoff\n return new Date(article.pubDate) >= cutoffDate;\n })\n // Sort by publication date, newest first (descending order)\n // b - a = descending (newest first), a - b would be ascending (oldest first)\n .sort((a, b) => new Date(b.pubDate) - new Date(a.pubDate))\n // Take only the first MAX_ARTICLES items (default: 20)\n .slice(0, MAX_ARTICLES);\n\n// Format articles as a numbered list string for the AI prompt\nconst formattedList = processedArticles\n .map((article, index) => {\n // Get the article snippet, with fallbacks if contentSnippet doesn't exist\n // Try contentSnippet first, then description, finally use default text\n const snippet = (article.contentSnippet || article.description || 'No description')\n // Truncate to SNIPPET_LENGTH characters to keep the list manageable\n .substring(0, SNIPPET_LENGTH);\n // Format each article as: \"1. \"Article Title\" - Description preview...\"\n return `${index + 1}. \"${article.title}\" - ${snippet}...`;\n })\n // Join all formatted articles with newline characters into one string\n .join('\\n');\n\n// ==================== CODE END ======================\n\n// Return the processed data in n8n's required format\n// Must return an array of objects, each with a 'json' property\nreturn [{\n json: {\n articleCount: processedArticles.length, // Number of articles found (for conditional check)\n articlesList: formattedList, // Formatted string for AI prompt\n rawArticles: processedArticles // Original article objects (for reference/debugging)\n }\n}];\n"
},
"typeVersion": 2
},
{
"id": "5730d377-6228-4d7c-9ec0-d02a6003cd96",
"name": "Has Articles?",
"type": "n8n-nodes-base.if",
"position": [
2176,
640
],
"parameters": {
"options": {},
"conditions": {
"options": {
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "condition-has-articles",
"operator": {
"type": "number",
"operation": "gt"
},
"leftValue": "={{ $json.articleCount }}",
"rightValue": 0
}
]
}
},
"typeVersion": 2
},
{
"id": "38d662bb-a7f7-493c-9d79-27b409dabc61",
"name": "Generate Content Calendar (Structured)",
"type": "@n8n/n8n-nodes-langchain.openAi",
"position": [
2400,
544
],
"parameters": {
"modelId": {
"__rl": true,
"mode": "list",
"value": "gpt-5-mini",
"cachedResultName": "GPT-5-MINI"
},
"options": {
"maxTokens": 4000
},
"messages": {
"values": [
{
"role": "system",
"content": "=# ROLE\nYou are a content strategist creating a weekly content calendar.\n\n# TASK\n\nYour task is to analyze a list of trending articles and generate content ideas for the following week.\n\n# RULES\n\n## STRICT OUTPUT RULES:\n\n- Output MUST be valid JSON only.\n- Do NOT include Markdown, comments, explanations, or extra text.\n\n- Each object MUST follow EXACTLY this structure:\n\n{\n \n \"Title\": \"...\",\n \"Content type\": \"...\",\n \"Target Audience\": \"...\",\n \"Publish Day\": \"...\",\n \"Status\": \"Draft\",\n \"Key Point\": \"...\"\n}\n\n## FIELD RULES:\n- \"Title\": short, clear, and actionable (max 80 characters).\n- \"Content type\": choose one (e.g. LinkedIn post, Carousel, Short video, Newsletter, Thread, Case study, Checklist).\n- \"Target Audience\": specific professional segment.\n- \"Publish Day\": MUST be one of these exact values:\n MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY\n- \"Status\": MUST always be \"Draft\".\n- \"Key Point\": one concise sentence describing the main takeaway.\n\n## CONTENT RULES:\n\n- Generate exactly 7 ideas.\n- Distribute ideas across MONDAY\u2013FRIDAY (no empty days; some days may repeat).\n- Mix content types across the week (avoid repeating the same type more than twice).\n- Each idea must be inspired by the trends but provide a unique, original angle.\n- Focus on practical, actionable value for professionals.\n\n# IMPORTANT:\nReturn JSON only."
},
{
"content": "=Based on these trending articles from this week:\n\n{{ $json.articlesList }}\n\nGenerate exactly 7 content ideas for next week's content calendar.\n"
}
]
},
"jsonOutput": true
},
"typeVersion": 1.8
},
{
"id": "2b237c53-b051-4983-bc34-04ebaeacd40a",
"name": "Split Into Individual Ideas",
"type": "n8n-nodes-base.splitOut",
"position": [
2688,
544
],
"parameters": {
"options": {},
"fieldToSplitOut": "message.content.ideas"
},
"typeVersion": 1
},
{
"id": "85f07e46-72c9-469e-bb33-26921ef65ab5",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
448,
176
],
"parameters": {
"width": 520,
"height": 924,
"content": "## Generate weekly content calendar with AI from RSS feeds\n\n### How it works\nThis workflow automatically generates a weekly content calendar by analyzing trending articles from your industry RSS feeds. Every Monday at 9 AM, it collects articles from TechCrunch, Ars Technica, and MIT News, filters those published in the last 7 days, and uses OpenAI's structured output to generate exactly 7 content ideas in validated JSON format. Each idea includes a title, content type, target audience, and key talking points\u2014then automatically adds them to your Notion database.\n\n### Setup steps\n1. **Configure RSS feeds**: Replace the example URLs with feeds relevant to your industry\n2. **Add OpenAI credentials**: Connect your OpenAI API key (gpt-5-mini recommended)\n3. **Create Notion database** with these properties:\n - Title (title)\n - Content Type (select: blog, linkedin, twitter, video, newsletter)\n - Target Audience (rich text)\n - Publish Day (select: Monday-Friday)\n - Status (select: Draft, In Progress, Done)\n - Key Points (rich text)\n4. **Connect Notion**: Add your Notion credentials and select your database\n5. **Map fields**: In the Notion node, map the AI output fields to your database properties\n6. **Test manually** before enabling the schedule\n\n**Tip**: Duplicate RSS nodes to add more sources. The AI automatically adjusts to more input."
},
"typeVersion": 1
},
{
"id": "87048c0a-6fd0-4275-b7cb-e978a8dc4e71",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
1232,
352
],
"parameters": {
"color": 7,
"width": 272,
"height": 720,
"content": "### \ud83d\udce5 RSS Sources\nAdd your industry feeds here.\nDuplicate nodes for more sources."
},
"typeVersion": 1
},
{
"id": "fa37bf50-0e1e-4035-ac45-65b89bec62e8",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
1664,
448
],
"parameters": {
"color": 7,
"width": 472,
"height": 440,
"content": "### \ud83d\udd04 Processing\nAggregate and filter articles from last 7 days.\n\n**Customize in code:**\n- `DAYS_BACK` \u2192 time window\n- `MAX_ARTICLES` \u2192 limit for AI"
},
"typeVersion": 1
},
{
"id": "66b56246-3251-4ff5-8f75-52035c5d4935",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
2336,
400
],
"parameters": {
"color": 7,
"width": 464,
"height": 352,
"content": "### \ud83e\udd16 AI Generation\nGPT creates 7 content ideas with strict JSON output.\n\nDistributes across Monday-Friday."
},
"typeVersion": 1
},
{
"id": "b6dc2f28-9f0c-407d-a2de-b6fe93f0e727",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
2832,
384
],
"parameters": {
"color": 7,
"width": 256,
"height": 384,
"content": "### \ud83d\udcdd Notion Output\nEach idea becomes a database page.\n\nReady for your content workflow."
},
"typeVersion": 1
},
{
"id": "d2554d17-ab84-4d9d-89f9-d118372ac06c",
"name": "Sticky Note5",
"type": "n8n-nodes-base.stickyNote",
"position": [
2368,
784
],
"parameters": {
"color": 7,
"width": 400,
"height": 240,
"content": "\n\n\n\n\n\n\n\n\n\n\n**No articles found in timeframe**\n\nStop execution gracefully."
},
"typeVersion": 1
},
{
"id": "1c2c3d0c-e5aa-484a-b5f0-1b694a641a7a",
"name": "No Recent Articles",
"type": "n8n-nodes-base.noOp",
"position": [
2400,
800
],
"parameters": {},
"typeVersion": 1
},
{
"id": "22f4adea-5c1f-4498-a657-ff34bb52c2da",
"name": "Create Database Page in Notion",
"type": "n8n-nodes-base.notion",
"position": [
2896,
544
],
"parameters": {
"title": "={{ $json.Title }}",
"options": {},
"resource": "databasePage",
"databaseId": {
"__rl": true,
"mode": "list",
"value": ""
},
"propertiesUi": {
"propertyValues": [
{
"key": "Content Type",
"richText": "={{ $json['Content type'] }}"
},
{
"key": "Target Audience",
"richText": "={{ $json['Target Audience'] }}"
},
{
"key": "Publish Day",
"richText": "={{ $json['Publish Day'] }}"
},
{
"key": "Status",
"richText": "={{ $json.Status }}"
},
{
"key": "Key Points",
"richText": "={{ $json['Key Point'] }}"
}
]
}
},
"typeVersion": 2.2
}
],
"active": false,
"settings": {
"availableInMCP": false,
"executionOrder": "v1"
},
"versionId": "d070e9ed-1d62-4db9-9231-892f76bee2eb",
"connections": {
"Has Articles?": {
"main": [
[
{
"node": "Generate Content Calendar (Structured)",
"type": "main",
"index": 0
}
],
[
{
"node": "No Recent Articles",
"type": "main",
"index": 0
}
]
]
},
"Weekly Monday 9AM": {
"main": [
[
{
"node": "RSS Feed - Tech News",
"type": "main",
"index": 0
},
{
"node": "RSS Feed - Biz & IT",
"type": "main",
"index": 0
},
{
"node": "RSS Feed - MIT Science & Tech",
"type": "main",
"index": 0
}
]
]
},
"RSS Feed - Biz & IT": {
"main": [
[
{
"node": "Combine All Articles",
"type": "main",
"index": 1
}
]
]
},
"Combine All Articles": {
"main": [
[
{
"node": "Filter and Format Articles",
"type": "main",
"index": 0
}
]
]
},
"RSS Feed - Tech News": {
"main": [
[
{
"node": "Combine All Articles",
"type": "main",
"index": 0
}
]
]
},
"Filter and Format Articles": {
"main": [
[
{
"node": "Has Articles?",
"type": "main",
"index": 0
}
]
]
},
"Split Into Individual Ideas": {
"main": [
[
{
"node": "Create Database Page in Notion",
"type": "main",
"index": 0
}
]
]
},
"RSS Feed - MIT Science & Tech": {
"main": [
[
{
"node": "Combine All Articles",
"type": "main",
"index": 2
}
]
]
},
"Generate Content Calendar (Structured)": {
"main": [
[
{
"node": "Split Into Individual Ideas",
"type": "main",
"index": 0
}
]
]
}
}
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Categories: AI, Content Creation, Marketing Automation, Productivity
Source: https://n8n.io/workflows/13103/ — 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.
AI Innovation Feed → Notion (Top 3 every 3 days). Uses rssFeedRead, openAi, notion. Scheduled trigger; 17 nodes.
AI-powered priority re-evaluation every 2 hours. Analyzes new signals, meeting decisions, emails, and blockers, then runs 3 AI passes (Impact, Urgency, Final Ranking) to suggest re-ranking. Only updat
YouTube Automation Pipeline - Notion + Gemini + CometAPI + JSON2Video. Uses notion, httpRequest, googleDrive, writeBinaryFile. Scheduled trigger; 43 nodes.
This workflow automatically collects the latest technology news, filters for emerging topics, and uses AI to score relevance and generate clean, ready-to-share content. It helps you focus on high-impa
Daily trigger scans your Notion database for unpublished blog ideas AI generates complete blog posts + engaging LinkedIn content using OpenAI (Blog Posting is not implemented yet) Creates custom image