n8n video automation: build the clip workflow end to end

You have a 40-minute podcast recording in Google Drive and you want eight captioned vertical clips out of it by tomorrow. n8n already handles the trigger, the transcript, the sheet, and the upload. The part that falls over is the middle: the actual cutting, cropping, and caption burn.
Quick answer: n8n video automation works when n8n orchestrates the pipeline and something else does the rendering. Build it as: trigger on a new file, get a timestamped transcript, pick clip windows with an LLM or a rules node, send one HTTP request per clip to a video API like FFmpeg Micro, then resume on a webhook and publish. n8n never touches the video bytes, so nothing times out and no FFmpeg binary is needed.
Where n8n video automation actually breaks
Conventional wisdom: n8n can't do video because there's no FFmpeg node. That's partly right, and most first attempts die exactly there. But the missing binary isn't the real blocker. The blocker is that n8n's execution model assumes a step finishes in a second or two, while a 45-second 1080p render takes 20 to 90 seconds of wall clock, and eight of them in a loop takes minutes.
Stack the constraints and you can see why the Execute Command approach falls apart:
- The Execute Command node is self-hosted only. It isn't available on n8n Cloud.
- Even self-hosted, the official
n8nio/n8nimage doesn't ship FFmpeg. You'd build a custom image and maintain it. - Binary data in n8n moves through the workflow as base64 in memory by default. A 400 MB source file passed between four nodes is a memory problem, not a video problem.
- The HTTP Request node's timeout option defaults to 300000 ms. A long synchronous render blows through it and the execution fails with a socket hangup, not a useful error.
So the fix isn't a bigger n8n container. It's not rendering inside n8n at all. Once the render lives behind an async API, n8n goes back to doing what it's good at: routing JSON between services.
The clip-repurposing workflow, end to end
Six nodes, one loop, no local FFmpeg. Here's the shape before the detail.
| Step | Node | What it does |
|---|---|---|
| 1 | Google Drive Trigger | Fires on a new file in `/inbox` |
| 2 | HTTP Request | Whisper transcription with segment timestamps |
| 3 | Basic LLM Chain | Returns clip windows as JSON |
| 4 | Split In Batches | One item per clip |
| 5 | HTTP Request | Submit the render job, pass a resume URL |
| 6 | Wait (On Webhook Call) | Pauses until the job posts back |
| 7 | HTTP Request + Sheets | Upload the output, log the row |
1. Trigger on the source file
Use the Google Drive Trigger node watching a specific folder, polling every minute. Grab the file's webContentLink or generate a signed URL. Don't download the file into n8n. You want a URL you can hand to other services, not 400 MB sitting in an execution's memory.
If your inputs arrive by hand or in bursts, a spreadsheet works fine as the queue instead of a trigger. We wrote that pattern up in Google Sheets is a fine video processing queue with n8n.
2. Get a transcript with real timestamps
Send the audio URL to OpenAI's /v1/audio/transcriptions with response_format: verbose_json and timestamp_granularities[]: segment. You get back segments with start and end in seconds, which is the whole point. Word-level timestamps cost nothing extra and make caption timing much tighter.
Whisper wants audio, not a 400 MB MP4. Extracting the audio track first is one operation and cuts upload time roughly in half on a typical podcast recording, since a 40-minute 1080p MP4 is around 500 MB and its AAC track is around 38 MB.
3. Pick the clip windows
Feed the transcript segments into a Basic LLM Chain with a Structured Output Parser and ask for an array like this:
[
{ "start": 754.2, "end": 801.6, "title": "Why retries make it worse", "hook": "..." },
{ "start": 1290.0, "end": 1338.4, "title": "The 15-minute cap", "hook": "..." }
]
Two rules that save you real rework. Constrain duration in the prompt (between 30 and 60 seconds), because models happily return 4-minute "clips." And snap start back to the nearest segment boundary in a Code node, because a clip that opens mid-word reads as broken no matter how good the content is.
If your source has no speech to transcribe, cut on visuals instead. FFmpeg scene detection gives you cut points from the picture itself.
4. Cut, crop, and caption in one call
This is the node that used to require FFmpeg. Add a Split In Batches node with batch size 1, then an HTTP Request node inside the loop that submits one job per clip to api.ffmpeg-micro.com. Set your API key as a header credential, method POST, body JSON. The exact route and payload for the operation you want are in the docs, and you can shape the request in the playground first and paste it straight into the node.
What you're describing in that one request is a chain that would otherwise be several FFmpeg passes: trim to the window, crop to 9:16, scale to 1080x1920, burn the captions, encode.
5. Wait without timing out
Do not poll in a loop with a Wait node set to 10 seconds. That burns executions and still races the render.
Instead, put a Wait node in "On Webhook Call" mode right after the submit, and pass {{ $execution.resumeUrl }} as the job's callback URL in step 4. n8n pauses the execution, stores it, and resumes the moment the job posts its result back. A 90-second render costs you zero polling requests and zero timeout risk. The full recipe, including what to do when the callback never arrives, is in how to fix n8n timeout errors when processing video.
6. Publish and log
The callback carries the output URL. Pass it to the YouTube node, a Buffer or Blotato HTTP call, or an S3 upload, then append a row to Google Sheets with the source file, clip title, output URL, and duration. That log is what lets you re-run a single failed clip instead of the whole 40-minute source.
FFmpeg CLI vs one API call
Both do the same job. One of them you have to install, version, and host.
| Operation | FFmpeg CLI | With FFmpeg Micro |
|---|---|---|
| Trim a window | `ffmpeg -ss 754.2 -to 801.6 -i in.mp4 -c copy clip.mp4` | one parameter in the job body |
| Crop to 9:16 | `ffmpeg -i clip.mp4 -vf "crop=ih*9/16:ih,scale=1080:1920" v.mp4` | one parameter |
| Burn captions | `ffmpeg -i v.mp4 -vf "subtitles=clip.srt:force_style='FontSize=28'" out.mp4` | one parameter |
| Run it | Install FFmpeg, host a worker, handle concurrency and cleanup | POST from an HTTP Request node |
The CLI commands are correct and worth knowing. The reason they don't belong in n8n is everything around them: a machine to run them on, a queue when eight clips land at once, disk cleanup, and a version of FFmpeg new enough that subtitles is compiled in. That's a service, and you didn't want to build a service. You wanted clips.
Pitfalls that cost people an afternoon
Stream copy cuts land on keyframes. -c copy is instant but seeks to the nearest keyframe, so a clip asked to start at 754.2s may actually start at 752.0s. If exact starts matter, re-encode. If they don't, copy and save the CPU.
Google Drive webContentLink URLs are not always fetchable by third parties. Files set to "Anyone with the link" work; files inherited from a restricted folder return HTML, and your render job fails with a decode error on what looks like a valid URL. Test the URL with curl -I before you trust it.
Split In Batches with batch size 1 is sequential. Eight clips at 60 seconds each is eight minutes of wall clock. Submit all jobs first, then collect callbacks, and the same eight clips finish in about the time of the slowest one.
Vertical crop cuts off whoever isn't centered. A two-person podcast in a 16:9 frame loses a head to crop=ih*9/16:ih. Use a blurred 9:16 background fill instead, which keeps the full frame and reads better on Reels anyway.
Caption font size is resolution-relative. FontSize=24 looks fine on a 720p preview and is unreadable at 1080x1920 on a phone. Set it after you know the output height, not before.
When not to build this in n8n
If your app already has a backend and you're rendering clips on user request, skip n8n and call the API directly from your code. The orchestration layer buys you nothing when there's one linear path and you already have a place to put the code.
If you need a human in the loop picking clips on a timeline, you want an editor, not a pipeline. FFmpeg Micro is an API, not an editor.
If you're doing full adaptive-bitrate streaming delivery with a player and DRM, that's Mux or Cloudflare Stream territory. Clip repurposing is file in, file out, and that's a different problem.
And if you're building this inside an agent loop rather than a visual workflow, use the MCP server and let Claude call the render as a tool. Same jobs, no n8n canvas.
FAQ
Can n8n process video without FFmpeg installed?
Yes. n8n doesn't need FFmpeg if the rendering happens behind an HTTP API. The HTTP Request node sends a job, a Wait node in webhook mode holds the execution, and the output URL comes back in the callback. No binary, no custom Docker image, and it works on n8n Cloud where the Execute Command node isn't available.
How do I automate cutting a long video into clips in n8n?
Transcribe the audio with Whisper using segment timestamps, pass those segments to an LLM node that returns start and end times as structured JSON, then loop with Split In Batches and submit one render job per window. The full walkthrough for the clipping logic is in turn long-form video into Shorts, Reels, and TikToks automatically.
Why does my n8n workflow time out when processing video?
Because the HTTP Request node waits for a synchronous response and its timeout defaults to 300000 ms, while renders and uploads regularly exceed that. Switch to async: submit the job, return immediately, and resume the execution from a webhook callback using {{ $execution.resumeUrl }}.
Does this work in Make or Zapier too?
Yes. The pattern is identical because it's just HTTP. Make uses a webhook module to catch the callback and Zapier uses a Catch Hook trigger in a second Zap. FFmpeg Micro works with n8n, Make, and Zapier the same way, since all three are calling the same REST endpoint.
What does it cost to run this on a weekly podcast?
One 40-minute source producing eight 45-second captioned vertical clips is eight render jobs a week. There's a free tier to start and usage-based pricing after that, broken down on the pricing page. Compare that against a $20/month always-on worker plus the hours you spend on FFmpeg version drift.
Build the workflow with the free tier first and see how the callback pattern behaves on your real files before you commit to a plan. Sign up free and paste your first render request into an HTTP Request node.
About Javid Jamae
Founder & CEO at FFmpeg Micro
Javid is a software engineer, author, and entrepreneur with over 25 years of professional software development experience across enterprise, startup, and consulting environments. He founded FFmpeg Micro to make video processing accessible to developers through a simple, automation-first REST API.
You might also like

Google Sheets Is a Fine Video Processing Queue with n8n
Build a Google Sheets video processing queue in n8n: rows trigger FFmpeg API jobs, and a webhook writes the output URL back to the row. No server needed.

Add an Intro and Outro to Video Automatically (n8n + FFmpeg)
Add an intro and outro to video automatically with FFmpeg or one API call. Concat demuxer vs concat filter, an n8n batch recipe, and mismatch bugs to avoid.

FFmpeg blackdetect: Find Black Frames and Split Video Automatically
FFmpeg blackdetect finds black frames using duration, pixel, and picture thresholds. Read the log, turn ranges into cut points, and split video automatically.
Ready to process videos at scale?
Start using FFmpeg Micro's simple API today. No infrastructure required.
Get Started Free