n8nvideo-automationffmpeg

Clip, Caption, and Reformat Video in One n8n Workflow API Chain

·Javid Jamae·10 min read
Clip, Caption, and Reformat Video in One n8n Workflow API Chain

A 45-minute webinar recording lands in Google Drive, and someone on the team spends the next hour pulling four clips out of it, padding each one to vertical, and pasting captions on top. The standard fix is to stitch together a transcription tool, a clipper, a caption app, and a scheduler, which means four accounts, four failure points, and the same file uploaded four times. The tools aren't the unit of work. The jobs are, and there are only three of them.

Quick answer: An n8n clip, caption, reformat video workflow is three chained jobs rather than three separate products: trim the source at exact timestamps, pad the trimmed clip to 1080x1920, then burn the SRT into the padded clip. Done by hand in FFmpeg, that's ffmpeg -ss/-to, then scale+pad, then the subtitles filter, with the file living on your disk between passes and the caption timings shifted to match the cut. Sent to FFmpeg Micro, it's three API calls chained by webhook, so n8n orchestrates the jobs and never carries the video bytes.

The pipeline is three jobs, and the order matters

The clip-caption-reformat chain fails most often on ordering, not on syntax. Each job's output becomes the next job's input, and two of the three steps change the geometry or timeline the next step depends on.

Burn captions before you pad, and the subtitle track gets scaled along with the video, which pushes the text down into the letterbox bar or shrinks it to unreadable. Pad before you trim, and you've encoded 45 minutes of black bars to throw away 44 of them. The order that survives contact with real files is trim, then reformat, then caption.

Job 1: trim the clip at the timestamps you want

Trimming is where accuracy is either free or expensive, depending on whether you re-encode. The stream-copy version is nearly instant because it doesn't decode anything:

ffmpeg -ss 00:12:34 -to 00:13:34 -i webinar.mp4 -c copy clip.mp4

That command snaps to the nearest keyframe at or before 12:34, so on a source encoded with a 10-second GOP your clip can start up to 10 seconds early. For repurposing, where the whole point is that the hook lands in the first second, that's a defect. Re-encode when the cut point has to be exact:

ffmpeg -ss 00:12:34 -to 00:13:34 -i webinar.mp4 \
  -c:v libx264 -crf 20 -preset veryfast -c:a aac -b:a 128k clip.mp4

The API equivalent is one job submission with the same start and end, plus a callback URL that n8n hands you. Exact parameter names for each job type are in the docs:

{
  "input": "https://www.googleapis.com/drive/v3/files/1AbC.../?alt=media",
  "operation": "trim",
  "start": "00:12:34",
  "end": "00:13:34",
  "webhook": "https://your-n8n.example.com/webhook-waiting/8f21c0"
}

Job 2: reformat to 9:16 before anything gets burned in

Reformatting a 1920x1080 interview to 1080x1920 is a scale followed by a pad, and the two filters have to agree about the aspect ratio or FFmpeg will stretch faces. force_original_aspect_ratio=decrease keeps the geometry honest:

ffmpeg -i clip.mp4 -vf \
  "scale=1080:1920:force_original_aspect_ratio=decrease,pad=1080:1920:-1:-1:color=black" \
  -c:a copy vertical.mp4

A 16:9 source padded to 9:16 leaves roughly 420 pixels of black above and below the video. That dead space is where your caption block and your hook text go, which is why this job runs before the caption burn. If you'd rather crop to fill the frame than letterbox it, the Reframe to Any Aspect Ratio blueprint does both modes, and the same job is callable from a workflow.

Job 3: burn the SRT into the finished frame

Burning captions is one filter, and what breaks it is timing, not styling. SRT timestamps are absolute to the source file, so a cue written for 00:12:40 in the webinar points 754 seconds past the end of a 60-second clip that was cut at 12:34. Every cue has to shift back by the clip's start offset before it's usable.

ffmpeg -i vertical.mp4 -vf \
  "subtitles=clip.srt:force_style='FontName=Inter,Fontsize=16,MarginV=90,Outline=2'" \
  -c:a copy final.mp4

MarginV=90 pushes the text up out of the bottom of the frame, which matters because TikTok and Reels both overlay their own UI in the lower band. If your captions arrive offset from the audio for a different reason, the fix is -itsoffset rather than editing the file, covered in FFmpeg subtitle delay isn't a slider drag. For clips where you don't have an SRT at all, the Auto Captions blueprint transcribes and burns in one pass with a review step before the render.

Wiring the chain in n8n so the video never enters n8n

The design rule for this chain is that n8n passes URLs, never bytes. The n8n community forum has a long-running thread about a roughly 1 GB video where a Read Binary File node on the FFmpeg output takes the whole instance down. That failure has nothing to do with FFmpeg. It's a workflow engine holding a media file in memory. Pass a URL in, take a webhook back, and the problem stops existing.

