AutomationFlowsAI & RAG › Generate AI Youtube Comments and Replies From a Video URL Using Gpt-4 and…

Generate AI Youtube Comments and Replies From a Video URL Using Gpt-4 and…

Original n8n title: Generate AI Youtube Comments and Replies From a Video URL Using Gpt-4 and Google Sheets

ByAlena - Prodigy AI Sol @kroll-elly on n8n.io

A form trigger accepts any YouTube URL: youtube.com/watch?v=ID, youtu.be/ID, youtube.com/embed/ID, or just a plain video ID A code node normalises the URL and extracts a clean video ID for the YouTube Data API v3 Calls the API to fetch video stats (title, description, tags,…

Event trigger★★★★☆ complexityAI-powered25 nodesForm TriggerHTTP RequestAgentOpenAI ChatOutput Parser StructuredGoogle Sheets
AI & RAG Trigger: Event Nodes: 25 Complexity: ★★★★☆ AI nodes: yes Added:

This workflow corresponds to n8n.io template #15175 — we link there as the canonical source.

This workflow follows the Agent → Form Trigger 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 →

Download .json
{
  "id": "",
  "meta": {
    "templateCredsSetupCompleted": false
  },
  "name": "Generate AI YouTube comments and replies from a video URL with GPT-4 and Google Sheets",
  "tags": [],
  "nodes": [
    {
      "id": "f3dba414-0563-4e09-8a52-96caf10f43d2",
      "name": "Video URL Input Form",
      "type": "n8n-nodes-base.formTrigger",
      "position": [
        384,
        336
      ],
      "parameters": {
        "options": {
          "respondWithOptions": {
            "values": {
              "formSubmittedText": "Processing your video... Check Google Sheets for results!"
            }
          }
        },
        "formTitle": "YouTube Video Comment Generator",
        "formFields": {
          "values": [
            {
              "fieldLabel": "Video URL",
              "placeholder": "https://www.youtube.com/watch?v=HdafI0t3sEY",
              "requiredField": true
            },
            {
              "fieldType": "number",
              "fieldLabel": "Max Comments to Process",
              "placeholder": "10"
            }
          ]
        },
        "formDescription": "Enter a YouTube video URL to generate engagement comments and replies"
      },
      "typeVersion": 2.2
    },
    {
      "id": "9e1cb342-818f-4974-9e20-acafd9b35bf6",
      "name": "Extract Video ID from URL",
      "type": "n8n-nodes-base.code",
      "position": [
        624,
        336
      ],
      "parameters": {
        "jsCode": "// Extract video ID from a single YouTube URL\nconst videoUrl = $input.first().json['Video URL'];\nconst maxComments = $input.first().json['Max Comments to Process'] || 10;\n\nlet videoId = '';\n\n// Handle different possible YouTube URL types\nif (videoUrl.includes('youtube.com/watch?v=')) {\n  // Example: https://www.youtube.com/watch?v=Aw7IjqKAX2k\n  videoId = videoUrl.split('v=')[1].split('&')[0];\n} else if (videoUrl.includes('youtu.be/')) {\n  // Example: https://youtu.be/Aw7IjqKAX2k\n  videoId = videoUrl.split('youtu.be/')[1].split('?')[0];\n} else if (videoUrl.includes('youtube.com/embed/')) {\n  // Example: https://www.youtube.com/embed/Aw7IjqKAX2k\n  videoId = videoUrl.split('/embed/')[1].split('?')[0];\n} else if (videoUrl.includes('youtube.com/v/')) {\n  // Example: https://www.youtube.com/v/Aw7IjqKAX2k\n  videoId = videoUrl.split('/v/')[1].split('?')[0];\n} else {\n  // Assume user directly provided the video ID\n  videoId = videoUrl.trim();\n}\n\n// Clean up possible extra parameters\nvideoId = videoId.split('&')[0].split('#')[0];\n\n// \u2705 Return a single structured JSON object\nreturn [{\n  json: {\n    videoId,\n    videoUrl: `https://www.youtube.com/watch?v=${videoId}`,\n    maxComments,\n    inputType: 'Direct Link'\n  }\n}];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "9ecea677-4bc7-4098-9e2c-3cb7733f9eda",
      "name": "Get Video Statistics",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        864,
        336
      ],
      "parameters": {
        "url": "=https://www.googleapis.com/youtube/v3/videos?part=statistics,snippet&id={{ $json.videoId }}",
        "options": {},
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "youTubeOAuth2Api"
      },
      "credentials": {
        "youTubeOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.3
    },
    {
      "id": "ec751168-1993-4744-a4a5-6924d54c7806",
      "name": "Format Video Data",
      "type": "n8n-nodes-base.code",
      "position": [
        1104,
        336
      ],
      "parameters": {
        "jsCode": "// Get video data from API response\nconst response = $input.first().json;\nconst videoData = response.items && response.items[0];\nconst prevData = $('Extract Video ID from URL').first().json;\n\nif (!videoData) {\n  throw new Error('Video not found. Please check the URL.');\n}\n\nconst stats = videoData.statistics;\nconst snippet = videoData.snippet;\n\nreturn [{\n  json: {\n    items: videoData,\n    videoId: videoData.id,\n    videoUrl: prevData.videoUrl,\n    maxComments: prevData.maxComments,\n    viewCount: parseInt(stats.viewCount || 0),\n    engagementScore: parseInt(stats.likeCount || 0) + parseInt(stats.commentCount || 0),\n    selectionType: 'Direct Link Input'\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "e7561725-217d-4fcc-8c4e-d4523efb5700",
      "name": "Get Video Comments",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1504,
        192
      ],
      "parameters": {
        "url": "=https://www.googleapis.com/youtube/v3/commentThreads?part=snippet&videoId={{ $json.videoId }}&maxResults={{ $json.maxComments }}",
        "options": {},
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "youTubeOAuth2Api"
      },
      "credentials": {
        "youTubeOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.3
    },
    {
      "id": "ecdcf25e-b56a-473b-aef5-42b8925a5316",
      "name": "Extract Comments",
      "type": "n8n-nodes-base.set",
      "position": [
        1744,
        192
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "id-1",
              "name": "items",
              "type": "array",
              "value": "={{ $json.items }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "2207e462-5298-4eb5-989c-805e495c9a26",
      "name": "Process Each Comment",
      "type": "n8n-nodes-base.code",
      "position": [
        1984,
        192
      ],
      "parameters": {
        "jsCode": "// Get the items array from the Extract Comments node\nconst commentsData = $input.first().json.items;\n\n// Create an array to hold individual comment items\nconst outputItems = [];\n\n// Loop through each comment in the items array\nfor (let i = 0; i < commentsData.length; i++) {\n  const comment = commentsData[i];\n  \n  // Create an output item for each comment with its details\n  outputItems.push({\n    json: {\n      commentId: comment.snippet.topLevelComment.id,\n      textDisplay: comment.snippet.topLevelComment.snippet.textDisplay,\n      textOriginal: comment.snippet.topLevelComment.snippet.textOriginal,\n      authorDisplayName: comment.snippet.topLevelComment.snippet.authorDisplayName,\n      authorChannelUrl: comment.snippet.topLevelComment.snippet.authorChannelUrl,\n      videoId: comment.snippet.videoId,\n      channelId: comment.snippet.channelId,\n      likeCount: comment.snippet.topLevelComment.snippet.likeCount,\n      publishedAt: comment.snippet.topLevelComment.snippet.publishedAt,\n      canReply: comment.snippet.canReply,\n      totalReplyCount: comment.snippet.totalReplyCount\n    }\n  });\n}\n\n// Return all comment items\nreturn outputItems;"
      },
      "typeVersion": 2
    },
    {
      "id": "8e792844-e6c6-46f8-88ea-52a99906ecf6",
      "name": "Select Top 10 Comments",
      "type": "n8n-nodes-base.code",
      "position": [
        2224,
        192
      ],
      "parameters": {
        "jsCode": "// Get all comment items from the input\nconst comments = $input.all().map(item => item.json);\n\n// Sort by newest (publishedAt descending)\nconst newestComments = [...comments].sort((a, b) => {\n  return new Date(b.publishedAt) - new Date(a.publishedAt);\n}).slice(0, 5);\n\n// Calculate engagement score and sort by it\nconst commentsByEngagement = [...comments].map(comment => ({\n  ...comment,\n  engagementScore: (comment.likeCount || 0) + (comment.totalReplyCount || 0)\n})).sort((a, b) => b.engagementScore - a.engagementScore);\n\n// Get top 5 by engagement\nconst topEngagementComments = commentsByEngagement.slice(0, 5);\n\n// Combine and remove duplicates based on commentId\nconst selectedComments = [...newestComments];\nconst selectedIds = new Set(newestComments.map(c => c.commentId));\n\nfor (const comment of topEngagementComments) {\n  if (!selectedIds.has(comment.commentId)) {\n    selectedComments.push(comment);\n    selectedIds.add(comment.commentId);\n  }\n}\n\n// Return as n8n items\nreturn selectedComments.map(comment => ({\n  json: comment\n}));"
      },
      "typeVersion": 2
    },
    {
      "id": "5edce8bd-c1ae-4729-8965-0d4ddc4831df",
      "name": "Comment Response Generator",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        2464,
        192
      ],
      "parameters": {
        "text": "=Comment text: {{ $json.textDisplay }}\n\nVideo ID: {{ $json.videoId }}\n\nComment author: {{ $json.authorDisplayName }}",
        "options": {
          "systemMessage": "You are a real person commenting on YouTube, not an AI. You are engaging as a thoughtful viewer who watched this video and wants to join the conversation with other commenters. Your task is to:\n\n1. Read the comment and respond as a fellow viewer, not as the channel owner\n2. Share your own perspective or agree/build on their point\n3. Reference something from the video to show you actually watched it\n4. Keep it natural and conversational - like chatting with someone in comments\n5. Keep responses concise (1-2 sentences max)\n6. Return the response in the specified JSON format\n\nGuidelines:\n- You're a peer viewer, NOT the video creator - never say \"thanks for watching\" or \"glad you liked my video\"\n- Be genuine and add to the discussion like a real person would\n- Ask a follow-up question or share a related thought\n- You can politely disagree or offer a different angle\n- Mention your own experience or interest in the topic when relevant\n- Sound human - use casual language, not corporate-speak\n\nWrite like a normal human:\n- simple words\n- natural tone\n- short (1-2 sentences)\n- no formal or corporate language\n\nAvoid:\n- sounding like AI\n- being promotional\n- saying \"great video\" or generic phrases\n- talking like a company\n- emojis (or max 1 if really natural)\n\nExamples:\n- \"Yeah I noticed that too, especially the part about chunking.\"\n- \"Interesting take, I actually had a different experience with that.\"\n- \"Good point, I think this becomes tricky when you have multiple docs involved.\"\n"
        },
        "promptType": "define",
        "hasOutputParser": true
      },
      "typeVersion": 3
    },
    {
      "id": "87e33765-2bdd-4ced-bb73-164d5d20cf52",
      "name": "OpenAI Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        2464,
        416
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4.1-mini"
        },
        "options": {},
        "builtInTools": {}
      },
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "c077e85d-093f-498b-9db0-5bc1b4017180",
      "name": "Structured Output Parser",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "position": [
        2608,
        416
      ],
      "parameters": {
        "schemaType": "manual",
        "inputSchema": "{\n\t\"type\": \"object\",\n\t\"properties\": {\n\t\t\"commentReply\": {\n\t\t\t\"type\": \"string\",\n\t\t\t\"description\": \"The crafted reply to post as a comment response\"\n\t\t}\n\t}\n}"
      },
      "typeVersion": 1.3
    },
    {
      "id": "147bbd84-4d47-4531-9d8b-9d19dead6363",
      "name": "Add VideoId to Replies",
      "type": "n8n-nodes-base.set",
      "position": [
        2864,
        192
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "vid-1",
              "name": "videoId",
              "type": "string",
              "value": "={{ $('Select Top 10 Comments').item.json.videoId }}"
            },
            {
              "id": "7358e49c-158e-44c6-901c-5a7ee0abb409",
              "name": "commentText",
              "type": "string",
              "value": "={{ $('Select Top 10 Comments').item.json.textDisplay }}"
            },
            {
              "id": "44e618e3-0ed4-4847-b45a-99219601ca9c",
              "name": "commentAuthor",
              "type": "string",
              "value": "={{ $('Select Top 10 Comments').item.json.authorDisplayName }}"
            }
          ]
        },
        "includeOtherFields": true
      },
      "typeVersion": 3.4
    },
    {
      "id": "ea49599f-bbd0-4d01-8c70-840637b3048f",
      "name": "Video Comment Generator",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        1504,
        480
      ],
      "parameters": {
        "text": "=Video Title: {{ $json.items.snippet.title }}\n\nVideo Description: {{ $json.items.snippet.description }}",
        "options": {
          "systemMessage": "You are a real person leaving a top-level comment on a YouTube video you just watched. You are NOT an AI and NOT the channel owner - you are a genuine viewer sharing your thoughts.\n\nBased on the video's title and description, write ONE natural comment as if you just finished watching.\n\nYour comment should:\n1. Sound like a real viewer, not a bot\n2. Reference something specific from the title or description\n3. Share an insight, question, or personal reaction\n4. Be short (1-2 sentences max)\n5. Return the result in the specified JSON format\n\nWrite like a normal human:\n- simple words\n- natural tone\n- short (1-2 sentences)\n- no formal or corporate language\n\nAvoid:\n- sounding like AI\n- being promotional\n- saying \"great video\" or generic compliments\n- talking like a company\n- emojis (or max 1 if really natural)\n\nExamples:\n- \"The part about evaluation really clicked for me, been struggling with the same thing.\"\n- \"Curious how this holds up with bigger datasets - anyone tried?\"\n- \"Didn't expect the comparison with embeddings, makes a lot of sense now.\"\n"
        },
        "promptType": "define",
        "hasOutputParser": true
      },
      "typeVersion": 3
    },
    {
      "id": "f5e4c781-7c3e-4382-bfb7-22953ff3039a",
      "name": "Video Comment Parser",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "position": [
        1568,
        704
      ],
      "parameters": {
        "schemaType": "manual",
        "inputSchema": "{\n\t\"type\": \"object\",\n\t\"properties\": {\n\t\t\"videoComment\": {\n\t\t\t\"type\": \"string\",\n\t\t\t\"description\": \"The crafted comment to post on the video\"\n\t\t}\n\t}\n}"
      },
      "typeVersion": 1.3
    },
    {
      "id": "002e81ce-8a76-402a-9e21-057c6614d2d6",
      "name": "Add VideoId to VideoComments",
      "type": "n8n-nodes-base.set",
      "position": [
        1904,
        624
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "vid-2",
              "name": "videoId",
              "type": "string",
              "value": "={{ $('Format Video Data').first().json.items.id }}"
            }
          ]
        },
        "includeOtherFields": true
      },
      "typeVersion": 3.4
    },
    {
      "id": "a32771a0-b038-4139-89b0-4cf3de37cd37",
      "name": "Merge Wait for Video Comment",
      "type": "n8n-nodes-base.merge",
      "position": [
        3104,
        480
      ],
      "parameters": {
        "mode": "combine",
        "options": {},
        "fieldsToMatchString": "=videoId"
      },
      "typeVersion": 3.1
    },
    {
      "id": "c85a77f5-5fc4-4085-9458-001a22a4169f",
      "name": "Prepare Sheet Data",
      "type": "n8n-nodes-base.set",
      "position": [
        3344,
        480
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "id-11",
              "name": "videoId",
              "type": "string",
              "value": "={{ $json.videoId }}"
            },
            {
              "id": "id-1",
              "name": "videoUrl",
              "type": "string",
              "value": "=https://www.youtube.com/watch?v={{ $json.videoId }}"
            },
            {
              "id": "id-2",
              "name": "videoTitle",
              "type": "string",
              "value": "={{ $('Format Video Data').first().json.items.snippet.title || '' }}"
            },
            {
              "id": "id-3",
              "name": "commentAuthor",
              "type": "string",
              "value": "={{ $json.commentAuthor || '' }}"
            },
            {
              "id": "id-4",
              "name": "commentText",
              "type": "string",
              "value": "={{ $json.commentText }}"
            },
            {
              "id": "id-5",
              "name": "myReply",
              "type": "string",
              "value": "={{ $json.output?.commentReply || '' }}"
            },
            {
              "id": "id-6",
              "name": "myVideoComment",
              "type": "string",
              "value": "={{ $json.output?.videoComment || '' }}"
            },
            {
              "id": "id-7",
              "name": "selectionType",
              "type": "string",
              "value": "=Direct Link Input"
            },
            {
              "id": "id-8",
              "name": "videoTags",
              "type": "string",
              "value": "={{ ($('Format Video Data').first().json.items.snippet.tags || []).join(', ') }}"
            },
            {
              "id": "id-9",
              "name": "viewCount",
              "type": "number",
              "value": "={{ $('Format Video Data').first().json.viewCount || 0 }}"
            },
            {
              "id": "id-10",
              "name": "engagementScore",
              "type": "number",
              "value": "={{ $('Format Video Data').first().json.engagementScore || 0 }}"
            },
            {
              "id": "id-12",
              "name": "videoDescription",
              "type": "string",
              "value": "={{ $('Format Video Data').first().json.items.snippet.description || '' }}"
            },
            {
              "id": "id-13",
              "name": "likeCount",
              "type": "number",
              "value": "={{ $('Format Video Data').first().json.items.statistics.likeCount || 0 }}"
            },
            {
              "id": "id-14",
              "name": "commentCount",
              "type": "number",
              "value": "={{ $('Format Video Data').first().json.items.statistics.commentCount || 0 }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "748dba0f-bdc1-4f7c-8526-4757b31238ea",
      "name": "Save to Google Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        3584,
        480
      ],
      "parameters": {
        "columns": {
          "value": {},
          "schema": [
            {
              "id": "videoId    ",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "videoId    ",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "videoUrl    ",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "videoUrl    ",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "videoTitle",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "videoTitle",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "commentAuthor",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "commentAuthor",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "commentText ",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "commentText ",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "myReply ",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "myReply ",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "myVideoComment",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "myVideoComment",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "selectionType",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "selectionType",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "videoTags ",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "videoTags ",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "viewCount",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "viewCount",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "engagementScore",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "engagementScore",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": " videoDescription",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": " videoDescription",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "likeCount ",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "likeCount ",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "commentCount",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "commentCount",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "autoMapInputData",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultUrl": "",
          "cachedResultName": ""
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultUrl": "",
          "cachedResultName": ""
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "9fae5247-3dc3-4aaa-a4cc-0ebe1fc3fefc",
      "name": "Sticky Note 0001",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1024,
        304
      ],
      "parameters": {
        "color": 7,
        "width": 1240,
        "height": 460,
        "content": "## AI YouTube Comment & Reply Generator\n\nSubmit a YouTube URL -> get AI-generated **replies to top comments** + **one original video comment**, all saved to Google Sheets for easy review and posting.\n\n### Credentials required\n- **YouTube Data API (OAuth2)** - for fetching video stats and comments\n- **OpenAI API** - for the GPT-4 agents\n- **Google Sheets (OAuth2)** - for saving results\n\n### Quick setup (5-10 min)\n1. Connect the three credentials above\n2. In **Save to Google Sheets** -> pick your destination sheet (column names are listed in the sticky note near that node)\n3. Optional: tweak the system prompts in both AI agents to match your niche and tone\n4. Activate the workflow and submit a video URL via the form\n\n### Tips\n- Works with any YouTube URL format (watch, youtu.be, embed, or plain ID)\n- Uses gpt-4.1-mini by default - swap for any OpenAI model you prefer\n- The **Max Comments to Process** form field lets you cap the API cost per run\n"
      },
      "typeVersion": 1
    },
    {
      "id": "fc55f55f-b4cf-41fb-8883-61325e8aa24b",
      "name": "Sticky Note 0002",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        192,
        -16
      ],
      "parameters": {
        "color": 4,
        "width": 560,
        "height": 248,
        "content": "## Step 1 - Input & Extract Video ID\n\nA **Form Trigger** accepts any YouTube URL:\n- youtube.com/watch?v=ID\n- youtu.be/ID\n- youtube.com/embed/ID\n- Or just the plain VIDEO_ID\n\nThe **Code** node normalises the URL and extracts a clean video ID for downstream API calls."
      },
      "typeVersion": 1
    },
    {
      "id": "f727fb07-60e1-4039-a105-577bb9efb589",
      "name": "Sticky Note 0003",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        832,
        32
      ],
      "parameters": {
        "color": 3,
        "width": 500,
        "height": 200,
        "content": "## Step 2 - Fetch Video Stats\n\nCalls **YouTube Data API v3** (/videos endpoint) to pull:\n- Title, description, tags\n- View / like / comment counts\n\n**Format Video Data** restructures the response for the rest of the flow."
      },
      "typeVersion": 1
    },
    {
      "id": "bd8cf657-7d0d-466a-9fc0-6fed20103077",
      "name": "Sticky Note 0004",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1408,
        -176
      ],
      "parameters": {
        "color": 6,
        "width": 900,
        "height": 220,
        "content": "## Step 3 - Get & Rank Top Comments\n\n1. Fetches comments via commentThreads (capped by the form's Max Comments field)\n2. Flattens each comment into its own item\n3. **Select Top 10 Comments** merges two lists, deduped by commentId:\n   - 5 **newest** comments (by publishedAt)\n   - 5 **highest-engagement** comments (likes + replies)\n\nYou always get ~10 unique, high-value comments worth responding to."
      },
      "typeVersion": 1
    },
    {
      "id": "6b88a98b-a4f5-4662-b8aa-e3bee51fcc9d",
      "name": "Sticky Note 0005",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2432,
        -160
      ],
      "parameters": {
        "color": 5,
        "width": 700,
        "height": 248,
        "content": "## Step 4a - AI Replies to Each Comment\n\n**Comment Response Generator** writes a natural, human-sounding reply per comment.\n\n- Responds as a fellow viewer, never as the creator\n- Uses GPT-4.1-mini (cheap + fast) - swap models freely\n- **Structured Output Parser** guarantees a clean commentReply field\n- Style rules live in the system prompt: short, casual, no corporate tone\n\nEdit the system prompt to match your niche, voice, or brand."
      },
      "typeVersion": 1
    },
    {
      "id": "de20262a-1fd1-4e85-b20c-6a999ca1b403",
      "name": "Sticky Note 0006",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1488,
        864
      ],
      "parameters": {
        "color": 5,
        "width": 540,
        "height": 380,
        "content": "## Step 4b - AI Writes a Video Comment\n\nRuns in parallel. **Video Comment Generator** writes ONE original top-level comment from the video's title + description.\n\nShares the OpenAI model with the reply agent. Merged with the replies downstream."
      },
      "typeVersion": 1
    },
    {
      "id": "1a6de9b2-7972-415f-9ba1-d9d32a731cb7",
      "name": "Sticky Note 0007",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3360,
        -96
      ],
      "parameters": {
        "color": 3,
        "width": 780,
        "height": 280,
        "content": "## Step 5 - Merge & Save to Google Sheets\n\n- **Merge** joins each reply with the video comment by videoId\n- **Prepare Sheet Data** normalises the final row shape\n- **Save to Google Sheets** appends one row per reply\n\n### Required columns in your sheet\nvideoId, videoUrl, videoTitle, commentAuthor, commentText, myReply, myVideoComment, selectionType, videoTags, viewCount, engagementScore, videoDescription, likeCount, commentCount\n\nIMPORTANT: After importing, open this node and select your own Sheet + tab."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "executionOrder": "v1"
  },
  "versionId": "",
  "connections": {
    "Extract Comments": {
      "main": [
        [
          {
            "node": "Process Each Comment",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format Video Data": {
      "main": [
        [
          {
            "node": "Get Video Comments",
            "type": "main",
            "index": 0
          },
          {
            "node": "Video Comment Generator",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "Comment Response Generator",
            "type": "ai_languageModel",
            "index": 0
          },
          {
            "node": "Video Comment Generator",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Get Video Comments": {
      "main": [
        [
          {
            "node": "Extract Comments",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Sheet Data": {
      "main": [
        [
          {
            "node": "Save to Google Sheets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Video Statistics": {
      "main": [
        [
          {
            "node": "Format Video Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Process Each Comment": {
      "main": [
        [
          {
            "node": "Select Top 10 Comments",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Video Comment Parser": {
      "ai_outputParser": [
        [
          {
            "node": "Video Comment Generator",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "Video URL Input Form": {
      "main": [
        [
          {
            "node": "Extract Video ID from URL",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Add VideoId to Replies": {
      "main": [
        [
          {
            "node": "Merge Wait for Video Comment",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Select Top 10 Comments": {
      "main": [
        [
          {
            "node": "Comment Response Generator",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Video Comment Generator": {
      "main": [
        [
          {
            "node": "Add VideoId to VideoComments",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Structured Output Parser": {
      "ai_outputParser": [
        [
          {
            "node": "Comment Response Generator",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "Extract Video ID from URL": {
      "main": [
        [
          {
            "node": "Get Video Statistics",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Comment Response Generator": {
      "main": [
        [
          {
            "node": "Add VideoId to Replies",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Add VideoId to VideoComments": {
      "main": [
        [
          {
            "node": "Merge Wait for Video Comment",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Merge Wait for Video Comment": {
      "main": [
        [
          {
            "node": "Prepare Sheet Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}

Credentials you'll need

Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.

Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

A form trigger accepts any YouTube URL: youtube.com/watch?v=ID, youtu.be/ID, youtube.com/embed/ID, or just a plain video ID A code node normalises the URL and extracts a clean video ID for the YouTube Data API v3 Calls the API to fetch video stats (title, description, tags,…

Source: https://n8n.io/workflows/15175/ — original creator credit. Request a take-down →

More AI & RAG workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

AI & RAG

🎯 Create viral TikToks, Shorts, Reels, podcasts, and ASMR videos in minutes — all on autopilot.

OpenAI, HTTP Request, Form Trigger +7
AI & RAG

Digistars - Scrape & Crawl. Uses httpRequest, n8n-nodes-firecrawl-scraper, googleSheets, lmChatOpenAi. Event-driven trigger; 63 nodes.

HTTP Request, N8N Nodes Firecrawl Scraper, Google Sheets +5
AI & RAG

🧠 Automate end-to-end SEO blog creation and WordPress publishing using a GPT-5 multi-agent workflow with real-time research, metadata generation, and optional featured images.

Output Parser Structured, HTTP Request, OpenAI +10
AI & RAG

The workflow runs every hour with a randomized delay of 5–20 minutes to help distribute load. It records the exact date and time a lead is emailed so you can track outreach. Follow-ups are automatical

Google Sheets, Agent, OpenAI Chat +5
AI & RAG

Transform your manual hiring process into an intelligent evaluation system that saves 15-20 minutes per candidate! This workflow automates the entire candidate assessment pipeline - from CSV/XLSX uplo

Form Trigger, Google Sheets, Google Drive +8