AutomationFlowsAI & RAG › Analyze Youtube Videos with Gpt-4o-mini and Get Relevance-ranked Insights

Analyze Youtube Videos with Gpt-4o-mini and Get Relevance-ranked Insights

ByIncrementors @incrementors on n8n.io

Submit up to 3 YouTube video URLs using a simple form and the workflow handles everything automatically. It fetches each video's title, channel, views, and duration from YouTube, submits each video to WayinVideo for accurate speaker-labeled transcription, then sends the…

Event trigger★★★★☆ complexityAI-powered27 nodesForm TriggerHTTP RequestAgentOpenAI ChatOutput Parser StructuredGoogle SheetsGmail
AI & RAG Trigger: Event Nodes: 27 Complexity: ★★★★☆ AI nodes: yes Added:

This workflow corresponds to n8n.io template #15183 — 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
{
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "nodes": [
    {
      "id": "8f61aa3f-eeef-441f-904e-f28864fa2f54",
      "name": "Overview",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -6336,
        -304
      ],
      "parameters": {
        "color": 4,
        "width": 572,
        "height": 1360,
        "content": "## YouTube Video Intelligence Tracker \u2014 YouTube API + WayinVideo + GPT-4o-mini + Sheets + Gmail\n\nFor content marketers, SEO strategists, and research teams who want structured intelligence from YouTube videos \u2014 not just auto-captions, but real speaker-labeled transcripts with GPT analysis tailored to your niche. Submit up to 3 YouTube URLs via the form. The workflow fetches title, channel, views, and duration from the YouTube Data API, submits each video to WayinVideo for accurate transcription, then sends the transcript to GPT-4o-mini for a 6-field analysis: summary, key topics, best quote, target audience, a relevance score for your niche, and a content gap your competitors missed. All results are logged to Google Sheets and emailed in a single report sorted by relevance.\n\n## How it works\n- **1. Form \u2014 YouTube Video Intelligence** collects up to 3 YouTube video URLs and your name\n- **2. Set \u2014 Config Values** stores both API keys, Sheet ID, email, niche, and form values\n- **3. Code \u2014 Extract Video IDs** parses video IDs from youtube.com and youtu.be URL formats and outputs one item per video\n- **4. HTTP \u2014 Fetch YouTube Metadata** calls the YouTube Data API v3 for title, channel, views, duration, and published date\n- **5. Code \u2014 Process Video Metadata** formats ISO 8601 duration to readable text and adds comma-formatted view counts\n- **6. HTTP \u2014 Submit Transcription Task** sends each video URL to WayinVideo for real speaker-labeled transcription\n- **7. Code \u2014 Save Transcript Task ID** saves the task ID and initializes the poll counter\n- **8\u201311. Transcription Polling Loop** polls every 45 seconds until SUCCEEDED \u2014 up to 15 polls (11 minutes). Groups transcript by speaker. Falls back to video description if empty\n- **13. AI Agent \u2014 Analyze Video** uses GPT-4o-mini to return summary, key topics, best quote, target audience, relevance score for your niche, and content gap\n- **16. Code \u2014 Prepare Results** formats all fields and adds a High/Medium/Low score label\n- **17. Google Sheets \u2014 Log Video Analysis** logs one row per video permanently\n- **18. IF \u2014 Last Video?** gates the Gmail report so it fires exactly once after all videos are logged\n- **19. Code \u2014 Build Gmail Report** collects all video results, sorts by relevance score, and builds the email\n- **20. Gmail \u2014 Send Intelligence Report** delivers the complete report to your inbox\n\n## Set up steps\n1. In **2. Set \u2014 Config Values** \u2014 replace PASTE_YOUR_YOUTUBE_DATA_API_KEY_HERE (from Google Cloud Console, enable YouTube Data API v3), PASTE_YOUR_WAYINVIDEO_API_KEY_HERE (from wayin.ai Account Settings), PASTE_YOUR_GOOGLE_SHEET_ID_HERE, PASTE_YOUR_EMAIL_HERE, PASTE_YOUR_NAME_HERE, and set yourNiche to your industry\n2. In **14. OpenAI \u2014 GPT-4o-mini Model** \u2014 connect your OpenAI credential\n3. In **17. Google Sheets \u2014 Log Video Analysis** \u2014 connect your Google Sheets OAuth2 credential\n4. In **20. Gmail \u2014 Send Intelligence Report** \u2014 connect your Gmail OAuth2 credential\n5. Create a Google Sheet tab named YouTube Intelligence with columns: Date, Video URL, Title, Channel, Views, Duration, Published, Summary, Key Topics, Best Quote, Target Audience, Relevance Score, Content Gap, Submitted By, Logged At"
      },
      "typeVersion": 1
    },
    {
      "id": "9ed92566-d766-4399-840c-cab58e2d3c75",
      "name": "Section \u2014 Form Input, Config, and Video ID Extraction",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -5728,
        -32
      ],
      "parameters": {
        "color": 5,
        "width": 660,
        "height": 388,
        "content": "## Form Input, Config, and Video ID Extraction\nUser submits up to 3 YouTube video URLs. Config stores both API keys, sheet settings, email, and niche. A Code node extracts video IDs from both youtube.com and youtu.be URL formats and outputs one item per valid video."
      },
      "typeVersion": 1
    },
    {
      "id": "b4a6bdc6-a104-464d-81a8-6e80b77eb55e",
      "name": "Section \u2014 YouTube Metadata Fetch and WayinVideo Submission",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -5040,
        -32
      ],
      "parameters": {
        "color": 6,
        "width": 852,
        "height": 388,
        "content": "## YouTube Metadata Fetch and WayinVideo Transcription Submission\nYouTube Data API v3 fetches title, channel, views, duration (converted from ISO 8601), and published date. WayinVideo receives the video URL for real speaker-labeled transcription. Task ID is saved for polling."
      },
      "typeVersion": 1
    },
    {
      "id": "5027e054-1cab-4638-a17a-00505f7549e6",
      "name": "Section \u2014 Transcription Polling Loop",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -4128,
        -32
      ],
      "parameters": {
        "color": 6,
        "width": 916,
        "height": 564,
        "content": "## Transcription Polling Loop\nPolls WayinVideo every 45 seconds until SUCCEEDED. Groups transcript segments by speaker. Falls back to video description if transcript is empty. Caps at 5000 characters for GPT. Loops back via Set node to preserve all data. Hard timeout after 15 polls (approximately 11 minutes)."
      },
      "typeVersion": 1
    },
    {
      "id": "bf7357e3-b939-45bd-b730-d653534a313e",
      "name": "Section \u2014 AI Video Analysis",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -3152,
        -144
      ],
      "parameters": {
        "color": 6,
        "width": 484,
        "height": 836,
        "content": "## AI Video Analysis\nGPT-4o-mini (temperature 0.2) analyzes the transcript and returns 6 fields: a 3\u20134 sentence summary, 5 key topics, the best quote, target audience, a relevance score from 1 to 10 for your niche, and a content gap your competitors missed."
      },
      "typeVersion": 1
    },
    {
      "id": "a9c7c118-b4fd-425f-9111-1fdf2608ef7f",
      "name": "Section \u2014 Results Assembly, Sheet Logging, and Gmail Report",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2608,
        -304
      ],
      "parameters": {
        "color": 4,
        "width": 932,
        "height": 932,
        "content": "## Results Assembly, Sheet Logging, and Gmail Report\nPrepares all fields with score labels. Google Sheets logs one row per video. The IF node checks isLastVideo \u2014 only the final video triggers Gmail. The report collects all processed videos using .all(), sorts by relevance score, and emails a complete intelligence digest."
      },
      "typeVersion": 1
    },
    {
      "id": "7be1b7fa-0f45-4230-a63a-6cb724717f2d",
      "name": "1. Form \u2014 YouTube Video Intelligence",
      "type": "n8n-nodes-base.formTrigger",
      "position": [
        -5664,
        112
      ],
      "parameters": {
        "options": {},
        "formTitle": "YouTube Video Intelligence Tracker",
        "formFields": {
          "values": [
            {
              "fieldLabel": "Video 1 URL",
              "placeholder": "https://www.youtube.com/watch?v=...",
              "requiredField": true
            },
            {
              "fieldLabel": "Video 2 URL",
              "placeholder": "https://www.youtube.com/watch?v=... (leave blank to skip)"
            },
            {
              "fieldLabel": "Video 3 URL",
              "placeholder": "https://www.youtube.com/watch?v=... (leave blank to skip)"
            },
            {
              "fieldLabel": "Your Name",
              "placeholder": "Example: Rahul Dutt"
            }
          ]
        },
        "formDescription": "Analyze up to 3 YouTube videos at once. Get structured summaries, key topics, best quotes, and relevance scores. All saved to Google Sheets and emailed to you."
      },
      "typeVersion": 2.2
    },
    {
      "id": "9d44ae70-fbcf-40f0-810c-d39436c590c7",
      "name": "2. Set \u2014 Config Values",
      "type": "n8n-nodes-base.set",
      "position": [
        -5440,
        112
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "cfg-001",
              "name": "youtubeApiKey",
              "type": "string",
              "value": "PASTE_YOUR_YOUTUBE_DATA_API_KEY_HERE"
            },
            {
              "id": "cfg-002",
              "name": "wayinVideoApiKey",
              "type": "string",
              "value": "PASTE_YOUR_WAYINVIDEO_API_KEY_HERE"
            },
            {
              "id": "cfg-003",
              "name": "sheetId",
              "type": "string",
              "value": "PASTE_YOUR_GOOGLE_SHEET_ID_HERE"
            },
            {
              "id": "cfg-004",
              "name": "sheetName",
              "type": "string",
              "value": "YouTube Intelligence"
            },
            {
              "id": "cfg-005",
              "name": "recipientEmail",
              "type": "string",
              "value": "PASTE_YOUR_EMAIL_HERE"
            },
            {
              "id": "cfg-006",
              "name": "senderName",
              "type": "string",
              "value": "PASTE_YOUR_NAME_HERE"
            },
            {
              "id": "cfg-007",
              "name": "yourNiche",
              "type": "string",
              "value": "SEO and digital marketing"
            },
            {
              "id": "cfg-008",
              "name": "video1Url",
              "type": "string",
              "value": "={{ $json['Video 1 URL']?.trim() || '' }}"
            },
            {
              "id": "cfg-009",
              "name": "video2Url",
              "type": "string",
              "value": "={{ $json['Video 2 URL']?.trim() || '' }}"
            },
            {
              "id": "cfg-010",
              "name": "video3Url",
              "type": "string",
              "value": "={{ $json['Video 3 URL']?.trim() || '' }}"
            },
            {
              "id": "cfg-011",
              "name": "submittedBy",
              "type": "string",
              "value": "={{ $json['Your Name'] || 'Unknown' }}"
            },
            {
              "id": "cfg-012",
              "name": "today",
              "type": "string",
              "value": "={{ $now.toFormat('dd MMM yyyy') }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "441b2f7c-35a4-4f5f-86a0-55119391d926",
      "name": "3. Code \u2014 Extract Video IDs",
      "type": "n8n-nodes-base.code",
      "position": [
        -5216,
        112
      ],
      "parameters": {
        "jsCode": "const config = $input.first().json;\n\nconst videos = [\n  config.video1Url,\n  config.video2Url,\n  config.video3Url\n].filter(url => url && (url.includes('youtube.com') || url.includes('youtu.be')));\n\nif (videos.length === 0) {\n  throw new Error('No valid YouTube URLs found. Please submit at least one YouTube URL.');\n}\n\nconst extractVideoId = (url) => {\n  try {\n    if (url.includes('youtu.be/')) {\n      return url.split('youtu.be/')[1].split('?')[0].split('&')[0];\n    }\n    const urlObj = new URL(url);\n    return urlObj.searchParams.get('v') || '';\n  } catch (e) {\n    return '';\n  }\n};\n\nreturn videos.map((url, index) => {\n  const videoId = extractVideoId(url);\n  return {\n    json: {\n      originalUrl: url,\n      videoId,\n      videoIndex: index + 1,\n      totalVideos: videos.length,\n      isLastVideo: index === videos.length - 1,\n      youtubeApiKey: config.youtubeApiKey,\n      wayinVideoApiKey: config.wayinVideoApiKey,\n      sheetId: config.sheetId,\n      sheetName: config.sheetName,\n      recipientEmail: config.recipientEmail,\n      senderName: config.senderName,\n      yourNiche: config.yourNiche,\n      submittedBy: config.submittedBy,\n      today: config.today\n    }\n  };\n});"
      },
      "typeVersion": 2
    },
    {
      "id": "0f7d5825-9725-44c8-8f79-8a983b293843",
      "name": "4. HTTP \u2014 Fetch YouTube Metadata",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -4992,
        112
      ],
      "parameters": {
        "url": "=https://www.googleapis.com/youtube/v3/videos",
        "options": {},
        "sendQuery": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "id",
              "value": "={{ $json.videoId }}"
            },
            {
              "name": "part",
              "value": "snippet,statistics,contentDetails"
            },
            {
              "name": "key",
              "value": "={{ $json.youtubeApiKey }}"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "9a7ef8e3-5c48-4034-a3ec-66aa91f16239",
      "name": "5. Code \u2014 Process Video Metadata",
      "type": "n8n-nodes-base.code",
      "position": [
        -4784,
        112
      ],
      "parameters": {
        "jsCode": "const response = $input.first().json;\nconst videoData = $('3. Code \u2014 Extract Video IDs').item.json;\n\nconst item = response?.items?.[0];\n\nif (!item) {\n  throw new Error('Video not found or is private: ' + videoData.originalUrl);\n}\n\nconst snippet = item.snippet || {};\nconst stats = item.statistics || {};\nconst details = item.contentDetails || {};\n\nconst rawDuration = details.duration || 'PT0S';\nconst durationMatch = rawDuration.match(/PT(?:(\\d+)H)?(?:(\\d+)M)?(?:(\\d+)S)?/);\nconst hours = parseInt(durationMatch?.[1] || 0);\nconst minutes = parseInt(durationMatch?.[2] || 0);\nconst seconds = parseInt(durationMatch?.[3] || 0);\nconst duration = (hours > 0 ? hours + 'h ' : '') + (minutes > 0 ? minutes + 'm ' : '') + seconds + 's';\n\nconst views = parseInt(stats.viewCount || 0).toLocaleString('en-US');\n\nconst publishedDate = snippet.publishedAt\n  ? new Date(snippet.publishedAt).toLocaleDateString('en-GB', { day: '2-digit', month: 'short', year: 'numeric' })\n  : 'Unknown';\n\nreturn [{\n  json: {\n    videoId: videoData.videoId,\n    originalUrl: videoData.originalUrl,\n    title: snippet.title || 'Unknown Title',\n    channel: snippet.channelTitle || 'Unknown Channel',\n    description: (snippet.description || '').substring(0, 500),\n    views,\n    duration,\n    publishedDate,\n    videoIndex: videoData.videoIndex,\n    totalVideos: videoData.totalVideos,\n    isLastVideo: videoData.isLastVideo,\n    wayinVideoApiKey: videoData.wayinVideoApiKey,\n    sheetId: videoData.sheetId,\n    sheetName: videoData.sheetName,\n    recipientEmail: videoData.recipientEmail,\n    senderName: videoData.senderName,\n    yourNiche: videoData.yourNiche,\n    submittedBy: videoData.submittedBy,\n    today: videoData.today\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "bdfb566c-fb7c-4038-a84e-3b5a1231ad0f",
      "name": "6. HTTP \u2014 Submit Transcription Task",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -4560,
        112
      ],
      "parameters": {
        "url": "https://wayinvideo-api.wayin.ai/api/v2/transcripts",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"video_url\": \"{{ $json.originalUrl }}\",\n  \"target_lang\": \"en\"\n}",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            },
            {
              "name": "Authorization",
              "value": "=Bearer {{ $json.wayinVideoApiKey }}"
            },
            {
              "name": "x-wayinvideo-api-version",
              "value": "v2"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "c61a55b0-21d1-40a6-9183-29c977012713",
      "name": "7. Code \u2014 Save Transcript Task ID",
      "type": "n8n-nodes-base.code",
      "position": [
        -4336,
        112
      ],
      "parameters": {
        "jsCode": "const response = $input.first().json;\nconst videoData = $('5. Code \u2014 Process Video Metadata').item.json;\n\nconst transcriptId = response?.data?.id;\n\nif (!transcriptId) {\n  throw new Error('WayinVideo did not return a task ID. Check your WayinVideo API key.');\n}\n\nreturn [{\n  json: {\n    transcriptId,\n    transcriptStatus: response?.data?.status || 'CREATED',\n    pollCount: 0,\n    videoId: videoData.videoId,\n    originalUrl: videoData.originalUrl,\n    title: videoData.title,\n    channel: videoData.channel,\n    description: videoData.description,\n    views: videoData.views,\n    duration: videoData.duration,\n    publishedDate: videoData.publishedDate,\n    videoIndex: videoData.videoIndex,\n    totalVideos: videoData.totalVideos,\n    isLastVideo: videoData.isLastVideo,\n    wayinVideoApiKey: videoData.wayinVideoApiKey,\n    sheetId: videoData.sheetId,\n    sheetName: videoData.sheetName,\n    recipientEmail: videoData.recipientEmail,\n    senderName: videoData.senderName,\n    yourNiche: videoData.yourNiche,\n    submittedBy: videoData.submittedBy,\n    today: videoData.today\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "35796446-d847-4ffe-8902-587517b7fca6",
      "name": "8. Wait \u2014 45 Seconds",
      "type": "n8n-nodes-base.wait",
      "position": [
        -4064,
        112
      ],
      "parameters": {
        "amount": 45
      },
      "typeVersion": 1.1
    },
    {
      "id": "28f7701f-1ab0-45b7-8eec-c8774f657187",
      "name": "9. HTTP \u2014 Poll Transcript Results",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -3840,
        112
      ],
      "parameters": {
        "url": "=https://wayinvideo-api.wayin.ai/api/v2/transcripts/results/{{ $json.transcriptId }}",
        "options": {},
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "=Bearer {{ $json.wayinVideoApiKey }}"
            },
            {
              "name": "x-wayinvideo-api-version",
              "value": "v2"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "67eeba6c-532f-4d28-8c6b-2c35b0353115",
      "name": "10. Code \u2014 Check Transcript Status",
      "type": "n8n-nodes-base.code",
      "position": [
        -3616,
        112
      ],
      "parameters": {
        "jsCode": "const pollResponse = $input.first().json;\nconst prev = $('7. Code \u2014 Save Transcript Task ID').item.json;\n\nconst status = pollResponse?.data?.status || 'UNKNOWN';\nconst pollCount = (prev.pollCount || 0) + 1;\n\nif (pollCount >= 15 && status !== 'SUCCEEDED') {\n  throw new Error('WayinVideo transcription timed out after 15 polls (about 11 minutes). Task ID: ' + prev.transcriptId);\n}\n\nif (status === 'FAILED') {\n  const errorMsg = pollResponse?.data?.error_message || 'Unknown error';\n  throw new Error('WayinVideo transcription failed: ' + errorMsg);\n}\n\nlet transcriptText = '';\nif (status === 'SUCCEEDED') {\n  const segments = pollResponse?.data?.transcript || [];\n  let currentSpeaker = '';\n  segments.forEach(seg => {\n    const speaker = seg.speaker || 'Speaker';\n    const text = (seg.text || '').trim();\n    if (!text) return;\n    if (speaker !== currentSpeaker) {\n      transcriptText += '\\n' + speaker + ': ';\n      currentSpeaker = speaker;\n    }\n    transcriptText += text + ' ';\n  });\n  transcriptText = transcriptText.trim();\n}\n\nif (!transcriptText || transcriptText.length < 50) {\n  transcriptText = 'Transcript not available. Using video description instead:\\n\\n' + (prev.description || 'No description available.');\n}\n\ntranscriptText = transcriptText.substring(0, 5000);\n\nreturn [{\n  json: {\n    transcriptId: prev.transcriptId,\n    transcriptStatus: status,\n    transcriptText,\n    pollCount,\n    isReady: status === 'SUCCEEDED',\n    videoId: prev.videoId,\n    originalUrl: prev.originalUrl,\n    title: prev.title,\n    channel: prev.channel,\n    views: prev.views,\n    duration: prev.duration,\n    publishedDate: prev.publishedDate,\n    videoIndex: prev.videoIndex,\n    totalVideos: prev.totalVideos,\n    isLastVideo: prev.isLastVideo,\n    wayinVideoApiKey: prev.wayinVideoApiKey,\n    sheetId: prev.sheetId,\n    sheetName: prev.sheetName,\n    recipientEmail: prev.recipientEmail,\n    senderName: prev.senderName,\n    yourNiche: prev.yourNiche,\n    submittedBy: prev.submittedBy,\n    today: prev.today\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "14ace53f-2c39-45e8-8271-533fdc442c48",
      "name": "11. IF \u2014 Transcript Ready?",
      "type": "n8n-nodes-base.if",
      "position": [
        -3392,
        112
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "leftValue": "",
            "caseSensitive": false,
            "typeValidation": "loose"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "cond-ready",
              "operator": {
                "type": "boolean",
                "operation": "true"
              },
              "leftValue": "={{ $json.isReady }}",
              "rightValue": true
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "8fe22f57-11ee-46d3-a01e-897374d699be",
      "name": "12. Set \u2014 Still Processing Loop Back",
      "type": "n8n-nodes-base.set",
      "position": [
        -3392,
        336
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "loop-transcript-001",
              "name": "transcriptId",
              "type": "string",
              "value": "={{ $json.transcriptId }}"
            },
            {
              "id": "loop-transcript-002",
              "name": "pollCount",
              "type": "number",
              "value": "={{ $json.pollCount }}"
            },
            {
              "id": "loop-transcript-003",
              "name": "wayinVideoApiKey",
              "type": "string",
              "value": "={{ $json.wayinVideoApiKey }}"
            },
            {
              "id": "loop-transcript-004",
              "name": "videoId",
              "type": "string",
              "value": "={{ $json.videoId }}"
            },
            {
              "id": "loop-transcript-005",
              "name": "originalUrl",
              "type": "string",
              "value": "={{ $json.originalUrl }}"
            },
            {
              "id": "loop-transcript-006",
              "name": "title",
              "type": "string",
              "value": "={{ $json.title }}"
            },
            {
              "id": "loop-transcript-007",
              "name": "channel",
              "type": "string",
              "value": "={{ $json.channel }}"
            },
            {
              "id": "loop-transcript-008",
              "name": "description",
              "type": "string",
              "value": "={{ $json.description }}"
            },
            {
              "id": "loop-transcript-009",
              "name": "views",
              "type": "string",
              "value": "={{ $json.views }}"
            },
            {
              "id": "loop-transcript-010",
              "name": "duration",
              "type": "string",
              "value": "={{ $json.duration }}"
            },
            {
              "id": "loop-transcript-011",
              "name": "publishedDate",
              "type": "string",
              "value": "={{ $json.publishedDate }}"
            },
            {
              "id": "loop-transcript-012",
              "name": "videoIndex",
              "type": "number",
              "value": "={{ $json.videoIndex }}"
            },
            {
              "id": "loop-transcript-013",
              "name": "totalVideos",
              "type": "number",
              "value": "={{ $json.totalVideos }}"
            },
            {
              "id": "loop-transcript-014",
              "name": "isLastVideo",
              "type": "boolean",
              "value": "={{ $json.isLastVideo }}"
            },
            {
              "id": "loop-transcript-015",
              "name": "sheetId",
              "type": "string",
              "value": "={{ $json.sheetId }}"
            },
            {
              "id": "loop-transcript-016",
              "name": "sheetName",
              "type": "string",
              "value": "={{ $json.sheetName }}"
            },
            {
              "id": "loop-transcript-017",
              "name": "recipientEmail",
              "type": "string",
              "value": "={{ $json.recipientEmail }}"
            },
            {
              "id": "loop-transcript-018",
              "name": "senderName",
              "type": "string",
              "value": "={{ $json.senderName }}"
            },
            {
              "id": "loop-transcript-019",
              "name": "yourNiche",
              "type": "string",
              "value": "={{ $json.yourNiche }}"
            },
            {
              "id": "loop-transcript-020",
              "name": "submittedBy",
              "type": "string",
              "value": "={{ $json.submittedBy }}"
            },
            {
              "id": "loop-transcript-021",
              "name": "today",
              "type": "string",
              "value": "={{ $json.today }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "5536ec22-e588-4b36-9e13-e9312d711f0f",
      "name": "13. AI Agent \u2014 Analyze Video",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        -3008,
        96
      ],
      "parameters": {
        "text": "=You are a content intelligence analyst for a {{ $json.yourNiche }} professional.\n\nAnalyze this YouTube video and return ONLY a valid JSON object. No extra text. No markdown. No backticks.\n\nVideo details:\nTitle: {{ $json.title }}\nChannel: {{ $json.channel }}\nViews: {{ $json.views }}\nDuration: {{ $json.duration }}\nPublished: {{ $json.publishedDate }}\nURL: {{ $json.originalUrl }}\n\nTranscript:\n{{ $json.transcriptText }}\n\nReturn exactly these 6 fields:\n\nsummary\n3 to 4 sentences summarizing what this video covers. Be specific \u2014 mention the actual topics and any key data points. Under 80 words.\n\nkeyTopics\nAn array of exactly 5 strings. The most important topics, concepts, or tactics covered in this video. Each under 8 words.\n\nbestQuote\nThe single most memorable or insightful statement from the transcript. One sentence under 25 words. If no clear quote is found write: No standout quote identified.\n\ntargetAudience\nOne sentence describing who this video is most useful for. Under 15 words.\n\nrelevanceScore\nA number from 1 to 10 showing how relevant this video is for a {{ $json.yourNiche }} professional.\n10 means directly actionable and highly relevant.\n7 to 9 means strong relevance with useful insights.\n4 to 6 means general interest or partial relevance.\n1 to 3 means low relevance for this niche.\n\ncontentGap\nOne thing this video did NOT cover that would make it more useful for a {{ $json.yourNiche }} professional. One sentence under 20 words.",
        "options": {},
        "promptType": "define",
        "hasOutputParser": true
      },
      "typeVersion": 1.7
    },
    {
      "id": "efac5738-e1da-4d61-b242-ef24c5db3949",
      "name": "14. OpenAI \u2014 GPT-4o-mini Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        -3008,
        304
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4o-mini"
        },
        "options": {
          "maxTokens": 600,
          "temperature": 0.2
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "d26db9e9-1728-4daf-bc36-5706b23dd85f",
      "name": "15. Parser \u2014 Structured Video Analysis",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "position": [
        -2864,
        528
      ],
      "parameters": {
        "schemaType": "manual",
        "inputSchema": "{\n  \"type\": \"object\",\n  \"properties\": {\n    \"summary\": { \"type\": \"string\", \"description\": \"3 to 4 sentence video summary\" },\n    \"keyTopics\": { \"type\": \"array\", \"items\": { \"type\": \"string\" }, \"description\": \"5 key topics covered\" },\n    \"bestQuote\": { \"type\": \"string\", \"description\": \"Most memorable statement from video\" },\n    \"targetAudience\": { \"type\": \"string\", \"description\": \"Who this video is for\" },\n    \"relevanceScore\": { \"type\": \"number\", \"description\": \"Relevance from 1 to 10\" },\n    \"contentGap\": { \"type\": \"string\", \"description\": \"What the video did not cover\" }\n  },\n  \"required\": [\"summary\", \"keyTopics\", \"bestQuote\", \"targetAudience\", \"relevanceScore\", \"contentGap\"]\n}"
      },
      "typeVersion": 1.3
    },
    {
      "id": "0c96f07e-2284-44cc-aaae-a7ac5ea7d72b",
      "name": "16. Code \u2014 Prepare Results",
      "type": "n8n-nodes-base.code",
      "position": [
        -2576,
        96
      ],
      "parameters": {
        "jsCode": "const aiOutput = $input.first().json.output;\nconst videoData = $('10. Code \u2014 Check Transcript Status').item.json;\n\nconst score = aiOutput?.relevanceScore || 0;\nconst scoreLabel = score >= 8 ? 'High' : score >= 5 ? 'Medium' : 'Low';\nconst keyTopics = (aiOutput?.keyTopics || []).join(', ');\n\nconst loggedAt = new Date().toISOString().replace('T', ' ').substring(0, 16);\n\nreturn [{\n  json: {\n    today: videoData.today,\n    originalUrl: videoData.originalUrl,\n    title: videoData.title,\n    channel: videoData.channel,\n    views: videoData.views,\n    duration: videoData.duration,\n    publishedDate: videoData.publishedDate,\n    summary: aiOutput?.summary || 'Not available',\n    keyTopics,\n    bestQuote: aiOutput?.bestQuote || 'Not available',\n    targetAudience: aiOutput?.targetAudience || 'Not available',\n    relevanceScore: score + ' out of 10 \u2014 ' + scoreLabel,\n    contentGap: aiOutput?.contentGap || 'Not available',\n    submittedBy: videoData.submittedBy,\n    loggedAt,\n    rawScore: score,\n    isLastVideo: videoData.isLastVideo,\n    sheetId: videoData.sheetId,\n    sheetName: videoData.sheetName,\n    recipientEmail: videoData.recipientEmail,\n    senderName: videoData.senderName,\n    yourNiche: videoData.yourNiche\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "f7232287-4520-42e9-b78e-6c04ae757e91",
      "name": "17. Google Sheets \u2014 Log Video Analysis",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        -2352,
        -80
      ],
      "parameters": {
        "columns": {
          "value": {
            "Date": "={{ $json.today }}",
            "Title": "={{ $json.title }}",
            "Views": "={{ $json.views }}",
            "Channel": "={{ $json.channel }}",
            "Summary": "={{ $json.summary }}",
            "Duration": "={{ $json.duration }}",
            "Logged At": "={{ $json.loggedAt }}",
            "Published": "={{ $json.publishedDate }}",
            "Video URL": "={{ $json.originalUrl }}",
            "Best Quote": "={{ $json.bestQuote }}",
            "Key Topics": "={{ $json.keyTopics }}",
            "Content Gap": "={{ $json.contentGap }}",
            "Submitted By": "={{ $json.submittedBy }}",
            "Relevance Score": "={{ $json.relevanceScore }}",
            "Target Audience": "={{ $json.targetAudience }}"
          },
          "mappingMode": "defineBelow"
        },
        "options": {
          "cellFormat": "USER_ENTERED"
        },
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "={{ $json.sheetName }}"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $json.sheetId }}"
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "5e21fd30-2635-4af3-8df3-6691b250b9cb",
      "name": "18. IF \u2014 Last Video?",
      "type": "n8n-nodes-base.if",
      "position": [
        -2352,
        240
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "leftValue": "",
            "caseSensitive": false,
            "typeValidation": "loose"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "cond-last",
              "operator": {
                "type": "boolean",
                "operation": "true"
              },
              "leftValue": "={{ $('16. Code \u2014 Prepare Results').item.json.isLastVideo }}",
              "rightValue": true
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "512aecdc-ec17-4951-a331-822bc8c9872c",
      "name": "19. Code \u2014 Build Gmail Report",
      "type": "n8n-nodes-base.code",
      "position": [
        -2128,
        80
      ],
      "parameters": {
        "jsCode": "const lastItem = $('16. Code \u2014 Prepare Results').item.json;\n\nlet allItems = [];\ntry {\n  allItems = $('16. Code \u2014 Prepare Results').all().map(i => i.json);\n} catch (e) {\n  allItems = [lastItem];\n}\n\nconst today = lastItem.today;\nconst senderName = lastItem.senderName;\nconst recipientEmail = lastItem.recipientEmail;\n\nconst sorted = [...allItems].sort((a, b) => (b.rawScore || 0) - (a.rawScore || 0));\n\nlet body = 'Hello ' + senderName + ',\\n\\n';\nbody += 'Here is your YouTube Video Intelligence Report for ' + today + '.\\n\\n';\nbody += 'Total videos analyzed: ' + sorted.length + '\\n\\n';\nbody += '============================================================\\n\\n';\n\nsorted.forEach((v, i) => {\n  body +=\n    (i + 1) + '. ' + (v.title || 'Unknown') + '\\n' +\n    'Channel: ' + (v.channel || 'Unknown') + '\\n' +\n    'Views: ' + (v.views || 'Unknown') + ' | Duration: ' + (v.duration || 'Unknown') + ' | Published: ' + (v.publishedDate || 'Unknown') + '\\n' +\n    'URL: ' + (v.originalUrl || 'Unknown') + '\\n' +\n    'Relevance score: ' + (v.relevanceScore || 'Unknown') + '\\n\\n' +\n    'Summary:\\n' + (v.summary || 'Not available') + '\\n\\n' +\n    'Key topics: ' + (v.keyTopics || 'Not available') + '\\n\\n' +\n    'Best quote: ' + (v.bestQuote || 'Not available') + '\\n\\n' +\n    'Best for: ' + (v.targetAudience || 'Not available') + '\\n\\n' +\n    'Content gap to exploit: ' + (v.contentGap || 'Not available') + '\\n\\n' +\n    '------------------------------------------------------------\\n\\n';\n});\n\nbody += 'All video analyses are saved in your Google Sheets YouTube Intelligence tab.\\n\\n';\nbody += 'Best regards,\\n' + senderName;\n\nreturn [{\n  json: {\n    emailSubject: 'YouTube Video Intelligence Report \u2014 ' + sorted.length + ' videos \u2014 ' + today,\n    emailBody: body,\n    recipientEmail\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "347ca99f-8e53-4025-bb84-7ce59a2a8ba0",
      "name": "20. Gmail \u2014 Send Intelligence Report",
      "type": "n8n-nodes-base.gmail",
      "position": [
        -1920,
        80
      ],
      "parameters": {
        "sendTo": "={{ $json.recipientEmail }}",
        "message": "={{ $json.emailBody }}",
        "options": {
          "appendAttribution": false
        },
        "subject": "={{ $json.emailSubject }}"
      },
      "typeVersion": 2.1
    },
    {
      "id": "857f7752-a729-45e3-afbc-8498871a16b6",
      "name": "21. Set \u2014 More Videos",
      "type": "n8n-nodes-base.set",
      "position": [
        -2128,
        400
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "more-001",
              "name": "result",
              "type": "string",
              "value": "More videos still being processed \u2014 loop continues."
            }
          ]
        }
      },
      "typeVersion": 3.4
    }
  ],
  "connections": {
    "18. IF \u2014 Last Video?": {
      "main": [
        [
          {
            "node": "19. Code \u2014 Build Gmail Report",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "21. Set \u2014 More Videos",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "8. Wait \u2014 45 Seconds": {
      "main": [
        [
          {
            "node": "9. HTTP \u2014 Poll Transcript Results",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "2. Set \u2014 Config Values": {
      "main": [
        [
          {
            "node": "3. Code \u2014 Extract Video IDs",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "11. IF \u2014 Transcript Ready?": {
      "main": [
        [
          {
            "node": "13. AI Agent \u2014 Analyze Video",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "12. Set \u2014 Still Processing Loop Back",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "16. Code \u2014 Prepare Results": {
      "main": [
        [
          {
            "node": "17. Google Sheets \u2014 Log Video Analysis",
            "type": "main",
            "index": 0
          },
          {
            "node": "18. IF \u2014 Last Video?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "3. Code \u2014 Extract Video IDs": {
      "main": [
        [
          {
            "node": "4. HTTP \u2014 Fetch YouTube Metadata",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "13. AI Agent \u2014 Analyze Video": {
      "main": [
        [
          {
            "node": "16. Code \u2014 Prepare Results",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "19. Code \u2014 Build Gmail Report": {
      "main": [
        [
          {
            "node": "20. Gmail \u2014 Send Intelligence Report",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "14. OpenAI \u2014 GPT-4o-mini Model": {
      "ai_languageModel": [
        [
          {
            "node": "13. AI Agent \u2014 Analyze Video",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "4. HTTP \u2014 Fetch YouTube Metadata": {
      "main": [
        [
          {
            "node": "5. Code \u2014 Process Video Metadata",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "5. Code \u2014 Process Video Metadata": {
      "main": [
        [
          {
            "node": "6. HTTP \u2014 Submit Transcription Task",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "7. Code \u2014 Save Transcript Task ID": {
      "main": [
        [
          {
            "node": "8. Wait \u2014 45 Seconds",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "9. HTTP \u2014 Poll Transcript Results": {
      "main": [
        [
          {
            "node": "10. Code \u2014 Check Transcript Status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "10. Code \u2014 Check Transcript Status": {
      "main": [
        [
          {
            "node": "11. IF \u2014 Transcript Ready?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "6. HTTP \u2014 Submit Transcription Task": {
      "main": [
        [
          {
            "node": "7. Code \u2014 Save Transcript Task ID",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "1. Form \u2014 YouTube Video Intelligence": {
      "main": [
        [
          {
            "node": "2. Set \u2014 Config Values",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "12. Set \u2014 Still Processing Loop Back": {
      "main": [
        [
          {
            "node": "8. Wait \u2014 45 Seconds",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "15. Parser \u2014 Structured Video Analysis": {
      "ai_outputParser": [
        [
          {
            "node": "13. AI Agent \u2014 Analyze Video",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    }
  }
}
Pro

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

About this workflow

Submit up to 3 YouTube video URLs using a simple form and the workflow handles everything automatically. It fetches each video's title, channel, views, and duration from YouTube, submits each video to WayinVideo for accurate speaker-labeled transcription, then sends the…

Source: https://n8n.io/workflows/15183/ — 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

🧠 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

This workflow automates end-to-end contract and invoice management using AI intelligence. It processes proposals through intelligent contract generation, approval workflows, and automated invoicing. O

Form Trigger, Data Table, Agent +4
AI & RAG

This n8n workflow template automates your lead generation and follow-up process using AI. It captures leads through a form, enriches them with company data, classifies them into different categories,

Gmail, Output Parser Structured, Form Trigger +5
AI & RAG

Automates SaaS operations by consolidating user management, AI-driven support triage, analytics, and billing into one unified system. User signups flow through registration, support requests route via

Form Trigger, Data Table, Agent +7