This workflow corresponds to n8n.io template #10719 — we link there as the canonical source.
This workflow follows the Agent → Airtable 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 →
{
"meta": {
"templateCredsSetupCompleted": true
},
"nodes": [
{
"id": "a4bb454b-5d7e-49c5-8af3-bf71b1a4aa61",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-48,
-384
],
"parameters": {
"width": 2800,
"height": 224,
"content": "### Requirements\n- YouTube Data API (OAuth2)\n- SupaData API Key\n- Airtable Token (if using base for deduplication)\n- RSS Feed from your YouTube Channel"
},
"typeVersion": 1
},
{
"id": "979d6059-d909-4baf-a49a-1130fd58ad0a",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-48,
-1280
],
"parameters": {
"color": 3,
"width": 2800,
"height": 880,
"content": "## YouTube Chapter Auto-Comment (RSS to YouTube)\n\nAutomatically posts chapter timestamps as a comment on your latest YouTube video \u2014 using your RSS feed and SupaData transcript API.\n\n---\n\n### Who it's for \nCreators who want every video to have structured chapters \u2014 without writing them manually.\n\n---\n\n### What it does \n- Watches your YouTube RSS feed \n- Gets the latest video ID \n- Skips videos already posted (Airtable check) \n- Fetches transcript via SupaData \n- Uses OpenAI to generate chapter timestamps \n- Posts the chapters as a YouTube comment\n\n---\n\n### Requirements \n- SupaData API key \n- OpenAI API key \n- YouTube OAuth2 credentials \n- Airtable (optional)\n\n---\n\n### Limitation \nYouTube API **does not allow pinning comments** \u2014 the comment will be posted, but not pinned.\n\n---\n\n### Airtable Template \n\ud83d\udd17 [Duplicate this base](https://airtable.com/appUJQfAXniGZzwL8/shraiQrFHLF3xxhX7) to track posted videos"
},
"typeVersion": 1
},
{
"id": "a9818346-9cb1-497a-8063-e7131bbc331f",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
-48,
-144
],
"parameters": {
"height": 736,
"content": "This node triggers when your YouTube channel publishes a new video via its RSS feed.\n\nYou can get your RSS feed from:\nhttps://www.youtube.com/feeds/videos.xml?channel_id=YOUR_CHANNEL_ID\n\nRuns on a daily schedule (e.g., every 4am)."
},
"typeVersion": 1
},
{
"id": "6079238b-6ebd-4a49-979d-7b8f18fa4655",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
224,
-144
],
"parameters": {
"color": 5,
"width": 608,
"height": 736,
"content": "Before continuing, this workflow checks if the video ID already exists in Airtable.\n\nThis prevents double-posting chapters on the same video.\n\n- If found \u2192 workflow stops\n- If not found \u2192 workflow continues and adds the video ID to Airtable"
},
"typeVersion": 1
},
{
"id": "aef3d533-2a32-46da-ba74-c77cbc649d8a",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
864,
-144
],
"parameters": {
"color": 6,
"width": 608,
"height": 736,
"content": "This node sends the video to SupaData's transcript API.\n\nURL format:\nhttps://api.supadata.ai/v1/transcript?url=https://youtu.be/{{ videoId }}\n\nSupaData returns a structured response with timestamps and chapters.\n\nYou must use a valid API key (set in HTTP credentials)."
},
"typeVersion": 1
},
{
"id": "8483c76d-d48c-4e93-aae5-99a41818bf1a",
"name": "Sticky Note5",
"type": "n8n-nodes-base.stickyNote",
"position": [
2144,
-144
],
"parameters": {
"color": 2,
"width": 608,
"height": 736,
"content": "### Add Chapters to YouTube Description\n\nThis section updates the description of your latest YouTube video.\n\n---\n\n#### Step 1: Fetch Original Description\n\n- Uses the YouTube API to get the current video description.\n- Retrieves the title, existing text, and metadata.\n\n---\n\n#### Step 2: Append Chapters to the Description\n\n- AI-generated chapter timestamps are appended at the bottom of the existing description.\n- The update is submitted back to YouTube using the update video API.\n\n---\n\nNote: No comment is posted. This step only updates the video description with chapter markers."
},
"typeVersion": 1
},
{
"id": "7a8294fb-1178-43ae-a528-d2c29207cbce",
"name": "OpenAI Chat Model",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"position": [
1648,
400
],
"parameters": {
"model": {
"__rl": true,
"mode": "list",
"value": "gpt-4o",
"cachedResultName": "gpt-4o"
},
"options": {}
},
"credentials": {
"openAiApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.2
},
{
"id": "9d71c11f-a240-4bab-8781-2d1e77327528",
"name": "Sticky Note7",
"type": "n8n-nodes-base.stickyNote",
"position": [
1504,
-144
],
"parameters": {
"color": 7,
"width": 608,
"height": 736,
"content": "This step uses OpenAI to automatically generate YouTube-style chapter timestamps based on the full video transcript.\n\nWhat it does:\n\t\u2022\tReads the transcript from the SupaData API\n\t\u2022\tSends it to GPT-4 or GPT-3.5 via OpenAI\n\t\u2022\tReturns timestamped chapters like:"
},
"typeVersion": 1
},
{
"id": "34cb277e-b7fd-4952-a4cf-f32fabe1b242",
"name": "Get New YouTube Video",
"type": "n8n-nodes-base.rssFeedReadTrigger",
"position": [
0,
128
],
"parameters": {
"feedUrl": "https://www.youtube.com/feeds/videos.xml?channel_id=UCDILbVG2rHR_BwfUAqrtuug&nocache=1",
"pollTimes": {
"item": [
{
"mode": "everyMinute"
}
]
}
},
"executeOnce": false,
"notesInFlow": false,
"typeVersion": 1,
"alwaysOutputData": false
},
{
"id": "29b84fe8-6ccc-4660-9eba-87228ad80055",
"name": "Check Airtable",
"type": "n8n-nodes-base.airtable",
"position": [
240,
128
],
"parameters": {
"base": {
"__rl": true,
"mode": "list",
"value": "appUJQfAXniGZzwL8",
"cachedResultUrl": "https://airtable.com/appUJQfAXniGZzwL8",
"cachedResultName": "YouTube Video IDS"
},
"table": {
"__rl": true,
"mode": "list",
"value": "tblgRW5IYgTz1bUxB",
"cachedResultUrl": "https://airtable.com/appUJQfAXniGZzwL8/tblgRW5IYgTz1bUxB",
"cachedResultName": "Table 1"
},
"options": {},
"operation": "search",
"filterByFormula": "=FIND(\"{{ $json.id.split(\":\").pop().trim() }}\", {Video ID}) > 0\n"
},
"credentials": {
"airtableTokenApi": {
"name": "<your credential>"
}
},
"typeVersion": 2.1,
"alwaysOutputData": true
},
{
"id": "ff6ebf58-f461-4f84-9f4f-1f98ca83ad35",
"name": "Is New Video?",
"type": "n8n-nodes-base.if",
"position": [
464,
128
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "69651e9f-d4d9-4417-9ec1-f28c19ed10f4",
"operator": {
"type": "string",
"operation": "empty",
"singleValue": true
},
"leftValue": "={{ $json['Video ID'] }}",
"rightValue": ""
}
]
}
},
"typeVersion": 2.2
},
{
"id": "6b62ac99-f5a7-4444-a164-574da357e6eb",
"name": "Save to Airtable",
"type": "n8n-nodes-base.airtable",
"position": [
688,
112
],
"parameters": {
"base": {
"__rl": true,
"mode": "list",
"value": "appUJQfAXniGZzwL8",
"cachedResultUrl": "https://airtable.com/appUJQfAXniGZzwL8",
"cachedResultName": "YouTube Video IDS"
},
"table": {
"__rl": true,
"mode": "list",
"value": "tblgRW5IYgTz1bUxB",
"cachedResultUrl": "https://airtable.com/appUJQfAXniGZzwL8/tblgRW5IYgTz1bUxB",
"cachedResultName": "Table 1"
},
"columns": {
"value": {
"Video ID": "={{ $('Get New YouTube Video').item.json.id.split(\":\")[2]}}\n"
},
"schema": [
{
"id": "Video ID",
"type": "string",
"display": true,
"removed": false,
"readOnly": false,
"required": false,
"displayName": "Video ID",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [
"Video ID"
],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "create"
},
"credentials": {
"airtableTokenApi": {
"name": "<your credential>"
}
},
"typeVersion": 2.1
},
{
"id": "943d060a-d587-4f75-94cc-d184076ea1a7",
"name": "Format Video ID",
"type": "n8n-nodes-base.set",
"position": [
896,
112
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "7caccd3e-f605-40ce-b2fd-0e6f48c310a3",
"name": "snippet.title",
"type": "string",
"value": "={{ $('Get New YouTube Video').item.json.title }}"
},
{
"id": "4ca86560-0701-4d2e-845a-aeab3bb8be36",
"name": "id.videoId",
"type": "string",
"value": "={{ $json.fields['Video ID'] }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "1dbeb5be-1c36-48be-898e-8d0722947c95",
"name": " Fetch Transcript",
"type": "n8n-nodes-base.httpRequest",
"position": [
1088,
112
],
"parameters": {
"url": "=https://api.supadata.ai/v1/transcript?url=https://youtu.be/{{ $json.id.videoId }}",
"options": {},
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth"
},
"credentials": {
"httpHeaderAuth": {
"name": "<your credential>"
}
},
"typeVersion": 4.2
},
{
"id": "3ee9cafb-76f2-4c0c-a382-8e7e2f34f85c",
"name": "Prepare Transcript + Duration",
"type": "n8n-nodes-base.code",
"position": [
1280,
112
],
"parameters": {
"jsCode": "const transcript = $json.content;\n\nconst lines = transcript.map(line => {\n const seconds = Math.floor(line.offset / 1000);\n const minutes = Math.floor(seconds / 60);\n const remaining = seconds % 60;\n const timestamp = `${String(minutes).padStart(2, '0')}:${String(remaining).padStart(2, '0')}`;\n return `${timestamp} ${line.text}`;\n});\n\nconst formattedTranscript = lines.join('\\n');\n\n// Calculate video length\nconst last = transcript[transcript.length - 1];\nconst maxDurationSeconds = Math.floor((last.offset + last.duration) / 1000);\n\nreturn [{\n json: {\n formattedTranscript,\n maxDurationSeconds\n }\n}];"
},
"typeVersion": 2
},
{
"id": "483ae4b0-e725-46be-a90f-6480fb8468a9",
"name": "AI: Generate Chapters",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
1712,
112
],
"parameters": {
"text": "=Based on the transcript below, generate chapter timestamps with short titles.\n\n\nFormatted transcript: {{ $json.formattedTranscript }}\n\nFull video length: {{ $json.maxDurationSeconds }}\n\nOnly return the chapters in this format:\n\n00:00 Intro \n01:10 Key Concept \n02:45 Main Topic \n04:30 Explanation \n...\n\nDo not include any intro text, explanation, or extra commentary \u2014 only the list of chapters.\n\n#Rules\n1. The timestamps have to always start at 00:00 to work on YouTube. So for example:\n- Don't include timestamps beyond {{ $json.maxDurationSeconds }} seconds\n- Use clear, descriptive titles\n- Group together lines close in time\n\n00:00 Intro \n01:10 Key Concept \n02:45 Main Topic \n04:30 Explanation \n\nIf we're missing the first 00:00 it won't be valid",
"options": {},
"promptType": "define"
},
"typeVersion": 2.2
},
{
"id": "0ded7384-5220-476e-a79d-2304e4c825a4",
"name": "Fetch Current Description",
"type": "n8n-nodes-base.youTube",
"position": [
2304,
464
],
"parameters": {
"options": {},
"videoId": "={{ $('Save to Airtable').item.json.fields['Video ID'].trim() }}",
"resource": "video",
"operation": "get"
},
"credentials": {
"youTubeOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "2785f37b-6761-4323-8bbc-323fa1b16d24",
"name": "Update Description",
"type": "n8n-nodes-base.youTube",
"position": [
2576,
464
],
"parameters": {
"title": "={{ $('Get New YouTube Video').item.json.title }}",
"videoId": "={{ $('Save to Airtable').item.json.fields['Video ID'].trim() }}",
"resource": "video",
"operation": "update",
"categoryId": "27",
"regionCode": "US",
"updateFields": {
"description": "={{ $json.snippet.description }}\n\n{{ $('AI: Generate Chapters').item.json.output }}"
}
},
"credentials": {
"youTubeOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 1
}
],
"connections": {
"Is New Video?": {
"main": [
[
{
"node": "Save to Airtable",
"type": "main",
"index": 0
}
]
]
},
"Check Airtable": {
"main": [
[
{
"node": "Is New Video?",
"type": "main",
"index": 0
}
]
]
},
"Format Video ID": {
"main": [
[
{
"node": " Fetch Transcript",
"type": "main",
"index": 0
}
]
]
},
"Save to Airtable": {
"main": [
[
{
"node": "Format Video ID",
"type": "main",
"index": 0
}
]
]
},
" Fetch Transcript": {
"main": [
[
{
"node": "Prepare Transcript + Duration",
"type": "main",
"index": 0
}
]
]
},
"OpenAI Chat Model": {
"ai_languageModel": [
[
{
"node": "AI: Generate Chapters",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"AI: Generate Chapters": {
"main": [
[
{
"node": "Fetch Current Description",
"type": "main",
"index": 0
}
]
]
},
"Get New YouTube Video": {
"main": [
[
{
"node": "Check Airtable",
"type": "main",
"index": 0
}
]
]
},
"Fetch Current Description": {
"main": [
[
{
"node": "Update Description",
"type": "main",
"index": 0
}
]
]
},
"Prepare Transcript + Duration": {
"main": [
[
{
"node": "AI: Generate Chapters",
"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.
airtableTokenApihttpHeaderAuthopenAiApiyouTubeOAuth2Api
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This n8n template automatically adds structured timestamp chapters to your latest YouTube video’s description using your RSS feed, SupaData for transcript extraction, and an AI tool for chapter generation.
Source: https://n8n.io/workflows/10719/ — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
This n8n automation workflow automates the creation, scripting, production, and posting of YouTube videos. It leverages AI (OpenAI), image generation (PIAPI), video rendering (Shotstack), and platform
Digital marketers, content creators, social media managers, and businesses who want to use AI marketing automation for YouTube Shorts without spending hours on production. This AI workflow helps anyon
Typeform IA - YT. Uses typeformTrigger, agent, lmChatOpenAi, toolWorkflow. Event-driven trigger; 75 nodes.
This workflow is perfect for content creators, digital marketers, and social media managers who want to automatically syndicate their content across multiple platforms. It's ideal for businesses, blog
📄 Documentation: Notion Guide