AutomationFlowsMarketing & Ads › Youtube Workflow

Youtube Workflow

Youtube Workflow. Uses youTube, rssFeedRead, httpRequest, emailSend. Scheduled trigger; 18 nodes.

Cron / scheduled trigger★★★★☆ complexity18 nodesYouTubeRSS Feed ReadHTTP RequestEmail SendStop And Error
Marketing & Ads Trigger: Cron / scheduled Nodes: 18 Complexity: ★★★★☆ Added:
Youtube Workflow — n8n workflow card showing YouTube, RSS Feed Read, HTTP Request integration

This workflow follows the Emailsend → HTTP Request 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": {
    "versionId": "1.0.0",
    "createdAt": "2025-09-29T07:07:55.383329",
    "updatedAt": "2025-09-29T07:07:55.383354",
    "owner": "n8n-user",
    "license": "MIT",
    "category": "automation",
    "status": "active",
    "priority": "high",
    "environment": "production"
  },
  "nodes": [
    {
      "id": "a5292068-5ace-4372-9869-46100ae81b8f",
      "name": "Get video details",
      "type": "n8n-nodes-base.youTube",
      "notes": "Make a call to the YouTube API so that we have the thumbnail for the email and the duration to filter out shorts.",
      "position": [
        1000,
        -60
      ],
      "parameters": {
        "part": [
          "contentDetails",
          "snippet",
          "id"
        ],
        "options": {},
        "videoId": "={{ $json.id.replace(\"yt:video:\", \"\") }}",
        "resource": "video",
        "operation": "get"
      },
      "credentials": {
        "youTubeOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "b9eb34aa-90c4-492a-a33e-37a32812fa32",
      "name": "Schedule Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -840,
        -160
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "hours",
              "hoursInterval": 1,
              "triggerAtMinute": 47
            }
          ]
        }
      },
      "typeVersion": 1.2,
      "notes": "This scheduleTrigger node performs automated tasks as part of the workflow."
    },
    {
      "id": "8f0dbe74-53e5-4b14-86f6-eb0f502c8471",
      "name": "Filter out shorts",
      "type": "n8n-nodes-base.if",
      "notes": "Sometime, some live broadcasts that are then posted as regular videos do not have a duration. That is why we check if `duration` is present in `contentDetails`.",
      "position": [
        1180,
        -60
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 1,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "or",
          "conditions": [
            {
              "id": "5342ecc0-d764-4bef-8161-d1f571fcb931",
              "operator": {
                "type": "string",
                "operation": "notExists",
                "singleValue": true
              },
              "leftValue": "={{ $json.contentDetails.duration }}",
              "rightValue": "\"duration\""
            },
            {
              "id": "b82e3373-a28b-49bd-afa0-4f48cafe2bfe",
              "operator": {
                "type": "number",
                "operation": "gt"
              },
              "leftValue": "={{ Duration.fromISO($json.contentDetails.duration).as('seconds') }}",
              "rightValue": 61
            }
          ]
        }
      },
      "notesInFlow": false,
      "typeVersion": 2
    },
    {
      "id": "14d54ed0-f5c0-4992-af56-0af2d8973963",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -900,
        -340
      ],
      "parameters": {
        "color": 7,
        "width": 220,
        "height": 460,
        "content": "### Default frequency: every hour\nChanging it here is enough if you want to check for new videos at a higher or lower frequency. You don't have to edit anything else."
      },
      "typeVersion": 1,
      "notes": "This stickyNote node performs automated tasks as part of the workflow."
    },
    {
      "id": "c4acbb10-1f57-4934-a324-f26d0532767c",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -660,
        -340
      ],
      "parameters": {
        "color": 5,
        "width": 880,
        "height": 460,
        "content": "### Get my subscriptions from the YouTube Data v3 API\nYou can expect to use 1 quota per 50 subscriptions per run, which is well within the 10 000/req a day allowed by default."
      },
      "typeVersion": 1,
      "notes": "This stickyNote node performs automated tasks as part of the workflow."
    },
    {
      "id": "4ae2d2f3-53b5-4431-90d8-06e41a6950e2",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        480,
        -160
      ],
      "parameters": {
        "color": 4,
        "width": 440,
        "height": 280,
        "content": "### Get the 15 latest videos of each channel with RSS\nUsing the YouTube API instead would cost too many quotas to make it viable."
      },
      "typeVersion": 1,
      "notes": "This stickyNote node performs automated tasks as part of the workflow."
    },
    {
      "id": "48894d79-7e59-49fc-beb5-445fb5ca2ff6",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        940,
        -160
      ],
      "parameters": {
        "color": 3,
        "width": 400,
        "height": 280,
        "content": "### Call YouTube's API for more data\nWe need the thumbnails for the email and the duration to filter out shorts."
      },
      "typeVersion": 1,
      "notes": "This stickyNote node performs automated tasks as part of the workflow."
    },
    {
      "id": "e3da3f97-138c-481e-a763-9a3c9e402928",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1360,
        -160
      ],
      "parameters": {
        "color": 6,
        "width": 260,
        "height": 280,
        "content": "### Configure your email here\nTo go to the video from the email, simply click on the thumbnail."
      },
      "typeVersion": 1,
      "notes": "This stickyNote node performs automated tasks as part of the workflow."
    },
    {
      "id": "0d092c3d-b2e1-4468-a044-c6cf0f37672b",
      "name": "Get latest 15 videos of each channel",
      "type": "n8n-nodes-base.rssFeedRead",
      "notes": "YouTube provides an RSS feed for each channel with the 15 latest videos.\nWe use this instead of the YouTube Data v3 API, as search requests cost a lot of \"quota points\" and would easily put us over the daily limit with just one workflow run.",
      "position": [
        540,
        -60
      ],
      "parameters": {
        "url": "{{ $env.BASE_URL }}",
        "options": {}
      },
      "typeVersion": 1.1
    },
    {
      "id": "34823384-d8a5-415a-87ff-203d65aa9a75",
      "name": "Get my subscriptions",
      "type": "n8n-nodes-base.httpRequest",
      "notes": "Get subscriptions from YouTube Data v3 API",
      "position": [
        -600,
        -160
      ],
      "parameters": {
        "url": "{{ $env.API_BASE_URL }}",
        "options": {
          "pagination": {
            "pagination": {
              "parameters": {
                "parameters": [
                  {
                    "name": "pageToken",
                    "value": "={{ $response.body.nextPageToken }}"
                  }
                ]
              },
              "completeExpression": "={{ !('nextPageToken' in $response.body) }}",
              "paginationCompleteWhen": "other"
            }
          }
        },
        "sendQuery": true,
        "authentication": "{{ $credentials.predefinedCredentialType }}",
        "queryParameters": {
          "parameters": [
            {
              "name": "mine",
              "value": "true"
            },
            {
              "name": "part",
              "value": "snippet,contentDetails"
            },
            {
              "name": "maxResults",
              "value": "50"
            }
          ]
        },
        "nodeCredentialType": "YOUR_CREDENTIAL_HERE"
      },
      "credentials": {
        "youTubeOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "notesInFlow": true,
      "typeVersion": 4.2
    },
    {
      "id": "534e38f3-ac40-4194-8821-5926ee581605",
      "name": "Check for errors",
      "type": "n8n-nodes-base.if",
      "position": [
        -400,
        -160
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "5972ff90-aa5a-470c-aa96-87138eb60565",
              "operator": {
                "type": "object",
                "operation": "exists",
                "singleValue": true
              },
              "leftValue": "={{ $json.error }}",
              "rightValue": "error"
            }
          ]
        }
      },
      "typeVersion": 2.2,
      "notes": "This if node performs automated tasks as part of the workflow."
    },
    {
      "id": "2d872c0f-30b9-4ffc-aba0-6644bf05d7bb",
      "name": "Only keep channels with unwatched videos",
      "type": "n8n-nodes-base.filter",
      "notes": "It's not a perfect indicator for new videos but helps reduce the amount of channels to process.",
      "position": [
        40,
        -60
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "4734ee8c-1655-47be-bd45-a9527aee2833",
              "operator": {
                "type": "number",
                "operation": "gt"
              },
              "leftValue": "={{ $json.contentDetails.newItemCount }}",
              "rightValue": 0
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "c7bd97ec-47c1-40b4-955d-bf89d3cde330",
      "name": "Keep only videos published since last run",
      "type": "n8n-nodes-base.filter",
      "notes": "We dynamically figure out the last run's execution time through the settings of the \"Schedule Trigger\" node.",
      "position": [
        740,
        -60
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "65d905a2-c89e-41f3-a2cf-0d1a76c48d8e",
              "operator": {
                "type": "dateTime",
                "operation": "after"
              },
              "leftValue": "={{ $json.pubDate.toDateTime() }}",
              "rightValue": "={{ \n  $('Schedule Trigger').item.json.timestamp.toDateTime().minus(\n    $('Schedule Trigger').params.rule.interval[0].hoursInterval,\n    $('Schedule Trigger').params.rule.interval[0].field\n  ).toISO()\n}}"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "72341b1f-a391-4210-b3ca-4e74ae1f2e1b",
      "name": "Send an email for each new video",
      "type": "n8n-nodes-base.emailSend",
      "notes": "The expression in the HTML for the thumbnail simply selects the last element of the thumbnails array so that we get the best possible resolution thumbnail available.",
      "position": [
        1440,
        -60
      ],
      "parameters": {
        "html": "=<h1 style=\"text-align: center;\">{{ $json.snippet.title }}</h1>\n<a href=\"{{ $env.WEBHOOK_URL }}{{ $json.id }}\">\n  <img src=\"{{ $json.snippet.thumbnails[Object.keys($json.snippet.thumbnails)[Object.keys($json.snippet.thumbnails).length - 1]].url }}\" alt=\"Watch on YouTube\" style=\"width:100%; height:auto; max-width:640px; display:block; margin: 10px auto;\">\n</a>",
        "options": {
          "appendAttribution": false
        },
        "subject": "={{ $json.snippet.channelTitle }}",
        "toEmail": "My Name <you@example.com>",
        "fromEmail": "YouTube <you@example.com>"
      },
      "credentials": {
        "smtp": {
          "name": "<your credential>"
        }
      },
      "notesInFlow": false,
      "typeVersion": 2.1
    },
    {
      "id": "b82cfbd5-71e3-418f-9b6d-6d0ec007733a",
      "name": "If the HTTP request failed, throw the error",
      "type": "n8n-nodes-base.stopAndError",
      "position": [
        -180,
        -260
      ],
      "parameters": {
        "errorMessage": "=Status code: {{ $json.error.code }}\nMessage: {{ $json.error.message }}"
      },
      "typeVersion": 1,
      "notes": "This stopAndError node performs automated tasks as part of the workflow."
    },
    {
      "id": "e89eca92-896f-46b5-8a4b-149d51682faa",
      "name": "Split out subscriptions to process individually",
      "type": "n8n-nodes-base.splitOut",
      "position": [
        -180,
        -60
      ],
      "parameters": {
        "options": {},
        "fieldToSplitOut": "items"
      },
      "typeVersion": 1,
      "notes": "This splitOut node performs automated tasks as part of the workflow."
    },
    {
      "id": "0e00fda6-1489-4c1a-8205-22e620a554c5",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        240,
        -240
      ],
      "parameters": {
        "width": 220,
        "height": 360,
        "content": "## Manually filter out channels\nTo find the channel ID of a channel, click on the description \u2192 Share channel \u2192 Copy channel ID"
      },
      "typeVersion": 1,
      "notes": "This stickyNote node performs automated tasks as part of the workflow."
    },
    {
      "id": "bcc2e57c-23b2-42b7-81ab-cdd88b70b8a3",
      "name": "Filter out channels",
      "type": "n8n-nodes-base.filter",
      "notes": "Optional step",
      "position": [
        300,
        -60
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "b27b14a9-c86c-4ebd-8a0f-4e7db722796e",
              "operator": {
                "type": "array",
                "operation": "notContains",
                "rightType": "any"
              },
              "leftValue": "={{[\n  \"exampleChannelId1\",\n  \"exampleChannelId2\"\n]}}",
              "rightValue": "={{ $json.snippet.resourceId.channelId }}"
            }
          ]
        }
      },
      "notesInFlow": true,
      "typeVersion": 2.2
    }
  ],
  "connections": {
    "Get my subscriptions": {
      "main": [
        [],
        [],
        [],
        [],
        [],
        [],
        [],
        []
      ]
    },
    "Send an email for each new video": {
      "main": [
        [],
        [],
        [],
        [],
        [],
        [],
        [],
        []
      ]
    }
  },
  "name": "Youtube Workflow",
  "settings": {
    "executionOrder": "v1",
    "saveManualExecutions": true,
    "callerPolicy": "workflowsFromSameOwner",
    "errorWorkflow": null,
    "timezone": "UTC",
    "executionTimeout": 3600,
    "maxExecutions": 1000,
    "retryOnFail": true,
    "retryCount": 3,
    "retryDelay": 1000
  },
  "description": "Automated workflow: Youtube Workflow. This workflow integrates 10 different services: stickyNote, youTube, httpRequest, filter, scheduleTrigger. It contains 20 nodes and follows best practices for error handling and security.",
  "notes": "Excellent quality workflow: Youtube Workflow. This workflow has been optimized for production use with comprehensive error handling, security, and documentation.",
  "id": "wf1704db348aa1"
}

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

