{
  "id": "RxDy1M56m2aYClX0",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Generate YouTube Content Ideas with Firecrawl, OpenAI & Notion",
  "tags": [],
  "nodes": [
    {
      "id": "40fb2709-240f-43b0-a33f-f3e60d1848c8",
      "name": "Set Niche",
      "type": "n8n-nodes-base.set",
      "position": [
        -4416,
        -532
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "be118a09-c919-47ac-968e-b44fdc6e9bec",
              "name": "query",
              "type": "string",
              "value": "<YOUR_NICHE_OR_KEYWORD>"
            },
            {
              "id": "2717ce3d-62b0-4127-9eb0-3e1f42ece9d4",
              "name": "limit",
              "type": "number",
              "value": 10
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "11c7bbd8-07ea-4d38-b55a-2477a1a8044a",
      "name": "OpenAI Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        -2392,
        -432
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4.1",
          "cachedResultName": "gpt-4.1"
        },
        "options": {},
        "responsesApiEnabled": false
      },
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "7f24a79e-1d36-40c4-878e-5f87cf595b63",
      "name": "Structured Output Parser",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "position": [
        -2264,
        -432
      ],
      "parameters": {
        "jsonSchemaExample": "{\n  \"analysis\": {\n    \"audienceProfile\": {\n      \"goals\": [\"goal 1\", \"goal 2\", \"goal 3\"],\n      \"needs\": [\"need 1\", \"need 2\", \"need 3\"],\n      \"painPoints\": [\"pain 1\", \"pain 2\", \"pain 3\"],\n      \"challenges\": [\"challenge 1\", \"challenge 2\", \"challenge 3\"]\n    },\n    \"keyInsights\": [\n      \"Insight 1 - supported by specific comments\",\n      \"Insight 2 - supported by engagement patterns\",\n      \"Insight 3 - supported by topic gaps\"\n    ],\n    \"topCommentAnalysis\": {\n      \"mostEngagedTheme\": \"Theme from the most-liked comments\",\n      \"topicGaps\": [\"Gap 1\", \"Gap 2\", \"Gap 3\"]\n    }\n  },\n  \"contentIdeas\": [\n    {\n      \"id\": 1,\n      \"title\": \"Content Idea Title\",\n      \"brief\": \"2-3 sentence brief\",\n      \"angle\": \"1-2 sentence unique angle\",\n      \"whyThisTopic\": \"Connection to audience insights\",\n      \"format\": \"Content format - reasoning\",\n      \"keyPoints\": [\"Point 1\", \"Point 2\", \"Point 3\", \"Point 4\", \"Point 5\"],\n      \"engagementPotential\": \"High/Medium/Low - reasoning\"\n    }\n  ],\n  \"strategy\": {\n    \"overallTheme\": \"General theme of the 5 ideas\",\n    \"publishingOrder\": \"Suggested publication order and reasoning\",\n    \"seriesOpportunity\": \"Potential for a series? How to link them together?\"\n  }\n}"
      },
      "typeVersion": 1.3
    },
    {
      "id": "34698409-62aa-4b7e-b819-160e33c75265",
      "name": "Loop Over Items",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        -3072,
        -532
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "93c15cec-cacc-442a-be28-d6da346c1f4d",
      "name": "Aggregate",
      "type": "n8n-nodes-base.aggregate",
      "position": [
        -928,
        -532
      ],
      "parameters": {
        "options": {},
        "fieldsToAggregate": {
          "fieldToAggregate": [
            {
              "fieldToAggregate": "id"
            }
          ]
        }
      },
      "typeVersion": 1
    },
    {
      "id": "4daadba4-bc4a-4b22-90b9-12f2f3d8444f",
      "name": "ContentIdeas",
      "type": "n8n-nodes-base.set",
      "position": [
        -1824,
        -656
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "ad12b694-99ba-4426-9f10-288ebce0b1c9",
              "name": "contentIdeas",
              "type": "array",
              "value": "={{ $('Identify Strategic Gaps').item.json.output.contentIdeas }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "4ff16f55-7e13-44d1-bec2-11fe3ca1a006",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -5264,
        -912
      ],
      "parameters": {
        "width": 496,
        "height": 544,
        "content": "## How it works\n\nThis workflow automates market research by identifying what your audience actually wants. It starts by searching for top-performing YouTube videos in your niche using Firecrawl. The system then performs a deep scrape of video descriptions and the top 20 comments to capture raw audience feedback. An AI Strategist analyzes this data to identify \"decision confusion\" and \"operational pain points,\" finally generating 5 data-backed content ideas. All insights are automatically structured and saved into Notion for your editorial team.\n\n## Setup steps\n1. **Firecrawl:** Get your API Key from firecrawl.dev and add it to the Header Auth in the HTTP Request nodes.\n2. **OpenAI:** Connect your OpenAI credentials (GPT-4o is recommended for best reasoning).\n3. **Notion:** Connect your Notion account and ensure you have two databases ready for \"Insights\" and \"Ideas.\"\n4. **Configuration:** Enter your target keyword in the 'Set Niche' node.\n5. **Execution:** Run the workflow to populate your Notion workspace with new strategy ideas.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "e5d3f751-6b5d-4b6e-b1ae-43433a99a9d5",
      "name": "Search YouTube Videos",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -4192,
        -532
      ],
      "parameters": {
        "url": "https://api.firecrawl.dev/v2/scrape",
        "method": "POST",
        "options": {},
        "sendBody": true,
        "authentication": "genericCredentialType",
        "bodyParameters": {
          "parameters": [
            {
              "name": "url",
              "value": "=https://www.youtube.com/results?search_query={{ $json.query.split(' ').join('+') }}"
            }
          ]
        },
        "genericAuthType": "httpHeaderAuth"
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.3
    },
    {
      "id": "b7805e06-4470-47df-b7e6-d80517a0894a",
      "name": "Check Search Status",
      "type": "n8n-nodes-base.if",
      "position": [
        -3968,
        -532
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "9f7b19eb-6c5e-412e-97d0-2f0481a2c79d",
              "operator": {
                "type": "boolean",
                "operation": "equals"
              },
              "leftValue": "={{ $json.success }}",
              "rightValue": true
            },
            {
              "id": "e8daf3c8-2fbd-402d-a73a-34578f621c78",
              "operator": {
                "type": "number",
                "operation": "equals"
              },
              "leftValue": "={{ $json.data.metadata.statusCode }}",
              "rightValue": 200
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "432fd24a-92a7-475d-aa0a-36da792bf266",
      "name": "Parse Video List",
      "type": "n8n-nodes-base.code",
      "position": [
        -3744,
        -532
      ],
      "parameters": {
        "jsCode": "const videos = [];\nconst inputItem = $input.first().json;\nconst limit = $('Set Niche').first().json.limit; \n\nif (!inputItem || !inputItem.data || !inputItem.data.markdown) {\n    return [{ json: { error: \"Data Not Found.\" } }];\n}\n\nconst markdown = inputItem.data.markdown;\n\nconst cleanString = (str) => {\n    return str.replace(/\\\\/g, '').trim();\n};\n\nconst parseNumericValue = (value) => {\n    if (!value || value === 'N/A') return 0;\n    const cleanedValue = value.toLowerCase().replace(/ subscribers| views/g, '').trim();\n    const multiplier = cleanedValue.slice(-1);\n    let num = parseFloat(cleanedValue);\n    if (isNaN(num)) return 0;\n    \n    if (multiplier === 'k') {\n        num *= 1000;\n    } else if (multiplier === 'm') {\n        num *= 1000000;\n    } else if (multiplier === 'b') {\n        num *= 1+1234567890;\n    }\n    \n    return num;\n};\n\nconst parseTimeAgo = (timeStr) => {\n    if (!timeStr || timeStr === 'N/A') return 999999;\n    \n    const lowerTime = timeStr.toLowerCase();\n    const match = lowerTime.match(/(\\d+)\\s*(second|minute|hour|day|week|month|year)/);\n    \n    if (!match) return 999999;\n    \n    const value = parseInt(match[1]);\n    const unit = match[2];\n    \n    switch(unit) {\n        case 'second': return value / 86400;\n        case 'minute': return value / 1440;\n        case 'hour': return value / 24;\n        case 'day': return value;\n        case 'week': return value * 7;\n        case 'month': return value * 30;\n        case 'year': return value * 365;\n        default: return 999999;\n    }\n};\n\nconst subscriberData = {};\nconst channelSubscriberRegex = /@([^\u2022]+?)\u2022(\\d+\\.?\\d*[KMB]? subscribers)/g;\nlet subMatch;\nwhile ((subMatch = channelSubscriberRegex.exec(markdown)) !== null) {\n    subscriberData[subMatch[1].trim()] = subMatch[2].trim();\n}\n\nconst videoBlockRegex = new RegExp(\n    /### \\[(.*?)\\]\\((https:\\/\\/www\\.youtube\\.com\\/watch\\?v=[^&]+).*?\\)/.source +\n    /[\\s\\S]*?\\[(.*?)\\]\\((https:\\/\\/www\\.youtube\\.com\\/@([^)]+))\\)/.source +\n    /[\\s\\S]*?(\\d+\\.?\\d*[KMB]? views)(.*?)ago/.source,\n    'g'\n);\n\nconst matches = [...markdown.matchAll(videoBlockRegex)];\n\nfor (const match of matches) {\n    const title = cleanString(match[1]);\n    const url = cleanString(match[2]);\n    const channelName = cleanString(match[3]);\n    const channelHandle = cleanString(match[5]); \n    const viewsRaw = cleanString(match[6]);\n    const timeAgo = cleanString(match[7] + 'ago');\n    \n    const channelSubscriberRaw = subscriberData[channelHandle] || 'N/A';\n    \n    const viewsNumeric = parseNumericValue(viewsRaw);\n    const subscriberNumeric = parseNumericValue(channelSubscriberRaw);\n    const daysAgo = parseTimeAgo(timeAgo);\n    \n    videos.push({\n        title: title,\n        url: url,\n        channelName: channelName,\n        channelHandle: `@${channelHandle}`,\n        channelSubscriber: channelSubscriberRaw,\n        views: viewsRaw,\n        uploadedAgo: timeAgo,\n        like: 'N/A', \n        comment: 'N/A',\n        _viewsNumeric: viewsNumeric,\n        _subscriberNumeric: subscriberNumeric,\n        _daysAgo: daysAgo\n    });\n}\n\nvideos.sort((a, b) => {\n    if (a._daysAgo !== b._daysAgo) {\n        return a._daysAgo - b._daysAgo; \n    }\n    if (b._viewsNumeric !== a._viewsNumeric) {\n        return b._viewsNumeric - a._viewsNumeric;\n    }\n    return b._subscriberNumeric - a._subscriberNumeric;\n});\n\nconst topNVideos = videos.slice(0, limit);\n\nconst finalVideos = topNVideos.map(video => {\n    delete video._viewsNumeric;\n    delete video._subscriberNumeric;\n    delete video._daysAgo;\n    return video;\n});\n\nreturn [{ json: { videos: finalVideos } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "0f8b256a-409e-4649-8ae3-1e9a80334bb9",
      "name": "Scrape Video Details",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -2848,
        -656
      ],
      "parameters": {
        "url": "https://api.firecrawl.dev/v2/scrape",
        "method": "POST",
        "options": {},
        "sendBody": true,
        "authentication": "genericCredentialType",
        "bodyParameters": {
          "parameters": [
            {
              "name": "url",
              "value": "={{ $json.url }}"
            }
          ]
        },
        "genericAuthType": "httpHeaderAuth"
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.3
    },
    {
      "id": "e5a772ed-f6cb-486e-8ddb-489d8d459bb2",
      "name": "Extract Audience Comments",
      "type": "n8n-nodes-base.code",
      "position": [
        -2624,
        -656
      ],
      "parameters": {
        "jsCode": "const output = {};\nconst inputItem = $input.first().json;\n\nif (!inputItem || !inputItem.data || !inputItem.data.markdown) {\n    return [{ json: { error: \"Markdown data not found in input.\" } }];\n}\n\nconst markdown = inputItem.data.markdown;\n\n\n\nlet channelNameMatch = markdown.match(/\\[([^\\]]+)\\]\\(https:\\/\\/www\\.youtube\\.com\\/@[^\\)]+\\)/);\nif (!channelNameMatch) {\n    channelNameMatch = markdown.match(/\\[([^\\]]+)\\]\\(https:\\/\\/www\\.youtube\\.com\\/channel\\/[^\\)]+\\)/);\n}\noutput.channelName = channelNameMatch ? channelNameMatch[1].trim() : 'N/A';\n\n\nlet viewsMatch = markdown.match(/(\\d+(?:,\\d+)*)\\s+views/);\nif (!viewsMatch) {\n    // Fallback: Try to find views in format like \"722K views\"\n    viewsMatch = markdown.match(/(\\d+(?:\\.\\d+)?[KMB])\\s+views/);\n}\noutput.views = viewsMatch ? viewsMatch[1].trim() : 'N/A';\n\n\nlet likesMatch = markdown.match(/(\\d+(?:\\.\\d+)?[KMB]?)\\s*(?:Share|Dislike)/);\nif (!likesMatch) {\n    likesMatch = markdown.match(/^(\\d+(?:\\.\\d+)?[KMB]?)$/m);\n}\noutput.totalLikes = likesMatch ? likesMatch[1].trim() : 'N/A';\n\nlet descriptionMatch = markdown.match(/Show less\\n\\n([\\s\\S]*?)(?:\\n\\nTimestamps:|\\n\\nHow this was made|\\n\\n\\.\\.\\.more)/i);\nif (!descriptionMatch) {\n    \n    descriptionMatch = markdown.match(/\\d+\\s+views[\\s\\S]*?\\n\\n([\\s\\S]*?)(?:\\n\\nTimestamps:|\\n\\nHow this was made)/i);\n}\n\nlet description = 'N/A';\nif (descriptionMatch) {\n    description = descriptionMatch[1]\n        .replace(/\\n\\n/g, ' ')                      \n        .replace(/\\n/g, ' ')                        \n        .replace(/\\[.*?\\]\\(.*?\\)/g, '')           \n        .replace(/!\\[.*?\\]\\(.*?\\)/g, '')          \n        .replace(/\\s+/g, ' ')                       \n        .replace(/Show lessRead more/g, '')         // Remove UI text\n        .replace(/Show less/g, '')\n        .replace(/Read more/g, '')\n        .replace(/\\.\\.\\.more/g, '')\n        .trim();\n    \n    // Limit description to first 500 characters for cleaner output\n    if (description.length > 500) {\n        description = description.substring(0, 500) + '...';\n    }\n}\n\noutput.description = description;\n\n\nlet urlMatch = markdown.match(/https:\\/\\/www\\.youtube\\.com\\/watch\\?v=([a-zA-Z0-9_-]+)/);\nif (urlMatch) {\n    output.url = `https://www.youtube.com/watch?v=${urlMatch[1]}`;\n} else {\n    output.url = 'N/A';\n}\n\n\n\nconst comments = [];\n\n\n\nconst commentRegex = /!\\[\\]\\((https?:\\/\\/[^\\)]+)\\)\\s*\\n\\n([^\\n]*?)(?:\\n\\n(?:Show lessRead more|Read more|Show less)?)?\\n\\nLike\\s*\\n\\n(\\d+(?:\\.\\d+)?[KMB]?)?\\s*\\n\\nDislike/gs;\n\nlet commentMatch;\nlet count = 0;\n\nwhile ((commentMatch = commentRegex.exec(markdown)) !== null) {\n    let commentText = commentMatch[2] || '';\n    let likesRaw = commentMatch[3] || '0';\n    \n    // Clean up comment text\n    commentText = commentText\n        .replace(/\\\\n/g, ' ')                    // Remove backslash escapes\n        .replace(/\\s+/g, ' ')                    // Normalize whitespace\n        .replace(/Show lessRead more/g, '')      // Remove YouTube UI text\n        .replace(/Show less/g, '')\n        .replace(/Read more/g, '')\n        .replace(/\\[.*?\\]/g, '')                 // Remove markdown links\n        .replace(/!\\[.*?\\]\\(.*?\\)/g, '')         // Remove markdown images\n        .replace(/\u200b@\\w+\\s*-\\s*/g, '')            // Remove mentions like @user -\n        .replace(/\\s*\u2764 by @\\w+/g, '')           // Remove heart reactions\n        .replace(/!\\[.*?\\]\\(.*?\\)/g, '')         // Remove emoji images\n        .trim();\n    \n    // Convert likes from format like \"333\" or \"10K\" to number\n    let likesNumber = 0;\n    if (likesRaw && likesRaw !== '0') {\n        if (likesRaw.includes('K')) {\n            likesNumber = parseInt(likesRaw) * 1000;\n        } else if (likesRaw.includes('M')) {\n            likesNumber = parseInt(likesRaw) * 1000000;\n        } else {\n            likesNumber = parseInt(likesRaw) || 0;\n        }\n    }\n    \n    // Only include comments with meaningful content (at least 5 characters)\n    if (commentText.length >= 5) {\n        comments.push({\n            comment: commentText,\n            likes: likesNumber\n        });\n        count++;\n    }\n}\n\n// Sort by likes in descending order and take top 20\ncomments.sort((a, b) => b.likes - a.likes);\noutput.top20Comments = comments.slice(0, 20);\noutput.totalCommentsExtracted = count;\n\n\nreturn [{ json: output }];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "b9dc0fce-ba19-4efa-8b0f-0029b28e208c",
      "name": "Identify Strategic Gaps",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        -2400,
        -656
      ],
      "parameters": {
        "text": "make content Idea",
        "options": {
          "systemMessage": "=**Role:** You are the **Chief Solution Officer & Content Strategist** at an **AI Automation Agency** serving **established small-to-medium businesses (SMEs)**.\n\n**Your Tasks:**\n\n1. Analyze the description, likes, views, and top 20 comments of provided content.\n2. Identify the goals, needs, pain points, and challenges of a **decision-maker level** audience.\n3. Propose 5 content ideas **rooted in systems and business decisions**.\n4. Ensure all ideas are **strategic & actionable**.\n\n---\n\n## \ud83e\uddec BRAND ARCHETYPE (MANDATORY)\n\n**Sage (Primary) + Ruler + Creator**\n\n**Principles:**\n\n* Focus on the *why & how the system works*, not the *how to build it*.\n* Demonstrate structure, control, and intellectual maturity.\n* Tone: Calm, objective, non-hype, and non-hard-selling.\n\n---\n\n## \ud83e\uddf1 CONTENT PILLARS\n\nEach idea must fall into one of these categories:\n\n1. Operational Bottleneck & Business Pain\n2. Decision-Making & System Thinking\n3. AI Automation Reality Check\n4. Scalable Workflow & Control System\n5. Case-Based Insight (hype-free)\n\n\u274c **Avoid technical tutorials & beginner-level content.**\n\n---\n\n## \ud83c\udfa5 DEMO WORKFLOW (SHOWCASE ONLY)\n\nDemos are recommended only under these conditions:\n\n* They are not a tutorial or step-by-step guide.\n* They focus on logical flow, integration, control, and business impact.\n* The narrative explains *why this structure was chosen*, risks involved, and common mistakes.\n* The demo should trigger curiosity, not provide a \"recipe.\"\n\n---\n\n## INPUT\n\n* **videoTitle:** {{ $('Limit Search Results').item.json.title }}\n* **channelName:** {{ $('Limit Search Results').item.json.channelName }}\n* **description:** {{ $json.description }}\n* **totalLikes:** {{ $json.totalLikes }}\n* **views:** {{ $json.views }}\n* **topComments:** {{ $json.top20Comments.map((item, i) => ' ' + i + ')' + item.comment + ' likes: ' + item.likes) }}\n\n---\n\n## ANALYSIS FRAMEWORK\n\n### 1. COMMENT ANALYSIS\n\nFocus on:\n\n* Decision confusion\n* Operational frustration\n* Skepticism & unrealistic expectations\n* Structural issues (rather than tool-specific issues)\n\n**Categories:**\n\n* Decision Confusion\n* Operational Frustration\n* Skepticism\n* Experience Insight\n* Validation\n\n### 2. AUDIENCE PROFILE\n\n* **Goals:** Reduce operational burden, increase oversight/control.\n* **Needs:** Thinking frameworks & decision validation.\n* **Pain Points:** Owner as the bottleneck, failed automation attempts.\n* **Challenges:** Misplaced priorities, over-optimization of tools.\n\n### 3. CONTENT OPPORTUNITIES\n\nPrioritize topics that:\n\n* Correct popular assumptions.\n* Halt implementation errors.\n* Highlight systemic issues.\n\n---\n\n## STRUCTURE OF THE 5 CONTENT IDEAS\n\nFor each idea, provide:\n\n1. **Title** \u2014 Problem & decision-based.\n2. **Brief** \u2014 Business impact (2\u20133 sentences).\n3. **Angle** \u2014 Unique perspective from a Chief Solution Officer.\n4. **Why This Topic** \u2014 Connection to audience insights/comments.\n5. **Format** \u2014 Strategic video / system demo / case breakdown.\n6. **Key Points** \u2014 5 strategic points (non-technical).\n7. **Engagement Potential** \u2014 High / Medium / Low + reasoning.\n\n---\n\n## OUTPUT FORMAT (JSON)\n\n{\n  \"analysis\": {\n    \"audienceProfile\": {\n      \"goals\": [\"goal 1\", \"goal 2\", \"goal 3\"],\n      \"needs\": [\"need 1\", \"need 2\", \"need 3\"],\n      \"painPoints\": [\"pain 1\", \"pain 2\", \"pain 3\"],\n      \"challenges\": [\"challenge 1\", \"challenge 2\", \"challenge 3\"]\n    },\n    \"keyInsights\": [\n      \"Insight 1 - supported by specific comments\",\n      \"Insight 2 - supported by engagement patterns\",\n      \"Insight 3 - supported by topic gaps\"\n    ],\n    \"topCommentAnalysis\": {\n      \"mostEngagedTheme\": \"Theme from the most liked comments\",\n      \"topicGaps\": [\"Gap 1\", \"Gap 2\", \"Gap 3\"]\n    }\n  },\n  \"contentIdeas\": [\n    {\n      \"id\": 1,\n      \"title\": \"Content Idea Title\",\n      \"brief\": \"2-3 sentence brief\",\n      \"angle\": \"1-2 sentence unique angle\",\n      \"whyThisTopic\": \"Connection to audience insight\",\n      \"format\": \"Content format - reasoning\",\n      \"keyPoints\": [\"Point 1\", \"Point 2\", \"Point 3\", \"Point 4\", \"Point 5\"],\n      \"engagementPotential\": \"High/Medium/Low - reasoning\"\n    }\n  ],\n  \"strategy\": {\n    \"overallTheme\": \"General theme of the 5 ideas\",\n    \"publishingOrder\": \"Suggested publication order and reasoning\",\n    \"seriesOpportunity\": \"Can this be a series? How to link them?\"\n  }\n}\n\n\n---\n\n## FINAL PRINCIPLES\n\nEvery content idea must have:\n\n* A **Hook** that is relatable to a broad professional audience.\n* A **Mid-section** that corrects the viewer's mindset/approach.\n* A **Closing** that reinforces your authority."
        },
        "promptType": "define",
        "hasOutputParser": true
      },
      "typeVersion": 3.1
    },
    {
      "id": "53826d14-f904-4b5c-acf7-f8e8d3e815bf",
      "name": "Store Competitor Data",
      "type": "n8n-nodes-base.notion",
      "position": [
        -2048,
        -656
      ],
      "parameters": {
        "title": "={{ $('Split Video Items').item.json.title }}",
        "options": {},
        "resource": "databasePage",
        "databaseId": {
          "__rl": true,
          "mode": "list",
          "value": "2d7bf4c7-dad2-8037-a141-d86dff2712b6",
          "cachedResultUrl": "https://www.notion.so/2d7bf4c7dad28037a141d86dff2712b6",
          "cachedResultName": "Competitor Content Insigth"
        },
        "propertiesUi": {
          "propertyValues": [
            {
              "key": "Description|rich_text",
              "textContent": "={{ $('Extract Audience Comments').item.json.description }}"
            },
            {
              "key": "URL|url",
              "urlValue": "={{ $('Extract Audience Comments').item.json.url }}"
            },
            {
              "key": "Likes|rich_text",
              "textContent": "={{ $('Extract Audience Comments').item.json.totalLikes }}"
            },
            {
              "key": "Views|rich_text",
              "textContent": "={{ $('Extract Audience Comments').item.json.views }}"
            },
            {
              "key": "AudienceInsigths|rich_text",
              "textContent": "=Goals: {{ $json.output.analysis.audienceProfile.goals }}\n\nNeeds: {{ $json.output.analysis.audienceProfile.needs }}\n\nPain Points: {{ $json.output.analysis.audienceProfile.painPoints }}\n\nChallenges: {{ $json.output.analysis.audienceProfile.challenges }}\n"
            }
          ]
        }
      },
      "credentials": {
        "notionApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "02c19438-38a2-4a6d-b71b-9b50c77d61fc",
      "name": "Store Content Strategy",
      "type": "n8n-nodes-base.notion",
      "position": [
        -1152,
        -656
      ],
      "parameters": {
        "title": "={{ $json.title }}",
        "options": {},
        "resource": "databasePage",
        "databaseId": {
          "__rl": true,
          "mode": "list",
          "value": "2d7bf4c7-dad2-8027-a02f-fc9c481a529a",
          "cachedResultUrl": "https://www.notion.so/2d7bf4c7dad28027a02ffc9c481a529a",
          "cachedResultName": "Content Idea"
        },
        "propertiesUi": {
          "propertyValues": [
            {
              "key": "Angle|rich_text",
              "textContent": "={{ $json.angle }}"
            },
            {
              "key": "Brief|rich_text",
              "textContent": "={{ $json.brief }}"
            },
            {
              "key": "Idea Number|number",
              "numberValue": "={{ $json.id }}"
            },
            {
              "key": "Format|rich_text",
              "textContent": "={{ $json.format }}"
            },
            {
              "key": "Reference|url",
              "urlValue": "={{ $('Store Competitor Data').item.json.url }}"
            }
          ]
        }
      },
      "credentials": {
        "notionApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "de7c2258-2e69-43cf-8c3b-778733aab586",
      "name": "Set Video Analysis Limit",
      "type": "n8n-nodes-base.limit",
      "position": [
        -1376,
        -656
      ],
      "parameters": {
        "maxItems": 100
      },
      "typeVersion": 1
    },
    {
      "id": "e5c45cdf-4d1d-48d9-bb8e-fcb9c5fdde28",
      "name": "Monthly Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -4640,
        -532
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "months"
            }
          ]
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "07687b5f-6b21-4819-8df2-0636a5512674",
      "name": "Limit Search Results",
      "type": "n8n-nodes-base.limit",
      "position": [
        -3296,
        -532
      ],
      "parameters": {
        "maxItems": "={{ $('Set Niche').item.json.limit }}"
      },
      "typeVersion": 1
    },
    {
      "id": "a63767de-6d1c-4bd4-917f-540dab421534",
      "name": "Split Video Items",
      "type": "n8n-nodes-base.splitOut",
      "position": [
        -3520,
        -532
      ],
      "parameters": {
        "options": {},
        "fieldToSplitOut": "videos"
      },
      "typeVersion": 1
    },
    {
      "id": "fad0e94c-d6a0-43ca-896a-e24c05c21964",
      "name": "Split Content Ideas",
      "type": "n8n-nodes-base.splitOut",
      "position": [
        -1600,
        -656
      ],
      "parameters": {
        "options": {},
        "fieldToSplitOut": "contentIdeas"
      },
      "typeVersion": 1
    },
    {
      "id": "37b57d42-c4e7-44dc-beb3-af6a00b60902",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -4712,
        -916
      ],
      "parameters": {
        "color": 6,
        "width": 1584,
        "height": 544,
        "content": "## Step 1: Fetch & Filter Videos"
      },
      "typeVersion": 1
    },
    {
      "id": "da68bc51-954a-4944-ae82-746a88e730bc",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -3120,
        -916
      ],
      "parameters": {
        "width": 640,
        "height": 544,
        "content": "## Step 2: Scrape & Extract Insights"
      },
      "typeVersion": 1
    },
    {
      "id": "9cd01b0e-750a-46bf-ae9c-3f1422931785",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2448,
        -832
      ],
      "parameters": {
        "color": 3,
        "width": 320,
        "height": 544,
        "content": "## Step 3: AI Strategy Generation"
      },
      "typeVersion": 1
    },
    {
      "id": "42a67a0e-afb5-498c-a4aa-ac8fa2d74d69",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2112,
        -916
      ],
      "parameters": {
        "color": 5,
        "width": 1344,
        "height": 544,
        "content": "## Step 4: Save to Notion"
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "availableInMCP": false,
    "executionOrder": "v1"
  },
  "versionId": "bc32fa99-70a3-4060-b21b-3b349e872e21",
  "connections": {
    "Aggregate": {
      "main": [
        [
          {
            "node": "Loop Over Items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set Niche": {
      "main": [
        [
          {
            "node": "Search YouTube Videos",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "ContentIdeas": {
      "main": [
        [
          {
            "node": "Split Content Ideas",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Loop Over Items": {
      "main": [
        [],
        [
          {
            "node": "Scrape Video Details",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Monthly Trigger": {
      "main": [
        [
          {
            "node": "Set Niche",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Video List": {
      "main": [
        [
          {
            "node": "Split Video Items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "Identify Strategic Gaps",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Split Video Items": {
      "main": [
        [
          {
            "node": "Limit Search Results",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check Search Status": {
      "main": [
        [
          {
            "node": "Parse Video List",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split Content Ideas": {
      "main": [
        [
          {
            "node": "Set Video Analysis Limit",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Limit Search Results": {
      "main": [
        [
          {
            "node": "Loop Over Items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Scrape Video Details": {
      "main": [
        [
          {
            "node": "Extract Audience Comments",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Search YouTube Videos": {
      "main": [
        [
          {
            "node": "Check Search Status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Store Competitor Data": {
      "main": [
        [
          {
            "node": "ContentIdeas",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Store Content Strategy": {
      "main": [
        [
          {
            "node": "Aggregate",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Identify Strategic Gaps": {
      "main": [
        [
          {
            "node": "Store Competitor Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set Video Analysis Limit": {
      "main": [
        [
          {
            "node": "Store Content Strategy",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Structured Output Parser": {
      "ai_outputParser": [
        [
          {
            "node": "Identify Strategic Gaps",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "Extract Audience Comments": {
      "main": [
        [
          {
            "node": "Identify Strategic Gaps",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}