Every time you upload a video to an online trimming service, that service has your video. For personal clips, that might be acceptable. For work content, screen recordings with sensitive data, or anything under NDA, uploading to a third party is a non-starter.
Browser-based video trimming that runs entirely client-side solves this. The video never leaves your machine. No upload, no server processing, no privacy concerns.
How browser-based trimming works
Modern browsers have two key APIs that enable this:
MediaSource API allows JavaScript to feed video data to a <video> element, enabling seeking to precise frame positions for setting trim points.
FFmpeg.wasm is a WebAssembly port of FFmpeg that runs entirely in the browser. It provides the same trimming, encoding, and muxing capabilities as desktop FFmpeg, but in a sandboxed browser environment.
The workflow:
- Load the video into memory using the File API
- Display it in a video player with frame-accurate seeking
- Let the user set start and end points
- Pass the video and trim points to FFmpeg.wasm
- FFmpeg trims without re-encoding (using -c copy for fast, lossless trimming)
- Return the trimmed video as a downloadable blob
const { createFFmpeg, fetchFile } = FFmpeg;
const ffmpeg = createFFmpeg({ log: true });
await ffmpeg.load();
ffmpeg.FS('writeFile', 'input.mp4', await fetchFile(videoFile));
await ffmpeg.run('-i', 'input.mp4', '-ss', startTime, '-to', endTime, '-c', 'copy', 'output.mp4');
const data = ffmpeg.FS('readFile', 'output.mp4');
const blob = new Blob([data.buffer], { type: 'video/mp4' });
Keyframe-accurate vs. frame-accurate trimming
The -c copy flag means no re-encoding. It simply copies the video and audio streams from the start point to the end point. This is fast (nearly instant for most clips) but has a limitation: it can only cut at keyframe boundaries.
Keyframes (I-frames) occur every 1-5 seconds in most videos. If your trim point falls between keyframes, the output will start at the nearest preceding keyframe, potentially including 1-4 seconds of unwanted content at the beginning.
For frame-accurate trimming, you need to re-encode the portion between the trim point and the nearest keyframe. This is slower but precise:
ffmpeg -i input.mp4 -ss 00:00:03.500 -to 00:00:08.200 -c:v libx264 -c:a aac output.mp4
The trade-off: keyframe-accurate is instant but imprecise. Frame-accurate is precise but takes seconds to minutes depending on the video.
The UX of trim point selection
A good video trimmer needs:
Visual timeline. A thumbnail strip or waveform showing the video content at a glance. This lets users navigate to the right area quickly.
Frame stepping. Arrow keys or buttons to step forward/backward one frame at a time for precise selection.
Handle dragging. Draggable start and end handles on the timeline. The selected region should be visually highlighted.
Preview. The ability to play only the selected region before committing to the trim. Nothing is more frustrating than trimming, waiting for processing, and discovering you were off by a second.
Timecode display. Show the current position, start point, end point, and duration of the selection in both timecode (HH:MM:SS.mmm) and frame number.
Why local processing matters
Consider what people trim:
- Screen recordings of internal tools (may contain customer data, credentials)
- Meeting recordings (confidential discussions)
- Security camera footage (sensitive locations)
- Personal videos (private content)
Uploading any of these to a web service means trusting that service with the content. Client-side processing eliminates that trust requirement entirely. The video exists only in your browser's memory.
I built a video trimmer at zovo.one/free-tools/video-trimmer that runs entirely in the browser using FFmpeg.wasm. Set trim points visually, preview the result, and download -- all without your video touching any server. It supports both fast keyframe-accurate trimming and precise frame-accurate trimming.
I'm Michael Lip. I build free developer tools at zovo.one. 500+ tools, all private, all free.
Top comments (0)