Youtube Workflow. Uses youTube, rssFeedRead, httpRequest, emailSend. Scheduled trigger; 18 nodes.

Source: https://github.com/basictechorg/n8n-marketing-sales/blob/main/workflows/content-marketing/0791_Stopanderror_Splitout_Create_Webhook.json — original creator credit. Request a take-down →

More Marketing & Ads workflows → · Browse all categories →

Related workflows

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

Marketing & Ads

每週 AI 新聞摘要 (Weekly AI News Digest). Uses rssFeedRead, httpRequest, emailSend. Scheduled trigger; 8 nodes.

RSS Feed Read, HTTP Request, Email Send
Marketing & Ads

post to mattermost v2. Uses rssFeedRead, httpRequest, stopAndError. Scheduled trigger; 7 nodes.

RSS Feed Read, HTTP Request, Stop And Error
Marketing & Ads

Post RSS feed items from yesterday to Slack. Uses rssFeedRead, slack, stopAndError. Scheduled trigger; 7 nodes.

RSS Feed Read, Slack, Stop And Error
Marketing & Ads

Production Workflow. Uses httpRequest, twitter, stopAndError. Scheduled trigger; 5 nodes.

HTTP Request, Twitter, Stop And Error
Marketing & Ads

Cocktail Recipe Sharing. Uses bannerbear, httpRequest, rocketchat, stopAndError. Scheduled trigger; 5 nodes.

Bannerbear, HTTP Request, Rocketchat +1