n8n YouTube Shorts Automation: Long Video In, Captioned Clips Out

An n8n YouTube Shorts automation that cuts every new video of a channel into captioned vertical clips, with a workflow JSON you can import.

To automate YouTube Shorts with n8n:

  1. Trigger the workflow from the channel's RSS feed whenever a new video comes out.
  2. Send the video link to Renderster with one HTTP Request node (POST /media, type: "clips").
  3. Wait for the job, then post the clips to Slack, Google Drive or YouTube.

Each video costs 7 credits, however long it is. Get your API key →

Most "n8n Shorts" tutorials build a faceless video from a template: a script, stock footage and a robot voice. This one does what most people actually want. It takes the long video you already published and cuts it into real Shorts: the best moments, vertical, with the speaker in frame, captions burned in and a title for each clip.

No community node and no plugin. It's plain HTTP Request nodes, and the full workflow JSON is further down so you can paste it into n8n.

What this workflow does

Here is the flow, node by node:

New video on the channel (RSS Feed Trigger, every hour)
  → Settings (Edit Fields: clip count, caption style, topic)
  → Create clips job (HTTP Request: POST https://renderster.com/media)
  → Wait 60 s
  → Check the job (HTTP Request: GET status_url)
  → Status (Switch)
       Done          → Post the clips to Slack
       Failed        → Job failed (Stop and Error)
       Still working → back to Wait 60 s

Renderster does the heavy part. It downloads the video, transcribes it, picks the moments worth posting (it favors the parts YouTube viewers replay the most, when the video has that data), crops each one to 9:16 around the speaker, burns word-by-word captions and writes a title, hook, description and hashtags for each clip. n8n only moves links around.

What you need

Step 1: Get your API key and add it to n8n

Sign in to Renderster and open the API Key page. Your personal key is there, hidden by default, with a copy button. The page also shows the two ways to send it: the X-API-Key header or Authorization: Bearer.

The Renderster API Key page with the personal key masked and the copy button
The Renderster API Key page with the personal key masked and the copy button

In n8n, create a credential of type Header Auth:

Every Renderster node in the workflow uses this one credential. Never paste the key into a node's URL or body: it would end up in exported workflows and screenshots.

Step 2: Trigger on a new video (RSS)

Every YouTube channel has a public RSS feed:

https://www.youtube.com/feeds/videos.xml?channel_id=CHANNEL_ID

The channel ID starts with UC. You find it on the channel's About page (Share channel → Copy channel ID).

Add an RSS Feed Trigger node, paste the feed URL and set the poll time. The template checks every hour. Each new entry gives you link (the video URL) and title.

Then an Edit Fields (Set) node called Settings holds what you may want to change later:

Field Value in the template What it does
video_url {{ $json.link }} The new video
video_title {{ $json.title }} Used in the Slack message
clip_count 5 1 to 12 clips per video
caption_style bold Also karaoke, highlight, single, boxed, clean, neon, box, beast, cortes, minimal
topic empty Optional: keep only moments about a subject, e.g. "the pricing questions"

Keeping these in one node means you never have to open the HTTP Request body to change a setting.

Step 3: HTTP Request to create the clips

Add an HTTP Request node named Create clips job:

{{ JSON.stringify({
  url: $json.video_url,
  type: 'clips',
  options: Object.assign(
    { clip_count: $json.clip_count, caption_style: $json.caption_style, hook_title: true },
    $json.topic ? { topic: $json.topic } : {}
  )
}) }}

hook_title: true shows each clip's title in a box at the top for the first seconds. Leave it out if you prefer clean clips.

The Idempotency-Key header matters more than it looks. n8n retries failed nodes, and networks drop answers. With the header, the same request within 24 hours returns the first answer instead of creating a second job and charging you twice. The key is the execution ID plus the item index, so two new videos in the same run still get two jobs.

Renderster answers right away with 202 Accepted:

{
  "id": "0f8b6c2e-5d1a-4c3e-9b7f-2a6d8e4c1b90",
  "status": "queued",
  "status_url": "https://renderster.com/media/0f8b6c2e-5d1a-4c3e-9b7f-2a6d8e4c1b90",
  "platform": "youtube",
  "type": "clips",
  "credit_cost": 7
}

The clips are not ready yet. That's the next step.

Step 4: Wait for the job (poll or webhook)

A clips job usually takes a few minutes, depending on the video's length. You have two ways to wait.

Option A: poll (what the template does)

A small loop:

  1. Wait 60 s (Wait node).
  2. Check the job: an HTTP Request GET to {{ $('Create clips job').item.json.status_url }} with the same credential. The template turns on Retry On Fail (3 tries, 5 s apart) so one network hiccup doesn't kill the run.
  3. Status: a Switch node on {{ $json.status }}. completed goes to Done, failed to Failed, and anything else (queued, processing) goes back to the Wait node.

Polling works everywhere, including an n8n running on your laptop. Status reads are cheap and don't cost credits (the limit is 1,200 a minute per account, far above what this loop does).

Option B: webhook

Add webhook_url to the body and Renderster calls it when the job ends. You can point it at a Webhook node in another workflow, or at a Wait node set to resume On Webhook Call (pass {{ $execution.resumeUrl }} as webhook_url).

The webhook body is short:

{"id": "0f8b6c2e-…", "status": "completed", "output_url": "https://renderster.com/files/…"}

On failure it carries "status": "failed" and an error message. It doesn't carry the clips, so after the webhook, do one GET on https://renderster.com/media/{{ $json.body.id }} to read result.clips. Renderster tries each webhook 3 times and only calls public addresses, so an n8n on localhost will never receive it. Use polling there.

Step 5: Post or send the clips

When the job is done, result.clips is a list. Each clip has:

Field Example
index 1
url https://renderster.com/files/…/clip_01.mp4
thumbnail a JPEG frame
title "The promise nobody expected"
hook the opening line
description, hashtags ready for the post
duration, start, end seconds
score how strong the AI thinks it is (0–100)

The template sends one Slack message with every clip's title, length and link:

{{ '*New clips from:* ' + $('Settings').item.json.video_title + '\n' +
   $json.result.clips.map(c => '• ' + c.title + ' (' + Math.round(c.duration) + ' s): ' + c.url).join('\n') }}

You don't need your own storage for this. Every clip link is a signed link on renderster.com (/files/<signature>/<key>). It opens in any browser, supports seeking, and ?download=1 at the end forces a download. Nobody needs a Renderster account to open it. Each job also has an expires_at date, after which its files may be deleted, so copy what you want to keep before then.

Other endings people use:

Look at the clips before they go public, at least for the first weeks. The AI picks moments well, but you know your audience and your brand.

A finished clips job page in Renderster, the same page a job created from n8n gets: the clip with its score, title, hashtags and "Why it works"
A finished clips job page in Renderster, the same page a job created from n8n gets: the clip with its score, title, hashtags and "Why it works"

Jobs created by the API show up in your Jobs list like any other, and the usage page marks where each call came from (n8n requests are tagged n8n).

Download the workflow JSON

Copy the JSON below, open an empty workflow in n8n and paste it (Ctrl+V / Cmd+V) on the canvas. Then:

  1. Replace CHANNEL_ID in New video on the channel.
  2. Pick your Renderster Header Auth credential in Create clips job and Check the job.
  3. Connect Slack and pick the channel in Post the clips to Slack.
  4. Activate the workflow.
{
  "name": "Clip every new YouTube video from a channel and share the clips in Slack",
  "nodes": [
    {"parameters": {"pollTimes": {"item": [{"mode": "everyHour"}]}, "feedUrl": "https://www.youtube.com/feeds/videos.xml?channel_id=CHANNEL_ID"},
     "id": "a31d696c-1aad-50ce-b372-2abf1d1de6d9", "name": "New video on the channel", "type": "n8n-nodes-base.rssFeedReadTrigger", "typeVersion": 1, "position": [-400, 0]},
    {"parameters": {"assignments": {"assignments": [
        {"id": "9cd35b83-3820-5924-a6b0-08a83ac6aa30", "name": "video_url", "value": "={{ $json.link }}", "type": "string"},
        {"id": "23d09df8-7b1e-5a30-a8b0-672d7fd67c32", "name": "video_title", "value": "={{ $json.title }}", "type": "string"},
        {"id": "e959d35d-eb12-5701-aa03-4b13ed46618f", "name": "clip_count", "value": 5, "type": "number"},
        {"id": "caf235b1-bc59-5602-a6b7-30371b210484", "name": "caption_style", "value": "bold", "type": "string"},
        {"id": "00711168-c6d0-5302-a9d9-222cd539f84a", "name": "topic", "value": "", "type": "string"}]}, "options": {}},
     "id": "c1d27d50-e90d-5e0f-b233-0d22ee282c7f", "name": "Settings", "type": "n8n-nodes-base.set", "typeVersion": 3.4, "position": [-180, 0]},
    {"parameters": {"method": "POST", "url": "https://renderster.com/media", "authentication": "genericCredentialType", "genericAuthType": "httpHeaderAuth",
        "sendHeaders": true, "headerParameters": {"parameters": [{"name": "Idempotency-Key", "value": "={{ $execution.id }}-{{ $itemIndex }}"}]},
        "sendBody": true, "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify({ url: $json.video_url, type: 'clips', options: Object.assign({ clip_count: $json.clip_count, caption_style: $json.caption_style, hook_title: true }, $json.topic ? { topic: $json.topic } : {}) }) }}",
        "options": {}},
     "id": "8766f80a-f1d8-5025-8da7-677a4a13c83e", "name": "Create clips job", "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.4, "position": [40, 0],
     "credentials": {"httpHeaderAuth": {"id": "REPLACE_ME", "name": "Renderster API key (X-API-Key)"}}},
    {"parameters": {"amount": 60}, "id": "426ebf51-fa58-5cf5-a7e1-f163c4c1caab", "name": "Wait 60 s", "type": "n8n-nodes-base.wait", "typeVersion": 1.1, "position": [260, 0],
     "webhookId": "476947af-2bf0-55cd-9448-833ef2fdb77b"},
    {"parameters": {"url": "={{ $('Create clips job').item.json.status_url }}", "authentication": "genericCredentialType", "genericAuthType": "httpHeaderAuth", "options": {}},
     "id": "8d7eb702-6254-5fef-8a0d-898d0b088e68", "name": "Check the job", "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.4, "position": [480, 0],
     "credentials": {"httpHeaderAuth": {"id": "REPLACE_ME", "name": "Renderster API key (X-API-Key)"}}, "retryOnFail": true, "maxTries": 3, "waitBetweenTries": 5000},
    {"parameters": {"rules": {"values": [
        {"conditions": {"options": {"caseSensitive": true, "leftValue": "", "typeValidation": "strict"},
          "conditions": [{"leftValue": "={{ $json.status }}", "rightValue": "completed", "operator": {"type": "string", "operation": "equals"}}], "combinator": "and"},
         "renameOutput": true, "outputKey": "Done"},
        {"conditions": {"options": {"caseSensitive": true, "leftValue": "", "typeValidation": "strict"},
          "conditions": [{"leftValue": "={{ $json.status }}", "rightValue": "failed", "operator": {"type": "string", "operation": "equals"}}], "combinator": "and"},
         "renameOutput": true, "outputKey": "Failed"}]},
        "options": {"fallbackOutput": "extra", "renameFallbackOutput": "Still working"}},
     "id": "21840310-3971-528c-b377-14ace73d5473", "name": "Status", "type": "n8n-nodes-base.switch", "typeVersion": 3.4, "position": [700, 0]},
    {"parameters": {"errorMessage": "={{ 'Renderster job failed: ' + $json.message }}"},
     "id": "1126f9ea-912a-5332-b915-1814644e394f", "name": "Job failed", "type": "n8n-nodes-base.stopAndError", "typeVersion": 1, "position": [940, 200]},
    {"parameters": {"resource": "message", "operation": "post", "select": "channel", "channelId": {"__rl": true, "value": "", "mode": "list"},
        "text": "={{ '*New clips from:* ' + $('Settings').item.json.video_title + '\\n' + $json.result.clips.map(c => '• ' + c.title + ' (' + Math.round(c.duration) + ' s): ' + c.url).join('\\n') }}",
        "otherOptions": {}},
     "id": "baaf5a76-483f-51fe-839e-99fd35fe08b9", "name": "Post the clips to Slack", "type": "n8n-nodes-base.slack", "typeVersion": 2.4, "position": [960, -120],
     "credentials": {"slackOAuth2Api": {"id": "REPLACE_ME", "name": "Slack account"}}}
  ],
  "connections": {
    "New video on the channel": {"main": [[{"node": "Settings", "type": "main", "index": 0}]]},
    "Settings": {"main": [[{"node": "Create clips job", "type": "main", "index": 0}]]},
    "Create clips job": {"main": [[{"node": "Wait 60 s", "type": "main", "index": 0}]]},
    "Wait 60 s": {"main": [[{"node": "Check the job", "type": "main", "index": 0}]]},
    "Check the job": {"main": [[{"node": "Status", "type": "main", "index": 0}]]},
    "Status": {"main": [
      [{"node": "Post the clips to Slack", "type": "main", "index": 0}],
      [{"node": "Job failed", "type": "main", "index": 0}],
      [{"node": "Wait 60 s", "type": "main", "index": 0}]]}
  },
  "settings": {"executionOrder": "v1"},
  "pinData": {},
  "meta": {"templateCredsSetupCompleted": false}
}

The JSON has no keys in it. The credential IDs say REPLACE_ME on purpose; n8n asks you to pick your own.

What it costs per video

A clips job costs 7 credits whether the video is 8 minutes or 2 hours. Polling and webhooks are free. A failed job gives its credits back.

Uploads a month Credits Fits in
4 (one a week) 28 Starter, with lots left
12 (three a week) 84 Starter
30 (one a day) 210 Starter (600 credits, US$29/mo)
90 (three channels, daily) 630 Pro (2,000 credits, US$79/mo)

On Starter, one credit is about US$0.048, so each video costs about US$0.34. Unused credits roll over, up to 3x your monthly credits. Tools that charge per minute of source video make long uploads expensive; here a 2-hour podcast costs the same as a 10-minute vlog. Full prices are on /pricing.

Troubleshooting

401 unauthorized. The credential is wrong or not selected. The header name must be exactly X-API-Key, and both HTTP Request nodes need the credential.

402 with insufficient credits. The answer says how many you have and what the job costs. Top up with a Credit Pack (500 credits that never expire) or wait for the monthly credits.

402 with free_clip_used or plan_required. The Free plan's one clips job is used, or you asked for something only paid plans have (downloads, transcripts, visual search). The Free plan's job also stops at 3 clips. Start the 7-day trial.

422. The link isn't a video Renderster can read. Check what the RSS item gives in link.

429. rate_limited means too many requests a minute (the limit is 30 media jobs a minute per account); wait for the Retry-After header. daily_limit means you reached a daily cap; the message says when it resets.

The loop never ends. Look at the job in Renderster: the Logs tab says which step it's on. You can also cancel it with DELETE https://renderster.com/media/{id}.

The job failed on a brand-new video. A premiere or live stream can show up in the feed before the video can be downloaded. The job fails and the credits come back. Add a Wait node of a few hours after the trigger if your channel does premieres.

I get Shorts I already posted. If the channel also uploads Shorts, add a Filter node after the trigger so only long videos go through (for example, a link that does not contain /shorts/).

FAQ

Is there a free n8n template for YouTube Shorts automation?

Yes. The workflow JSON on this page is free to copy and import: RSS trigger, Renderster clips job, a wait loop and a Slack message. There is also a ready-made template in the official n8n library, Edit, clip and dub Telegram videos with Renderster: send a video or link to a Telegram bot and get it back edited, clipped or dubbed. You need your own n8n and a Renderster API key. The Free plan lets you run one clips job to test it; clipping every new video needs a paid plan, which starts with a 7-day free trial.

Does this cut my real video, or make a faceless video?

It cuts your real video. Renderster downloads the long video, picks the best moments, crops them to vertical around the speaker and burns captions in. Nothing is generated from stock footage or a script.

Do I need a community node or plugin?

No. Everything uses n8n's built-in HTTP Request, Wait, Switch, RSS and Slack nodes. Authentication is a Header Auth credential with your API key in X-API-Key.

Where are the clips stored?

On Renderster. Each clip comes back as a signed link on renderster.com that anyone can open or download, so you can share it straight from Slack or a sheet. Check the job's expires_at and copy the files to your own storage if you need them longer.

Can it post to YouTube or TikTok automatically?

n8n's YouTube node can upload a video, so you can download each clip's url and upload it with the generated title and description. We suggest uploading as private or unlisted first and reviewing. For TikTok and Instagram, use their official APIs or a scheduler you already pay for.

Can I do the same with Make or Zapier?

Yes. It's the same HTTP call: POST https://renderster.com/media with the X-API-Key header and the JSON body, then poll status_url. The clips API guide has the full request and response, and the Shorts tutorial shows the same job in the web app. API reference: /docs.