{
  "name": "YouTube Upload Cross-Post",
  "nodes": [
    {
      "parameters": {
        "content": "## YouTube New Video Cross-Post to Telegram + Discord\n\nUpload a video, and your Telegram and Discord communities hear about it within 15 minutes - title, link, and a call to watch, posted while the algorithm window is hot.\n\n**Setup time:** 10 minutes  ·  **Level:** Beginner\n\n**You'll need accounts/credentials for:** YouTube, Telegram, Discord\n\n**Replace these before running:**\n- `REPLACE_WITH_CHANNEL_ID`\n- `REPLACE_WITH_CHAT_ID`\n\n**Setup steps:**\n1. Get your channel ID (YouTube Studio > Settings > Channel > Advanced) and put it in the RSS node URL: youtube.com/feeds/videos.xml?channel_id=YOURID.\n2. Connect Telegram (bot token from @BotFather, add the bot to your channel as admin) and set the chat ID.\n3. Create a Discord webhook (channel settings > Integrations) and add it to the Discord node.\n4. Activate. Your next upload announces itself.\n\nFree templates and updates: navkhan103.github.io",
        "height": 618,
        "width": 400,
        "color": 4
      },
      "id": "sticky-setup",
      "name": "Setup — read me first",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -440,
        -140
      ]
    },
    {
      "parameters": {
        "content": "### How it runs\n\nStarts from **Every 15 Minutes**.\n\n1. A Schedule Trigger polls every 15 minutes.\n2. An RSS node reads your channel's public feed (every YouTube channel has one - no API key required).\n3. A Code node passes only videos published since the last poll.\n4. Telegram and Discord nodes announce the video simultaneously.",
        "height": 348,
        "width": 400,
        "color": 7
      },
      "id": "sticky-how",
      "name": "How it runs",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -440,
        518
      ]
    },
    {
      "parameters": {
        "content": "### If something breaks\n\nThe read and AI nodes here **retry 3× automatically** (5s apart), which absorbs rate limits and brief timeouts.\n\nNodes that **send or write deliberately do not retry** — a send that reached the far end but lost its response would otherwise fire twice, so you'd get duplicate messages or duplicate rows.\n\nTo be told when one of those fails, build a workflow starting with an **Error Trigger** node that posts to Slack or email, then set it under **three-dot menu > Settings > Error Workflow**. Do it once and point every workflow at it.",
        "height": 400,
        "width": 400,
        "color": 3
      },
      "id": "sticky-fail",
      "name": "If something breaks",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -440,
        906
      ]
    },
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "minutes",
              "minutesInterval": 15
            }
          ]
        }
      },
      "id": "d7e8f9a0-0001-4000-8000-000000000001",
      "name": "Every 15 Minutes",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.2,
      "position": [
        0,
        0
      ]
    },
    {
      "parameters": {
        "url": "https://www.youtube.com/feeds/videos.xml?channel_id=REPLACE_WITH_CHANNEL_ID",
        "options": {}
      },
      "id": "d7e8f9a0-0002-4000-8000-000000000002",
      "name": "Channel Feed",
      "type": "n8n-nodes-base.rssFeedRead",
      "typeVersion": 1.1,
      "position": [
        220,
        0
      ],
      "retryOnFail": true,
      "maxTries": 3,
      "waitBetweenTries": 5000
    },
    {
      "parameters": {
        "jsCode": "const cutoff = Date.now() - 15 * 60 * 1000;\nreturn $input.all()\n  .map(i => i.json)\n  .filter(v => new Date(v.isoDate || v.pubDate).getTime() > cutoff)\n  .map(v => ({ json: { title: v.title, link: v.link } }));"
      },
      "id": "d7e8f9a0-0003-4000-8000-000000000003",
      "name": "New Uploads Only",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        440,
        0
      ]
    },
    {
      "parameters": {
        "chatId": "REPLACE_WITH_CHAT_ID",
        "text": "=🎬 New video is live!\n{{ $json.title }}\n{{ $json.link }}",
        "additionalFields": {}
      },
      "id": "d7e8f9a0-0004-4000-8000-000000000004",
      "name": "Announce on Telegram",
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1.2,
      "position": [
        660,
        -100
      ]
    },
    {
      "parameters": {
        "authentication": "webhook",
        "content": "=🎬 **New video is live!**\n{{ $json.title }}\n{{ $json.link }}"
      },
      "id": "d7e8f9a0-0005-4000-8000-000000000005",
      "name": "Announce on Discord",
      "type": "n8n-nodes-base.discord",
      "typeVersion": 2,
      "position": [
        660,
        100
      ]
    }
  ],
  "connections": {
    "Every 15 Minutes": {
      "main": [
        [
          {
            "node": "Channel Feed",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Channel Feed": {
      "main": [
        [
          {
            "node": "New Uploads Only",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "New Uploads Only": {
      "main": [
        [
          {
            "node": "Announce on Telegram",
            "type": "main",
            "index": 0
          },
          {
            "node": "Announce on Discord",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  }
}