AutomationFlowsAI & RAG › Youtube RAG Pipeline - Ingestion & Vectorization

Youtube RAG Pipeline - Ingestion & Vectorization

YouTube RAG Pipeline - Ingestion & Vectorization. Uses youTube, n8n-nodes-langchain. Event-driven trigger; 8 nodes.

Event trigger★★★★☆ complexityAI-powered8 nodesYouTubeN8N Nodes Langchain
AI & RAG Trigger: Event Nodes: 8 Complexity: ★★★★☆ AI nodes: yes Added:

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
{
  "name": "YouTube RAG Pipeline - Ingestion & Vectorization",
  "nodes": [
    {
      "parameters": {},
      "id": "trigger-manual",
      "name": "Manual Trigger",
      "type": "n8n-nodes-base.manualTrigger",
      "typeVersion": 1,
      "position": [
        0,
        300
      ]
    },
    {
      "parameters": {
        "videoId": "={{ $json.videoId }}"
      },
      "id": "get-metadata",
      "name": "Get Metadata",
      "type": "n8n-nodes-base.youTube",
      "typeVersion": 1,
      "position": [
        220,
        300
      ]
    },
    {
      "parameters": {
        "resource": "commentThread",
        "videoId": "={{ $json.id }}",
        "limit": 20
      },
      "id": "get-comments",
      "name": "Get Comments",
      "type": "n8n-nodes-base.youTube",
      "typeVersion": 1,
      "position": [
        440,
        300
      ]
    },
    {
      "parameters": {
        "jsCode": "const inputItem = $input.first().json;\nlet videoId = inputItem.id;\n\nif (!videoId) {\n  return [{ json: { error: \"No video ID found\" } }];\n}\n\nconst youtubePageUrl = `https://www.youtube.com/watch?v=${videoId}`;\n\ntry {\n  const response = await fetch(youtubePageUrl);\n  if (!response.ok) throw new Error(\"Failed to fetch page\");\n  const body = await response.text();\n\n  const playerResponseMatch = body.match(/ytInitialPlayerResponse = ({.*?});/);\n  if (!playerResponseMatch) throw new Error(\"No player response found\");\n\n  const ytInitialPlayerResponse = JSON.parse(playerResponseMatch[1]);\n  const captionTracks = ytInitialPlayerResponse?.captions?.playerCaptionsTracklistRenderer?.captionTracks;\n\n  if (!captionTracks || captionTracks.length === 0) {\n    return [{ json: { ...inputItem, transcript: \"[No Captions Available]\" } }];\n  }\n\n  const preferredTrack = captionTracks.find(track => track.languageCode === 'en') || captionTracks[0];\n  const transcriptResponse = await fetch(preferredTrack.baseUrl + '&fmt=json3');\n  const transcriptData = await transcriptResponse.json();\n\n  const transcript = transcriptData.events\n    .filter(event => event.segs)\n    .map(event => event.segs.map(seg => seg.utf8).join(' ')\n    .join(' ')\n    .replace(/[\\u200B-\\u200D\\uFEFF]/g, '')\n    .replace(/\\s+/g, ' ')\n    .trim();\n\n  return [{ json: { ...inputItem, transcript } }];\n\n} catch (error) {\n  return [{ json: { ...inputItem, transcript: \"[Error Fetching Transcript: \" + error.message + \"]\" } }];\n}"
      },
      "id": "fetch-transcript",
      "name": "Fetch Transcript (Code)",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        660,
        300
      ]
    },
    {
      "parameters": {
        "mode": "manual",
        "assignments": {
          "assignments": [
            {
              "id": "content",
              "name": "content",
              "value": "={{ $json.snippet.title }}\n\n{{ $json.snippet.description }}\n\nTRANSCRIPT:\n{{ $json.transcript }}\n\nCOMMENTS:\n{{ $json.comments }}",
              "type": "string"
            }
          ]
        }
      },
      "id": "format-document",
      "name": "Format Document",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        880,
        300
      ]
    },
    {
      "parameters": {
        "chunkSize": 1000,
        "chunkOverlap": 200
      },
      "id": "text-splitter",
      "name": "Text Splitter",
      "type": "n8n-nodes-langchain.textSplitterRecursiveCharacterTextSplitter",
      "typeVersion": 1,
      "position": [
        1100,
        200
      ]
    },
    {
      "parameters": {
        "model": "text-embedding-3-small"
      },
      "id": "embeddings",
      "name": "OpenAI Embeddings",
      "type": "n8n-nodes-langchain.embeddingsOpenAi",
      "typeVersion": 1,
      "position": [
        1100,
        400
      ]
    },
    {
      "parameters": {
        "mode": "insert",
        "collection": "youtube_knowledge_base",
        "options": {}
      },
      "id": "qdrant-store",
      "name": "Qdrant Vector Store",
      "type": "n8n-nodes-langchain.vectorStoreQdrant",
      "typeVersion": 1,
      "position": [
        1100,
        0
      ]
    }
  ],
  "connections": {
    "Manual Trigger": {
      "main": [
        [
          {
            "node": "Get Metadata",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Metadata": {
      "main": [
        [
          {
            "node": "Get Comments",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Comments": {
      "main": [
        [
          {
            "node": "Fetch Transcript (Code)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Transcript (Code)": {
      "main": [
        [
          {
            "node": "Format Document",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format Document": {
      "main": [
        [
          {
            "node": "Qdrant Vector Store",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Text Splitter": {
      "ai_textSplitter": [
        [
          {
            "node": "Qdrant Vector Store",
            "type": "ai_textSplitter",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Embeddings": {
      "ai_embedding": [
        [
          {
            "node": "Qdrant Vector Store",
            "type": "ai_embedding",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  }
}
Pro

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

About this workflow

YouTube RAG Pipeline - Ingestion & Vectorization. Uses youTube, n8n-nodes-langchain. Event-driven trigger; 8 nodes.

Source: https://github.com/wranngle/n8n_showcase/blob/main/workflows/knowledge_management/youtube-rag-pipeline/workflow.json — 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

YT Processing UPDATED. Uses googleSheets, youTube, httpRequest, googleDrive. Event-driven trigger; 44 nodes.

Google Sheets, YouTube, HTTP Request +11
AI & RAG

Api Schema Extractor. Uses manualTrigger, httpRequest, splitOut, textSplitterRecursiveCharacterTextSplitter. Event-driven trigger; 88 nodes.

HTTP Request, Text Splitter Recursive Character Text Splitter, Document Default Data Loader +9
AI & RAG

Wait Splitout. Uses manualTrigger, httpRequest, splitOut, textSplitterRecursiveCharacterTextSplitter. Event-driven trigger; 88 nodes.

HTTP Request, Text Splitter Recursive Character Text Splitter, Document Default Data Loader +9
AI & RAG

This workflow automates the process of discovering and extracting APIs from various services, followed by generating custom schemas. It works in three distinct stages: research, extraction, and schema

HTTP Request, Text Splitter Recursive Character Text Splitter, Document Default Data Loader +9
AI & RAG

Inquiry-Agent. Uses @digitalocean/n8n-nodes-digitalocean-gradient-serverless-inference, stopAndError, googleDocs, gmail. Event-driven trigger; 88 nodes.

@Digitalocean/N8N Nodes Digitalocean Gradient Serverless Inference, Stop And Error, Google Docs +12