The node chain end to end:

  1. Google Drive Trigger watching a folder, set to poll every minute. Dropbox Trigger works identically if that's where your recordings land.
  2. HTTP Request to submit the trim job, with the Drive download URL as the input and {{ $execution.resumeUrl }} as the webhook.
  3. Wait node set to resume "On Webhook Call." Most builds get this wrong: the execution parks at zero cost until FFmpeg Micro calls back, so a four-minute render doesn't hit any HTTP timeout.
  4. HTTP Request to submit the reformat job, using the output URL that the trim webhook returned as this job's input.
  5. Wait, again on webhook.
  6. HTTP Request to submit the caption burn, then a final Wait.
  7. Google Drive Upload or a Slack message with the finished URL.

Loop steps 2 through 7 over a list of timestamp pairs from Google Sheets and one webinar becomes six clips without anyone opening an editor. More on that queue pattern: Google Sheets is a fine video processing queue with n8n.

For anyone still planning to shell out to a local binary: the Execute Command node is disabled by default in n8n v2.0 and later, because arbitrary shell execution isn't safe in a shared instance, and on n8n Cloud it was never an option. Any guide telling you to install FFmpeg next to n8n describes a product that no longer ships that way.

Stitched tool chain vs one media API

A stitched tool chain and three chained API jobs both produce a captioned vertical clip. The difference is moving parts and failure modes.

Stitched tool chainThree chained API jobs
Accounts to manageTranscriber, clipper, caption app, schedulerOne
File transfers per clipUpload and download at each hopZero through n8n, URLs only
Failure surfaceAny tool's UI change breaks the automationHTTP status codes and a webhook
Long rendersHTTP timeout or a polling loop you wroteWait node parked on a webhook
Caption timing after a cutManual re-sync per clipOffset passed with the job
Style controlWhatever the tool's presets allowFull `force_style` on the burn

Pitfalls that break this workflow in production

The problems that show up on clip six of a batch are rarely the ones you hit on clip one. Wire around these before you run at volume.

Audio drift after a stream-copy trim is the most common. If your source has variable frame rate, which screen recordings and Zoom exports usually do, -c copy preserves the original timestamps and the audio can lead the video by a fraction of a second that compounds across a longer clip. Re-encode the trim and it disappears.

Fonts are the second. The subtitles filter renders with fonts available to the renderer, not fonts on your laptop, so FontName=Inter falls back to a default if Inter isn't there. Test one clip and look at it before you queue 40.

The third is the retry loop. If a job fails and your n8n error branch resubmits it, make sure it uses the original source URL rather than the failed job's output URL, which may not exist. An IF node checking the job status field before the next HTTP Request node is enough.

Last, Google Drive download URLs expire and Drive sometimes serves an HTML confirmation page instead of the file for large items. Generate a fresh direct link inside the workflow rather than storing one, or the job fails with a decode error on a file that's actually HTML.

When this build is the wrong call

Three chained media jobs are the right shape when the source video is the content and you're cutting it down. They're the wrong shape when you're generating video from a design, meaning a branded template with dynamic text fields, animated lower-thirds, and a designer-owned layout that changes monthly. That's a template-editor product's job, and trying to express it as FFmpeg filter chains means you'll rebuild a layout engine badly.

This also isn't the build for one clip a week. If a human is already opening the file, picking the moment by ear, and posting it, the automation costs more attention than it saves. The math turns around at a few clips a week, and hard once you're running clips for multiple clients, which the content repurposing workflows page walks through.

FAQ

Can I run FFmpeg inside n8n instead of calling an API?

Running FFmpeg inside n8n is not practical on current versions. The Execute Command node is disabled by default in n8n v2.0 and later and has never been available on n8n Cloud, so a self-hosted instance with a custom Docker image is the only path, and that instance owns the encoding CPU, disk, and memory pressure of every render. Our end-to-end n8n clip workflow guide covers the hosted alternative.

How do I chain jobs when each render takes minutes?

Chaining long jobs in n8n works through the Wait node in "On Webhook Call" mode. Submit the job with {{ $execution.resumeUrl }} as the callback, and the execution parks until FFmpeg Micro posts back with the output URL, which sidesteps HTTP timeouts entirely. Polling in a loop also works, but it burns executions and adds latency before your workflow notices.

Do the captions need to be an SRT file?

An SRT file is the usual input for burning captions, and it needs its cue timings rebased to the clip's start time rather than the source video's. If you don't have a transcript, generate captions from the clip itself after trimming, which avoids the offset problem because the cues are already relative to the clip. The video captions use case page covers both routes.

Will a 45-minute source file break the workflow?

A 45-minute source file is fine as long as it never passes through n8n as binary data. The trim job reads from the source URL directly, and the only thing crossing your workflow engine is a JSON body with a URL and two timestamps. Trouble starts when a Read Binary File or Download node pulls the render into an n8n execution's memory.

Can I add a music bed or a hook overlay to the same chain?

Adding a music bed or hook text is a fourth job in the same chain, submitted the same way as the first three. The pattern doesn't change: one job per operation, each one taking the previous output URL as its input, which is also how background music gets added.

Build the three jobs once and every long recording that hits your Drive folder turns into finished vertical clips without a person in the loop. Sign up free and run the trim job against one of your own files to see what comes back on the webhook.

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.

Software EngineeringVideo ProcessingFFmpegCloud ArchitectureAPI DesignAutomation

Skip the command line

The Auto Captions blueprint transcribes your video and burns the captions in. You just review the transcript.

Run it (free)