AutomationFlowsSocial Media › Scheduled Youtube Transcription with De-duplication Using Transcript.io and…

Scheduled Youtube Transcription with De-duplication Using Transcript.io and…

Original n8n title: Scheduled Youtube Transcription with De-duplication Using Transcript.io and Supabase

Byautomedia @automate-social-media on n8n.io

This template is for advanced users, content teams, and data analysts who need a robust, automated system for capturing YouTube transcripts. It’s ideal for those who monitor multiple channels and want to ensure they only process and save each video's transcript once.

Cron / scheduled trigger★★★★★ complexity52 nodesSupabaseStop And ErrorRSS Feed ReadHTTP Request
Social Media Trigger: Cron / scheduled Nodes: 52 Complexity: ★★★★★ Added:

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

This workflow follows the HTTP Request → RSS Feed Read 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": "1e662a57-60c5-43eb-abd8-b2bc21172c49",
      "name": "Discard URL",
      "type": "n8n-nodes-base.code",
      "position": [
        4864,
        400
      ],
      "parameters": {
        "jsCode": "// Nothing leaves this node\nreturn [];\n"
      },
      "retryOnFail": true,
      "typeVersion": 2,
      "alwaysOutputData": true
    },
    {
      "id": "5c844f20-1172-4872-83fe-713390354a00",
      "name": "Check if URL Is In Database",
      "type": "n8n-nodes-base.supabase",
      "onError": "continueRegularOutput",
      "position": [
        4176,
        176
      ],
      "parameters": {
        "filters": {
          "conditions": [
            {
              "keyName": "source_url",
              "keyValue": "={{ $json.link }}",
              "condition": "eq"
            }
          ]
        },
        "tableId": "content_queue_1",
        "matchType": "allFilters",
        "operation": "getAll",
        "returnAll": true
      },
      "credentials": {
        "supabaseApi": {
          "name": "<your credential>"
        }
      },
      "retryOnFail": true,
      "typeVersion": 1,
      "alwaysOutputData": true
    },
    {
      "id": "f98d2813-0e5d-4a0c-a996-79d2c5af6f4e",
      "name": "Wait",
      "type": "n8n-nodes-base.wait",
      "position": [
        7744,
        -128
      ],
      "parameters": {
        "amount": 20
      },
      "typeVersion": 1.1
    },
    {
      "id": "9949e72c-d4c8-4bd9-b4b2-98b3e4d65bc6",
      "name": "Channel Info",
      "type": "n8n-nodes-base.set",
      "position": [
        1152,
        352
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "7f952495-fb69-43fd-a42e-518d631b7456",
              "name": "youtubeChannels",
              "type": "string",
              "value": "={{ $json.source_identifier }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "e31aaf93-90c7-4f8a-8e18-833713303936",
      "name": "Channel Info + Channel ID",
      "type": "n8n-nodes-base.set",
      "position": [
        1648,
        352
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "91bee9e2-9c54-4b87-920f-0221e6939c88",
              "name": "rssUrl",
              "type": "string",
              "value": "={{ $json.rssUrl }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "20f63f7f-f2a8-4d22-9649-0868dbd8fd05",
      "name": "Max Content Age Days",
      "type": "n8n-nodes-base.set",
      "position": [
        1920,
        160
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "425d78aa-c900-4156-98f9-4dcc812db7e6",
              "name": "max_content_age_days",
              "type": "string",
              "value": "={{ $json.max_content_age_days }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "2bc62093-e2e2-4e7e-baa2-2fda3a292ef5",
      "name": "Date & Time",
      "type": "n8n-nodes-base.dateTime",
      "position": [
        2736,
        -16
      ],
      "parameters": {
        "date": "={{ $json.pubDate || $json.isoDate }}",
        "format": "yyyy-MM-dd",
        "options": {},
        "operation": "formatDate",
        "outputFieldName": "standardizedPubDate"
      },
      "retryOnFail": true,
      "typeVersion": 2
    },
    {
      "id": "17518981-d6d1-4b0f-99e7-edf382ab3c7a",
      "name": "Add to Content Queue Table",
      "type": "n8n-nodes-base.supabase",
      "onError": "continueRegularOutput",
      "position": [
        7424,
        -656
      ],
      "parameters": {
        "tableId": "content_queue_1",
        "fieldsUi": {
          "fieldValues": [
            {
              "fieldId": "content_type",
              "fieldValue": "youtube"
            },
            {
              "fieldId": "title",
              "fieldValue": "={{ $json.title }}"
            },
            {
              "fieldId": "source_url",
              "fieldValue": "={{ $json.link }}"
            },
            {
              "fieldId": "content_snippet",
              "fieldValue": "={{ $json.transcript }}"
            },
            {
              "fieldId": "status",
              "fieldValue": "new"
            },
            {
              "fieldId": "published_date",
              "fieldValue": "={{ $json.pubDate }}"
            },
            {
              "fieldId": "creator",
              "fieldValue": "={{ $json.author }}"
            }
          ]
        }
      },
      "credentials": {
        "supabaseApi": {
          "name": "<your credential>"
        }
      },
      "retryOnFail": true,
      "typeVersion": 1,
      "alwaysOutputData": true
    },
    {
      "id": "b4a9862d-14ed-472a-a724-e5d293ab506e",
      "name": "Transcript Worked?",
      "type": "n8n-nodes-base.if",
      "position": [
        6720,
        -384
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "or",
          "conditions": [
            {
              "id": "fd22fed6-00aa-4d9a-94d5-58bb78f16bd1",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.statusMessage }}",
              "rightValue": "OK"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "adb806fd-b17d-43a2-87f7-0afd2e519a8c",
      "name": "New Video Information",
      "type": "n8n-nodes-base.set",
      "notes": "TEST CONTENT:\n[\n  {\n    \"client_id\": \"80d1c63b-59d6-479b-b7f7-ee91e859987e\",\n    \"max_content_age_days\": \"60\",\n    \"author\": \"Ted Talk\",\n    \"title\": \"Mental Toughness\",\n    \"link\": \"https://www.youtube.com/watch?v=rNxC16mlO60\",\n    \"pubDate\": \"2025-08-14T01:17:49.000Z\",\n    \"isMyContent\": null,\n    \"authority_score\": null,\n    \"niche_keywords\": null\n  }\n]\n",
      "position": [
        6080,
        -352
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "a87b5163-a235-4806-bb4a-d5795ac3634a",
              "name": "author",
              "type": "string",
              "value": "={{ $json.author }}"
            },
            {
              "id": "eb2aebb9-820b-43a8-81b7-e56d559ec8c4",
              "name": "title",
              "type": "string",
              "value": "={{ $json.title }}"
            },
            {
              "id": "6b2efe1f-c03a-4952-8599-7f9c6581699e",
              "name": "link",
              "type": "string",
              "value": "={{ $json.link }}"
            },
            {
              "id": "e31d8325-c92a-48f2-9741-024f4d4fe0fe",
              "name": "pubDate",
              "type": "string",
              "value": "={{ $json.pubDate }}"
            }
          ]
        },
        "includeOtherFields": true
      },
      "typeVersion": 3.4
    },
    {
      "id": "5dd2dd09-69ee-4b33-8a37-159b3b144e20",
      "name": "Verify Channel ID + Create RSS Link",
      "type": "n8n-nodes-base.code",
      "position": [
        1376,
        352
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "// \u2500\u2500 Pull the fields we need from the incoming item \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nconst channelId       = $json[\"youtubeChannels\"];\nconst authorityScore  = $json[\"authority_score\"];\nconst nicheKeywords   = $json[\"niche_keywords\"];\n\nconsole.log(\n  `Channel: ${channelId}, authority: ${authorityScore}, ` +\n  `keywords: ${nicheKeywords?.length || 0}`\n);\n\n// \u2500\u2500 Skip if the channel ID is missing or blank \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nif (!channelId || channelId.trim() === '') {\n  return null;\n}\n\n// \u2500\u2500 Only keep well-formed YouTube channel IDs (start with \u201cUC\u201d, 24 chars) \u2500\u2500\u2500\u2500\u2500\nif (channelId.startsWith('UC') && channelId.length === 24) {\n  return {\n    channelId,\n    rssUrl: `https://www.youtube.com/feeds/videos.xml?channel_id=${channelId}`,\n    authority_score: authorityScore,\n    niche_keywords: nicheKeywords,\n    success: true\n  };\n} else {\n  console.log(`\u274c Invalid Channel ID format: ${channelId}`);\n  return null;  // Skip invalid IDs\n}"
      },
      "retryOnFail": true,
      "typeVersion": 2,
      "alwaysOutputData": true
    },
    {
      "id": "306120f4-df29-4caa-bf83-79cbb41195e4",
      "name": "try to get video_id again",
      "type": "n8n-nodes-base.code",
      "position": [
        6048,
        -608
      ],
      "parameters": {
        "jsCode": "// YouTube Video ID Extractor - returns `video_id`\nfunction extractYouTubeVideoId(url) {\n  if (!url || typeof url !== 'string') {\n    return null;\n  }\n  const regex = /(?:youtube\\.com\\/(?:[^\\/\\n\\s]+\\/\\S+\\/|(?:v|e(?:mbed)?|shorts)\\/|.*[?&]v=)|youtu\\.be\\/)([a-zA-Z0-9_-]{11})/i;\n  const match = url.match(regex);\n  return match && match[1] ? match[1] : null;\n}\n\nconst input = $input.all();\nconst results = [];\n\nfor (const item of input) {\n  const url =\n    item.json.url ||\n    item.json.video_url ||\n    item.json.youtube_url ||\n    (typeof item.json === 'string' ? item.json : '');\n  const id = extractYouTubeVideoId(url);\n  results.push({\n    original_url: url,\n    video_id: id,\n    is_valid: id !== null,\n    clean_url: id ? `https://www.youtube.com/watch?v=${id}` : null,\n  });\n}\n\nreturn results;\n"
      },
      "typeVersion": 2
    },
    {
      "id": "da478902-afbc-4d5a-8597-0330f88215b1",
      "name": "Loop Over Each Channel",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        1920,
        352
      ],
      "parameters": {
        "options": {}
      },
      "retryOnFail": true,
      "typeVersion": 3,
      "waitBetweenTries": 3000
    },
    {
      "id": "b29bffc1-bf77-4de1-986d-30a731f115d0",
      "name": "Loop Over Recent Videos",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        3696,
        304
      ],
      "parameters": {
        "options": {}
      },
      "retryOnFail": true,
      "typeVersion": 3
    },
    {
      "id": "12a20fa2-5191-474d-ab53-dfcd2da2fb27",
      "name": "Loop Over New Videos",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        4192,
        -352
      ],
      "parameters": {
        "options": {}
      },
      "retryOnFail": true,
      "typeVersion": 3
    },
    {
      "id": "67401f48-da32-4606-8306-9a50eb2c75f8",
      "name": "Is Video Recent Enough?",
      "type": "n8n-nodes-base.if",
      "position": [
        3136,
        160
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "e3ff753e-f5f0-4d69-ace1-d0b9415fb294",
              "operator": {
                "type": "dateTime",
                "operation": "afterOrEquals"
              },
              "leftValue": "={{ $('Date & Time').item.json.standardizedPubDate }}",
              "rightValue": "={{ DateTime.now().minus({ days: $json.max_content_age_days }).toFormat('yyyy-MM-dd') }}"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "13763184-58b4-4173-baee-2fd8a24ceb1a",
      "name": "Was Video ID Found?",
      "type": "n8n-nodes-base.if",
      "position": [
        5664,
        -672
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "ddb872f1-00b7-45e4-9d9c-02fbcacc8173",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              },
              "leftValue": "={{ $json.is_valid }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "4fbc9742-cc2b-453a-a44f-f0fece8a1cbb",
      "name": "Merge DB Check Result",
      "type": "n8n-nodes-base.merge",
      "position": [
        4384,
        304
      ],
      "parameters": {
        "mode": "combine",
        "options": {},
        "combineBy": "combineByPosition"
      },
      "typeVersion": 3.2
    },
    {
      "id": "4b68db0f-e6c6-4ce7-af7e-1045b6cbe7d6",
      "name": "Add Client & Age Rules",
      "type": "n8n-nodes-base.merge",
      "position": [
        2320,
        176
      ],
      "parameters": {
        "mode": "combine",
        "options": {},
        "combineBy": "combineAll"
      },
      "typeVersion": 3.2
    },
    {
      "id": "7a9e60b1-12ab-4d4a-8a56-59fca5a03925",
      "name": "Data with Raw Date",
      "type": "n8n-nodes-base.set",
      "position": [
        2544,
        176
      ],
      "parameters": {
        "options": {},
        "includeOtherFields": true
      },
      "typeVersion": 3.4
    },
    {
      "id": "dd7a8e83-9e37-43c7-b003-182b8960c0fc",
      "name": "Merge Formatted Date",
      "type": "n8n-nodes-base.merge",
      "position": [
        2912,
        160
      ],
      "parameters": {
        "mode": "combine",
        "options": {},
        "combineBy": "combineByPosition"
      },
      "typeVersion": 3.2
    },
    {
      "id": "1d2e79d2-e3e4-4ecf-b408-17bbf6876367",
      "name": "Add Transcript to Video Data",
      "type": "n8n-nodes-base.merge",
      "position": [
        7104,
        -656
      ],
      "parameters": {
        "mode": "combine",
        "options": {},
        "combineBy": "combineByPosition"
      },
      "typeVersion": 3.2
    },
    {
      "id": "d95c20a3-faa0-45df-becf-4605674f295b",
      "name": "Transcript Failed",
      "type": "n8n-nodes-base.stopAndError",
      "position": [
        7056,
        -112
      ],
      "parameters": {
        "errorMessage": "Transcript Failed"
      },
      "typeVersion": 1
    },
    {
      "id": "cdfff4fa-6dcc-4c90-b213-322376c71126",
      "name": "Merge Video ID With Video Data",
      "type": "n8n-nodes-base.merge",
      "position": [
        6272,
        -672
      ],
      "parameters": {
        "mode": "combine",
        "options": {},
        "combineBy": "combineByPosition"
      },
      "typeVersion": 3.2
    },
    {
      "id": "fd0d633f-6640-43bb-bda4-6bfeb52f8f68",
      "name": "Rename URL",
      "type": "n8n-nodes-base.set",
      "position": [
        5824,
        -608
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "6e3e0929-a6d9-44a8-85f8-aab2a863b15b",
              "name": "url",
              "type": "string",
              "value": "={{ $json.original_url }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "deeb3d63-dfb9-4c25-9760-d21f9a8b98a5",
      "name": "Rename Original URL",
      "type": "n8n-nodes-base.set",
      "position": [
        4768,
        -672
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "78fb6dce-dd95-4d98-9df6-436a1491683a",
              "name": "original_url",
              "type": "string",
              "value": "={{ $json.link }}"
            }
          ]
        },
        "includeOtherFields": true
      },
      "typeVersion": 3.4
    },
    {
      "id": "c3777b03-1d5c-4f6b-a006-9ecf2c83bc7f",
      "name": "Find Video ID",
      "type": "n8n-nodes-base.set",
      "position": [
        4992,
        -672
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "f5928422-6fb1-44d8-9c7e-4e3c3fc643ae",
              "name": "video_id",
              "type": "string",
              "value": "={{ $json.original_url.match(/(?:youtube\\.com\\/(?:[^\\/\\n\\s]+\\/\\S+\\/|(?:v|e(?:mbed)?|shorts)\\/|.*[?&]v=)|youtu\\.be\\/)([a-zA-Z0-9_-]{11})/i)?.[1] || null }}"
            }
          ]
        },
        "includeOtherFields": true
      },
      "typeVersion": 3.4
    },
    {
      "id": "16f57225-471d-4ce0-a120-8adc42a33a6e",
      "name": "Is Video ID valid?",
      "type": "n8n-nodes-base.set",
      "position": [
        5216,
        -672
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "b0a840da-4cef-4a4c-bfd2-14e0afa06f5d",
              "name": "is_valid",
              "type": "boolean",
              "value": "={{ $json.original_url.match(/(?:youtube\\.com\\/(?:[^\\/\\n\\s]+\\/\\S+\\/|(?:v|e(?:mbed)?|shorts)\\/|.*[?&]v=)|youtu\\.be\\/)([a-zA-Z0-9_-]{11})/i) !== null }}"
            }
          ]
        },
        "includeOtherFields": true
      },
      "typeVersion": 3.4
    },
    {
      "id": "9e6301d9-1c69-4fda-bcf6-ab21203486ca",
      "name": "Clean Up URL",
      "type": "n8n-nodes-base.set",
      "position": [
        5440,
        -672
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "3add2b91-4a26-4a33-b982-bd90a3bf2790",
              "name": "clean_url",
              "type": "string",
              "value": "={{ $json.video_id ? `https://www.youtube.com/watch?v=${$json.video_id}` : null }}"
            }
          ]
        },
        "includeOtherFields": true
      },
      "typeVersion": 3.4
    },
    {
      "id": "f0e30110-f0fc-42bd-a14b-ccd0e958d49c",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -912,
        -320
      ],
      "parameters": {
        "width": 736,
        "height": 576,
        "content": "## **Advanced YouTube Transcriptor**\n\nWelcome! This workflow runs on a schedule to find new YouTube videos, checks your database to prevent duplicates, transcribes them, and saves the data.\n\n### **\ud83d\ude80 4-Step Setup**\n\n1.  **Set Max Video Age:** In the **\"Max Days\"** node, define how many days back you want to search for new videos.\n2.  **Add Channel IDs:** Update the list of YouTube Channel IDs in the **\"Channels To Track\"** node.\n3.  **Add API Key:** Select the **\"Get Transcript from API\"** node and add your `youtube-transcript.io` API key in the credentials.\n4.  **Connect Supabase (IMPORTANT):** You must add your Supabase credentials to **TWO** nodes:\n    * `Check if URL Is In Database`\n    * `Add to Content Queue Table`\n\n### **\u2728 Customization**\n\n* **Change Schedule:** Click the **\"Schedule Trigger\"** node to change how often the workflow runs.\n* **Transcribe Shorts:** In the **\"Filter Out Youtube Shorts\"** node, delete the second condition to allow YouTube Shorts to be transcribed.\n\nActivate the workflow and you're all set!"
      },
      "typeVersion": 1
    },
    {
      "id": "b4a594d0-7e22-4dfa-97c2-1fac51fd3fce",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        384,
        -320
      ],
      "parameters": {
        "color": 3,
        "width": 3008,
        "height": 976,
        "content": "## **Part 1: Get Recent Videos**\n\nThis section fetches the list of specified YouTube channels from our database. It then loops through each channel, constructs an RSS feed URL, and pulls the list of the most recent videos. Finally, it filters out any videos published before our `max_content_age_days` limit."
      },
      "typeVersion": 1
    },
    {
      "id": "800fd1ef-d675-4f4f-a11a-a607cf5366ee",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3408,
        64
      ],
      "parameters": {
        "color": 4,
        "width": 1632,
        "height": 592,
        "content": "## **Part 2: Filter for New Content Only**\n\nHere, we loop through the videos in our database. We check against our `content_queue_1` table in Supabase to see if we've already processed this video's URL. We only keep videos that are not already in our database."
      },
      "typeVersion": 1
    },
    {
      "id": "8555920f-ea81-4c70-911a-a54c8e5c624c",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        4112,
        -816
      ],
      "parameters": {
        "color": 5,
        "width": 3152,
        "height": 848,
        "content": "## **Part 3: Video Transcription**\n\nThis section extracts a clean YouTube Video ID from the link, then sends it to the `youtube-transcript.io` API. If the API call is successful, the JSON response is parsed to get a clean text transcript. If it fails, the workflow stops for that item."
      },
      "typeVersion": 1
    },
    {
      "id": "9e423d16-0852-445d-81da-d9e5df423335",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        7312,
        -768
      ],
      "parameters": {
        "width": 320,
        "height": 336,
        "content": "## **Part 4: Save to Database**"
      },
      "typeVersion": 1
    },
    {
      "id": "d433fa8a-61ee-4525-9035-b75feb433fab",
      "name": "Find Channel's Videos",
      "type": "n8n-nodes-base.rssFeedRead",
      "position": [
        2160,
        448
      ],
      "parameters": {
        "url": "={{ $json.rssUrl }}",
        "options": {}
      },
      "retryOnFail": true,
      "typeVersion": 1.1
    },
    {
      "id": "b6c973cd-73b7-4dac-b9ab-27adc27c2e6e",
      "name": "Channels To Track",
      "type": "n8n-nodes-base.set",
      "position": [
        624,
        352
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "71df3a21-e1b2-4906-b0ef-dd0d93f6cca5",
              "name": "source_identifier",
              "type": "array",
              "value": "={{ ['UCaEkuhQejDMyindRnUbISIg', 'UCIPPMRA040LQr5QPyJEbmXA'] }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "795fbe12-6a67-4059-a62c-5009c4b839f7",
      "name": "Split Out",
      "type": "n8n-nodes-base.splitOut",
      "position": [
        896,
        352
      ],
      "parameters": {
        "options": {},
        "fieldToSplitOut": "source_identifier"
      },
      "typeVersion": 1
    },
    {
      "id": "91372563-4b4e-4a46-90ff-89e1eb261840",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        816,
        80
      ],
      "parameters": {
        "color": 4,
        "width": 256,
        "height": 448,
        "content": "## Splits all of the websites into their own items so that they go into the loop one at a time\n"
      },
      "typeVersion": 1
    },
    {
      "id": "41cb7972-1246-4741-929b-f7fd6085f247",
      "name": "Sticky Note7",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        544,
        80
      ],
      "parameters": {
        "color": 5,
        "width": 256,
        "height": 448,
        "content": "## Stores the Channel IDs of the youtube channels you are tracking\n\nFind channel IDs for free by using a website such as https://www.tunepocket.com/youtube-channel-id-finder"
      },
      "typeVersion": 1
    },
    {
      "id": "befb4428-08b8-448f-a7ad-58c2d98b5967",
      "name": "Sticky Note8",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        112,
        -320
      ],
      "parameters": {
        "color": 4,
        "width": 256,
        "height": 576,
        "content": "## Filter out Youtube Videos posted X days ago.\n\nDefault = 60 days.\n\nFor example, if you only want videos posted within the past 7 days, change this number to 7"
      },
      "typeVersion": 1
    },
    {
      "id": "a5531b89-dce9-4098-b60b-04c66a9d97c3",
      "name": "Sticky Note9",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -160,
        -320
      ],
      "parameters": {
        "color": 5,
        "width": 256,
        "height": 576,
        "content": "## How often do you want this to run?\n\n**PRO TIP**: Replace this with a schedule node!"
      },
      "typeVersion": 1
    },
    {
      "id": "b1f269e8-e04d-4d51-8bfe-ccffb0677e3b",
      "name": "Sticky Note10",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1296,
        240
      ],
      "parameters": {
        "color": 6,
        "width": 256,
        "height": 288,
        "content": "## Convert to a valid RSS feed link"
      },
      "typeVersion": 1
    },
    {
      "id": "d231bab6-52d0-43a3-a6e2-1dec577d5950",
      "name": "Sticky Note11",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2480,
        -64
      ],
      "parameters": {
        "color": 5,
        "width": 880,
        "height": 448,
        "content": "## Filter out videos older than your preferred number of days.\nDefault = 60 days\n"
      },
      "typeVersion": 1
    },
    {
      "id": "bd78965a-b40a-4d7a-9220-df4850f6adda",
      "name": "Official Captions/Transcript",
      "type": "n8n-nodes-base.code",
      "position": [
        6944,
        -400
      ],
      "parameters": {
        "jsCode": "const trackToText = (track) => track.transcript.map(t => t.text).join(' ');\n\nconst results = [];\n\nfor (const cur of $input.all()) {\n  // Parse data field if it\u2019s a string\n  let dataArray;\n  if (typeof cur.json.data === 'string') {\n    try {\n      dataArray = JSON.parse(cur.json.data);\n    } catch {\n      continue;\n    }\n  } else {\n    dataArray = cur.json.data;\n  }\n\n  const item = Array.isArray(dataArray) ? dataArray[0] : null;\n  if (!item || !item.tracks?.[0]) continue;\n\n  results.push({\n    json: {\n      id: item.id,\n      transcript: trackToText(item.tracks[0])\n    }\n  });\n}\n\nreturn results;\n"
      },
      "typeVersion": 2
    },
    {
      "id": "bc132ab8-2b68-459e-b799-38b1461946f4",
      "name": "author + title + link + pubDate",
      "type": "n8n-nodes-base.set",
      "position": [
        3936,
        320
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "6a9e1676-958b-459f-9759-8923abf17ca9",
              "name": "author",
              "type": "string",
              "value": "={{ $json.author }}"
            },
            {
              "id": "1e46ca11-f2fd-4791-8f99-d6a29cf788ef",
              "name": "title",
              "type": "string",
              "value": "={{ $json.title }}"
            },
            {
              "id": "26062740-7a51-46ef-8b59-1a21794dea12",
              "name": "link",
              "type": "string",
              "value": "={{ $json.link }}"
            },
            {
              "id": "8f7d651d-e422-4145-ae56-cdd596e199b9",
              "name": "pubDate",
              "type": "string",
              "value": "={{ $json.pubDate }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "5e4b3e4c-4019-4da8-a31b-148010961c2f",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        4448,
        -400
      ],
      "parameters": {
        "width": 688,
        "height": 432,
        "content": "## Filter Out Youtube Shorts?\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n**Default = Will NOT extract transcript from Youtube Shorts.\n\nIf you want the transcripts from Youtube Shorts as well. Delete the second filter on this node.**"
      },
      "typeVersion": 1
    },
    {
      "id": "5972dd56-a725-4d74-a5bd-b425da95e831",
      "name": "Schedule Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -80,
        -64
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "triggerAtHour": 1
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "5985ba47-bd1e-4450-8ac8-56eaeb7ce8ad",
      "name": "Sticky Note13",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        6352,
        -480
      ],
      "parameters": {
        "width": 336,
        "height": 464,
        "content": "## Free Youtube Transcripts\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n### This website allows for 25 free Youtube transcripts per month.\n\nGet your api key here:\nhttps://www.youtube-transcript.io/\n\n### Only works on videos with CAPTIONS"
      },
      "typeVersion": 1
    },
    {
      "id": "15dd6258-de11-4bce-a5e4-f10896ab965d",
      "name": "Get Transcript from API",
      "type": "n8n-nodes-base.httpRequest",
      "notes": "Failures:\n\n[\n  {\n    \"body\": {\n      \"error\": {\n        \"code\": 503,\n        \"message\": \"The model is overloaded. Please try again later.\",\n        \"status\": \"UNAVAILABLE\"\n      }\n    },\n    \"headers\": {\n      \"vary\": \"Origin, X-Origin, Referer\",\n      \"content-type\": \"application/json; charset=UTF-8\",\n      \"date\": \"Wed, 13 Aug 2025 18:07:09 GMT\",\n      \"server\": \"scaffolding on HTTPServer2\",\n      \"x-xss-protection\": \"0\",\n      \"x-frame-options\": \"SAMEORIGIN\",\n      \"x-content-type-options\": \"nosniff\",\n      \"server-timing\": \"gfet4t7; dur=19896\",\n      \"alt-svc\": \"h3=\\\":443\\\"; ma=2592000,h3-29=\\\":443\\\"; ma=2592000\",\n      \"connection\": \"close\",\n      \"transfer-encoding\": \"chunked\"\n    },\n    \"statusCode\": 503,\n    \"statusMessage\": \"Service Unavailable\"\n  }\n]",
      "position": [
        6480,
        -384
      ],
      "parameters": {
        "url": "https://www.youtube-transcript.io/api/transcripts",
        "method": "POST",
        "options": {
          "response": {
            "response": {
              "neverError": true,
              "fullResponse": true,
              "responseFormat": "text"
            }
          }
        },
        "jsonBody": "={\n  \"ids\": [\n    \"{{$json.video_id}}\"\n  ]\n}",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        }
      },
      "credentials": {
        "httpQueryAuth": {
          "name": "<your credential>"
        },
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "retryOnFail": true,
      "typeVersion": 4.2,
      "waitBetweenTries": 5000
    },
    {
      "id": "4de16b7e-bd72-4b0d-ab0b-27f8128e1d7d",
      "name": "Set Max Video Age",
      "type": "n8n-nodes-base.set",
      "position": [
        176,
        -64
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "71683423-567a-428e-8bf5-e2a7b36ddf77",
              "name": "max_content_age_days",
              "type": "string",
              "value": "=60"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "0fd75803-0c94-4fb5-bdfb-10be427e4725",
      "name": "Is Video Already in Database?",
      "type": "n8n-nodes-base.if",
      "onError": "continueRegularOutput",
      "position": [
        4608,
        304
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "loose"
          },
          "combinator": "or",
          "conditions": [
            {
              "id": "0e8f8e26-63ae-4273-8ccf-4e6cbb47669d",
              "operator": {
                "type": "string",
                "operation": "exists",
                "singleValue": true
              },
              "leftValue": "={{ $json.source_url }}",
              "rightValue": 0
            }
          ]
        },
        "looseTypeValidation": true
      },
      "typeVersion": 2.2,
      "alwaysOutputData": false
    },
    {
      "id": "68f066dc-0fe0-4df5-9b56-dfda7d69229a",
      "name": "Filter Out YouTube Shorts",
      "type": "n8n-nodes-base.if",
      "position": [
        4592,
        -336
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "af405725-90d8-4c1a-8497-0a92e273ced7",
              "operator": {
                "type": "string",
                "operation": "exists",
                "singleValue": true
              },
              "leftValue": "={{$json.link}}",
              "rightValue": ""
            },
            {
              "id": "2c3a30eb-489f-4ce9-bdf2-9f63c683456e",
              "operator": {
                "type": "string",
                "operation": "notContains"
              },
              "leftValue": "={{ $json.link }}",
              "rightValue": "youtube.com/shorts"
            }
          ]
        }
      },
      "typeVersion": 2.2
    }
  ],
  "connections": {
    "Wait": {
      "main": [
        [
          {
            "node": "Loop Over New Videos",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split Out": {
      "main": [
        [
          {
            "node": "Channel Info",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Rename URL": {
      "main": [
        [
          {
            "node": "try to get video_id again",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Date & Time": {
      "main": [
        [
          {
            "node": "Merge Formatted Date",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Discard URL": {
      "main": [
        [
          {
            "node": "Loop Over Recent Videos",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Channel Info": {
      "main": [
        [
          {
            "node": "Verify Channel ID + Create RSS Link",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Clean Up URL": {
      "main": [
        [
          {
            "node": "Was Video ID Found?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Find Video ID": {
      "main": [
        [
          {
            "node": "Is Video ID valid?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Schedule Trigger": {
      "main": [
        [
          {
            "node": "Set Max Video Age",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Channels To Track": {
      "main": [
        [
          {
            "node": "Split Out",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set Max Video Age": {
      "main": [
        [
          {
            "node": "Channels To Track",
            "type": "main",
            "index": 0
          },
          {
            "node": "Max Content Age Days",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Data with Raw Date": {
      "main": [
        [
          {
            "node": "Date & Time",
            "type": "main",
            "index": 0
          },
          {
            "node": "Merge Formatted Date",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Is Video ID valid?": {
      "main": [
        [
          {
            "node": "Clean Up URL",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Transcript Worked?": {
      "main": [
        [
          {
            "node": "Official Captions/Transcript",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Transcript Failed",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Rename Original URL": {
      "main": [
        [
          {
            "node": "Find Video ID",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Was Video ID Found?": {
      "main": [
        [
          {
            "node": "Merge Video ID With Video Data",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Rename URL",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Loop Over New Videos": {
      "main": [
        [],
        [
          {
            "node": "Filter Out YouTube Shorts",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Max Content Age Days": {
      "main": [
        [
          {
            "node": "Add Client & Age Rules",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge Formatted Date": {
      "main": [
        [
          {
            "node": "Is Video Recent Enough?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Find Channel's Videos": {
      "main": [
        [
          {
            "node": "Loop Over Each Channel",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge DB Check Result": {
      "main": [
        [
          {
            "node": "Is Video Already in Database?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "New Video Information": {
      "main": [
        [
          {
            "node": "Merge Video ID With Video Data",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Add Client & Age Rules": {
      "main": [
        [
          {
            "node": "Data with Raw Date",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Loop Over Each Channel": {
      "main": [
        [
          {
            "node": "Add Client & Age Rules",
            "type": "main",
            "index": 1
          }
        ],
        [
          {
            "node": "Find Channel's Videos",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Transcript from API": {
      "main": [
        [
          {
            "node": "Transcript Worked?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Is Video Recent Enough?": {
      "main": [
        [
          {
            "node": "Loop Over Recent Videos",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Loop Over Recent Videos": {
      "main": [
        [
          {
            "node": "Loop Over New Videos",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "author + title + link + pubDate",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Channel Info + Channel ID": {
      "main": [
        [
          {
            "node": "Loop Over Each Channel",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter Out YouTube Shorts": {
      "main": [
        [
          {
            "node": "Rename Original URL",
            "type": "main",
            "index": 0
          },
          {
            "node": "New Video Information",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Loop Over New Videos",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "try to get video_id again": {
      "main": [
        [
          {
            "node": "Merge Video ID With Video Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Add to Content Queue Table": {
      "main": [
        [
          {
            "node": "Wait",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check if URL Is In Database": {
      "main": [
        [
          {
            "node": "Merge DB Check Result",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Add Transcript to Video Data": {
      "main": [
        [
          {
            "node": "Add to Content Queue Table",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Official Captions/Transcript": {
      "main": [
        [
          {
            "node": "Add Transcript to Video Data",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Is Video Already in Database?": {
      "main": [
        [
          {
            "node": "Discard URL",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Loop Over Recent Videos",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge Video ID With Video Data": {
      "main": [
        [
          {
            "node": "Get Transcript from API",
            "type": "main",
            "index": 0
          },
          {
            "node": "Add Transcript to Video Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "author + title + link + pubDate": {
      "main": [
        [
          {
            "node": "Check if URL Is In Database",
            "type": "main",
            "index": 0
          },
          {
            "node": "Merge DB Check Result",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Verify Channel ID + Create RSS Link": {
      "main": [
        [
          {
            "node": "Channel Info + Channel ID",
            "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

This template is for advanced users, content teams, and data analysts who need a robust, automated system for capturing YouTube transcripts. It’s ideal for those who monitor multiple channels and want to ensure they only process and save each video's transcript once.

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

More Social Media workflows → · Browse all categories →

Related workflows

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

Social Media

This workflow is for content creators, marketers, researchers, and anyone who needs to quickly get text transcripts from YouTube videos. If you analyze video content, repurpose it for blogs or social

Stop And Error, RSS Feed Read, HTTP Request +1
Social Media

You are in the bad habit of always checking your feed to see if there are new videos? This workflow will help you get rid of this habit by delivering an email notification for each new video posted fr

YouTube, RSS Feed Read, HTTP Request +2
Social Media

This workflow demonstrates how to combine trend harvesting, channel intelligence, and AI scoring to select the best daily content ideas for short-form videos (YouTube Shorts / TikTok).

YouTube, OpenRouter Chat, RSS Feed Read +4
Social Media

This workflow contains community nodes that are only compatible with the self-hosted version of n8n.

HTTP Request, Google Sheets, RSS Feed Read +3
Social Media

Automatically track your favorite YouTube creators and get a daily summary of new videos delivered to Discord.

RSS Feed Read, Discord