{
  "id": "dxZQhOkZXNNFtuHM",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Transform YouTube transcripts to AI-generated GEO summaries in Notion",
  "tags": [],
  "nodes": [
    {
      "id": "c0e9b7f9-0ab3-4275-9fbe-266e602052f8",
      "name": "Sticky Note - Overview",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1936,
        -720
      ],
      "parameters": {
        "width": 420,
        "height": 528,
        "content": "## \ud83c\udfa5 YouTube \u2192 GEO Summary Automation\n\n### How it works\nThis workflow extracts audio from YouTube videos, transcribes the content using OpenAI Whisper, and generates structured GEO summaries (Goal-Execution-Outcome) through AI analysis. The final summary is saved to a Notion database with organized metadata, making video content searchable and actionable.\n\n### Setup steps\n1. Connect **YouTube OAuth2**, **OpenAI API**, and **Notion** credentials\n2. Replace the RapidAPI key placeholder in \"HTTP - Get YouTube Audio\" node\n3. Update the Notion database ID in the final node to match your workspace\n4. Configure the Schedule Trigger interval (default: hourly)\n5. Replace the hardcoded video ID with a dynamic input or playlist source\n6. Test with a single video before enabling the schedule"
      },
      "typeVersion": 1
    },
    {
      "id": "8002b504-7541-4197-a29b-4f060e30f7f9",
      "name": "Sticky Note - Fetch",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1936,
        -176
      ],
      "parameters": {
        "color": 2,
        "width": 712,
        "height": 380,
        "content": "## \ud83d\udce5 Video Fetch & Metadata\nRetrieves video details from YouTube API and prepares metadata like title, description, thumbnail, and publish date for downstream processing."
      },
      "typeVersion": 1
    },
    {
      "id": "bac21e13-bdb7-4334-961b-50f065cfae3e",
      "name": "Sticky Note - Audio",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1200,
        -176
      ],
      "parameters": {
        "color": 2,
        "width": 880,
        "height": 560,
        "content": "## \ud83c\udfa7 Audio Download & Transcription\nDownloads audio from YouTube using RapidAPI, converts it to text via OpenAI Whisper, and filters out empty transcripts before merging with metadata."
      },
      "typeVersion": 1
    },
    {
      "id": "8e850fb3-c485-4efa-9333-4eb5f600e237",
      "name": "Sticky Note - AI",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -288,
        -192
      ],
      "parameters": {
        "color": 2,
        "width": 676,
        "height": 608,
        "content": "## \ud83e\udd16 AI Analysis & GEO Extraction\nUses GPT-4o-mini with structured output parsing to analyze the transcript and generate Goal, Execution, Outcome, and Keywords in JSON format."
      },
      "typeVersion": 1
    },
    {
      "id": "b11022ae-7f4b-4319-b60b-662a18f455bc",
      "name": "Sticky Note - Storage",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        416,
        -192
      ],
      "parameters": {
        "color": 2,
        "width": 472,
        "height": 428,
        "content": "## \ud83d\udcbe Data Storage\nParses the AI-generated JSON and creates a new page in Notion with formatted GEO content and video metadata."
      },
      "typeVersion": 1
    },
    {
      "id": "d571f5f8-5546-4036-ba2e-19bda81d5e75",
      "name": "Sticky Note - Security",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        448,
        256
      ],
      "parameters": {
        "color": 3,
        "width": 320,
        "height": 180,
        "content": "## \ud83d\udd10 Credentials & Security\n**Required credentials:**\n- YouTube OAuth2\n- OpenAI API key\n- Notion API integration\n- RapidAPI key (replace placeholder)\n\n\u26a0\ufe0f Remove all personal tokens before sharing this template."
      },
      "typeVersion": 1
    },
    {
      "id": "126d7e25-da79-47d6-a9f0-9511f462c22b",
      "name": "Schedule Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -1808,
        32
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "hours"
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "5a992308-5d1d-4ee6-a0c8-44c2b9fea494",
      "name": "Set - Prepare Video Metadata",
      "type": "n8n-nodes-base.set",
      "position": [
        -1360,
        32
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "field1",
              "name": "videoId",
              "type": "string",
              "value": "={{ $json.id }}"
            },
            {
              "id": "field2",
              "name": "title",
              "type": "string",
              "value": "={{$json.snippet.title}}"
            },
            {
              "id": "field3",
              "name": "description",
              "type": "string",
              "value": "={{$json.snippet.description}}"
            },
            {
              "id": "field4",
              "name": "publishedAt",
              "type": "string",
              "value": "={{$json.snippet.publishedAt}}"
            },
            {
              "id": "field5",
              "name": "thumbnailUrl",
              "type": "string",
              "value": "={{$json.snippet.thumbnails.default.url}}"
            },
            {
              "id": "field6",
              "name": "videoUrl",
              "type": "string",
              "value": "=https://www.youtube.com/watch?v={{$json.id.videoId}}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "56c1c33b-2b75-4367-98a3-6ed6c751a4f1",
      "name": "HTTP - Download Audio File",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -912,
        96
      ],
      "parameters": {
        "url": "={{ $json.file }}",
        "options": {
          "response": {
            "response": {
              "responseFormat": "file"
            }
          }
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "8a4192d9-e1e2-4171-ab9c-4eb241e1f716",
      "name": "IF - Skip if No Transcript",
      "type": "n8n-nodes-base.if",
      "position": [
        -464,
        96
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 1,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "condition1",
              "operator": {
                "type": "string",
                "operation": "notEmpty"
              },
              "leftValue": "={{$json.text}}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "dde57237-e117-4e8c-a427-acddade93e03",
      "name": "Merge - Attach Metadata + Transcript",
      "type": "n8n-nodes-base.merge",
      "position": [
        -240,
        32
      ],
      "parameters": {
        "mode": "combine",
        "options": {},
        "combineBy": "combineByPosition"
      },
      "typeVersion": 3
    },
    {
      "id": "30b4d2a5-0eb8-4223-acb6-e0dd2954ff44",
      "name": "Function - Parse GEO JSON",
      "type": "n8n-nodes-base.code",
      "position": [
        464,
        32
      ],
      "parameters": {
        "jsCode": "// Get the input data\nconst inputData = $input.all();\n\n// Process each item\nreturn inputData.map(item => {\n  const output = item.json.output;\n  \n  return {\n    json: {\n    \n      \n      // Goals as rich text or multi-line text\n      Goals: output.goal.join('\\n\u2022 '),\n      \n      // Execution steps as rich text or multi-line text\n      Execution: output.execution.join('\\n\u2022 '),\n      \n      // Outcomes as rich text or multi-line text\n      Outcomes: output.outcome.join('\\n\u2022 '),\n      \n      // Keywords as multi-select or text\n      Keywords: output.keywords,\n      \n      // Alternative: If you want all goals in one formatted string\n      GoalsFormatted: '\u2022 ' + output.goal.join('\\n\u2022 '),\n      ExecutionFormatted: '\u2022 ' + output.execution.join('\\n\u2022 '),\n      OutcomesFormatted: '\u2022 ' + output.outcome.join('\\n\u2022 '),\n      \n      // Keywords as comma-separated string (if Notion expects text)\n      KeywordsText: output.keywords.join(', ')\n    }\n  };\n});"
      },
      "typeVersion": 2
    },
    {
      "id": "9a92e535-79e3-44fd-b307-0426d7fb13ea",
      "name": "Notion - Create GEO Summary Page",
      "type": "n8n-nodes-base.notion",
      "position": [
        688,
        32
      ],
      "parameters": {
        "title": "={{ $('Merge - Attach Metadata + Transcript').item.json.title }}",
        "options": {},
        "resource": "databasePage",
        "databaseId": {
          "__rl": true,
          "mode": "list",
          "value": "[Your Database ID]",
          "cachedResultUrl": "https://www.notion.so/example",
          "cachedResultName": "YouTube GEO"
        },
        "propertiesUi": {
          "propertyValues": [
            {
              "key": "Goal|rich_text",
              "textContent": "={{ $json.GoalsFormatted }}"
            },
            {
              "key": "Execution|rich_text",
              "textContent": "={{ $json.ExecutionFormatted }}"
            },
            {
              "key": "Outcomes|rich_text",
              "textContent": "={{ $json.OutcomesFormatted }}"
            },
            {
              "key": "Keywords|rich_text",
              "textContent": "={{ $json.KeywordsText }}"
            }
          ]
        }
      },
      "credentials": {
        "notionApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "b01bfd5d-aab7-4b32-9708-8656bd11ca22",
      "name": "HTTP - Get YouTube Audio",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -1136,
        96
      ],
      "parameters": {
        "url": "=https://youtube-video-fast-downloader-24-7.p.rapidapi.com/download_audio/{{ $json.videoId }}?quality=140\n",
        "options": {},
        "sendBody": true,
        "sendHeaders": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "videoId",
              "value": "={{ $json.videoId }}"
            }
          ]
        },
        "headerParameters": {
          "parameters": [
            {
              "name": "x-rapidapi-host",
              "value": "youtube-video-fast-downloader-24-7.p.rapidapi.com"
            },
            {
              "name": "x-rapidapi-key",
              "value": "[Your RapidAPI Key]"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "49b97a02-564b-42ff-94fc-9c1614956689",
      "name": "YouTube - Fetch Video Details",
      "type": "n8n-nodes-base.youTube",
      "position": [
        -1584,
        32
      ],
      "parameters": {
        "options": {},
        "resource": "video",
        "operation": "get"
      },
      "credentials": {
        "youTubeOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "71f6a34a-3c35-48f9-aaf7-0760e75893dc",
      "name": "OpenAI - Transcribe Audio (Whisper)",
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "position": [
        -688,
        96
      ],
      "parameters": {
        "options": {},
        "resource": "audio",
        "operation": "transcribe"
      },
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.8
    },
    {
      "id": "2915c932-68ee-4f84-a23c-6dda7c213449",
      "name": "OpenAI Chat Model - GPT-4o-mini",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        -16,
        256
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4o-mini",
          "cachedResultName": "gpt-4o-mini"
        },
        "options": {}
      },
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "827a05fc-f985-4e58-baf6-6e1d438736ae",
      "name": "Memory - Conversation Buffer",
      "type": "@n8n/n8n-nodes-langchain.memoryBufferWindow",
      "position": [
        128,
        256
      ],
      "parameters": {
        "sessionKey": "GEO-session",
        "sessionIdType": "customKey"
      },
      "typeVersion": 1.3
    },
    {
      "id": "2bd27d1a-f1d3-4ac7-8525-ebf4857380c6",
      "name": "Output Parser - Structured JSON",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "position": [
        256,
        256
      ],
      "parameters": {
        "jsonSchemaExample": "{ \n  \"goal\": [\n    \"Automate the creation of client proposals\",\n    \"Eliminate manual formatting and writing\",\n    \"Personalize proposals using existing CRM data\"\n  ],\n  \"execution\": [\n    \"Workflow triggers on demand or scheduled\",\n    \"Fetches lead data from Google Sheets\",\n    \"Filters only proposal-ready leads\",\n    \"GPT-4o generates custom proposal text\",\n    \"Proposal formatted into HTML email\",\n    \"Saved directly as Gmail draft\"\n  ],\n  \"outcome\": [\n    \"Significant time saved per proposal\",\n    \"Consistent, professional output\",\n    \"Higher proposal quality and personalization\",\n    \"Faster pipeline from lead to send\"\n  ],\n  \"keywords\": [\n    \"n8n workflow\",\n    \"business proposals\",\n    \"GPT-4 automation\",\n    \"sales automation\",\n    \"Google Sheets integration\",\n    \"Gmail automation\"\n  ]\n}\n"
      },
      "typeVersion": 1.3
    },
    {
      "id": "7f8a6b79-7c25-417a-8861-d8c6f6112003",
      "name": "AI Agent - GEO Analyzer",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        48,
        32
      ],
      "parameters": {
        "text": "=Video Metadata:\nID: {{ $json.videoId }}\nTitle: {{ $json.title }}\nDescription: {{ $json.description }}\nPublished At: {{ $json.publishedAt }}\nDuration (seconds): {{ $json.usage.seconds }}\n\nThumbnail: {{ $json.thumbnailUrl }}\nURL: {{ $json.videoUrl }}\n\nTranscript:\n{{ $json.text }}\n\nInstructions:\nFrom this video data, generate a structured GEO summary in JSON.\n\nUse this format:\n\n{\n  \"goal\": [],\n  \"execution\": [],\n  \"outcome\": [],\n  \"keywords\": []\n}\n\nRules for each:\n- \"goal\": What is the video trying to solve, teach, or achieve?\n- \"execution\": The step-by-step process, workflow, method, or strategy shown\n- \"outcome\": The transformation, final result, or benefit for the viewer\n- \"keywords\": Output 5\u201310 SEO keywords relevant to the content\n\nEach field must contain 2\u20135 bullet points.\nDo not repeat video title or description.\nBe accurate, concise, and factual.\n",
        "options": {
          "systemMessage": "=You are an expert YouTube content analyst AI. Your job is to analyze video content and produce structured GEO summaries that are clear, useful, and easy to rank.\n\nFollow these rules:\n- Never hallucinate\n- Never invent details not present in the text\n- Use only facts from the provided transcription and metadata\n- Be concise, insightful, and analytical\n- Do NOT repeat metadata\n- Do NOT include filler text or intros\n- Always output in exact JSON using the required keys\n"
        },
        "promptType": "define",
        "hasOutputParser": true
      },
      "typeVersion": 2.1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "734242db-4f6a-4c34-a2ca-3cf344f2b998",
  "connections": {
    "Schedule Trigger": {
      "main": [
        [
          {
            "node": "YouTube - Fetch Video Details",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI Agent - GEO Analyzer": {
      "main": [
        [
          {
            "node": "Function - Parse GEO JSON",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "HTTP - Get YouTube Audio": {
      "main": [
        [
          {
            "node": "HTTP - Download Audio File",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Function - Parse GEO JSON": {
      "main": [
        [
          {
            "node": "Notion - Create GEO Summary Page",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "HTTP - Download Audio File": {
      "main": [
        [
          {
            "node": "OpenAI - Transcribe Audio (Whisper)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "IF - Skip if No Transcript": {
      "main": [
        [
          {
            "node": "Merge - Attach Metadata + Transcript",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Memory - Conversation Buffer": {
      "ai_memory": [
        [
          {
            "node": "AI Agent - GEO Analyzer",
            "type": "ai_memory",
            "index": 0
          }
        ]
      ]
    },
    "Set - Prepare Video Metadata": {
      "main": [
        [
          {
            "node": "Merge - Attach Metadata + Transcript",
            "type": "main",
            "index": 0
          },
          {
            "node": "HTTP - Get YouTube Audio",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "YouTube - Fetch Video Details": {
      "main": [
        [
          {
            "node": "Set - Prepare Video Metadata",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model - GPT-4o-mini": {
      "ai_languageModel": [
        [
          {
            "node": "AI Agent - GEO Analyzer",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Output Parser - Structured JSON": {
      "ai_outputParser": [
        [
          {
            "node": "AI Agent - GEO Analyzer",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI - Transcribe Audio (Whisper)": {
      "main": [
        [
          {
            "node": "IF - Skip if No Transcript",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge - Attach Metadata + Transcript": {
      "main": [
        [
          {
            "node": "AI Agent - GEO Analyzer",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}