ffmpegvideo-encodingapi

Compress video for the web: bitrate, codecs, and one-call presets

·Javid Jamae·8 min read
Compress video for the web: bitrate, codecs, and one-call presets

Most people compress a web video by dragging the bitrate slider down until the file is small enough, then wonder why it looks like a JPEG from 2006. The file size is fine. The playback is worse than it needs to be. And half the time the video still won't start playing until it fully downloads.

Quick answer: To compress video for the web, encode with H.264 (libx264) using CRF quality instead of a fixed bitrate, pick a preset like medium, downscale to your target resolution, and add -movflags +faststart so the file streams before it finishes downloading. One command does it locally; a video compression API does the same job in one call with no FFmpeg to install.

Conventional wisdom says smaller video means lower bitrate. That's partly right. Bitrate does control size. But for the web, the thing that makes a video small and watchable isn't a lower bitrate, it's letting the encoder spend bits where the eye actually notices. That's what CRF encoding does, and it's why a well-compressed 1080p clip can look sharp at a third the size of a bitrate-capped one.

Bitrate vs CRF: why quality-based compression wins for web

CRF (Constant Rate Factor) tells the encoder a quality target and lets the bitrate float scene by scene. Fixed bitrate wastes bits on easy frames and starves complex ones. For web delivery, CRF is the better default.

With libx264, CRF runs 0 to 51. Lower is higher quality and bigger. A few anchors that hold up in practice:

  • CRF 18: visually lossless, large files. Use for archival, not web.
  • CRF 23: the x264 default. Good quality, reasonable size.
  • CRF 26–28: the web sweet spot. Noticeably smaller, still clean on a phone or laptop.

The -preset flag is a separate lever: it trades encode time for compression efficiency, not quality. veryslow squeezes out a smaller file at the same CRF than ultrafast, but takes far longer. medium is the sane default; slow is worth it for content you encode once and serve many times.

Pick a codec: H.264, H.265, VP9, or AV1

Choose the codec by where the video plays, not by which one compresses best on paper. Here's the honest state of things:

  • H.264 (libx264). Plays everywhere: every browser, every phone, every embed. Largest files of the modern codecs, zero compatibility risk. This is the correct default for a general web audience.
  • H.265 / HEVC (libx265). Roughly 25–50% smaller than H.264 at the same quality, but browser support is patchy and it carries licensing baggage. Good for controlled apps, risky for open web.
  • VP9. Royalty-free, strong compression, well supported in Chrome and Firefox. Common on YouTube.
  • AV1. The best compression of the four and royalty-free, but slow to encode and still spotty on older devices.

If you're serving a landing page or a public embed, encode H.264 and move on. If you control the player and the audience, H.265 or AV1 buys real bandwidth savings.

The FFmpeg command to compress video for the web

Here's the command that does it right, with faststart so the video plays during download instead of after:

ffmpeg -i input.mp4 \
  -c:v libx264 -crf 26 -preset slow \
  -vf "scale=-2:1080" \
  -c:a aac -b:a 128k \
  -movflags +faststart \
  output.mp4

What each part earns you:

  • -crf 26 -preset slow: quality-based compression at the web sweet spot.
  • -vf "scale=-2:1080": downscale to 1080p height; -2 keeps the aspect ratio and forces an even width (H.264 requires even dimensions).
  • -c:a aac -b:a 128k: standard web audio; 128 kbps AAC is transparent for most content.
  • -movflags +faststart: moves the MP4 moov atom to the front so browsers can start playback immediately. Skip this and your video buffers to 100% before the first frame shows.

Not sure what you're feeding in? Run ffprobe first to check the source resolution, codec, and bitrate so you're not upscaling or re-encoding something that's already fine.

One API call instead: a video compression API

The FFmpeg command works great until you need it inside a product, an n8n flow, or an agent, and you hit the part nobody warns you about: installing and running FFmpeg. Binaries, versions, a server that stays up, and long jobs you have to babysit.

A video compression API is the same operation with none of the operations. You submit a job with your compression settings, poll or get a webhook, and download the output. No FFmpeg to install, no servers to run.

curl -X POST https://api.ffmpeg-micro.com/jobs \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "input": "https://example.com/input.mp4",
    "operation": "compress",
    "settings": { "codec": "h264", "crf": 26, "preset": "slow", "height": 1080 }
  }'

The request shape and exact parameters live in the docs; the point is that one call replaces a whole media microservice. Here's the tradeoff laid out plainly:

FFmpeg CLI on your own boxFFmpeg Micro API
SetupInstall binary, manage versionsNone, just an API key
ScalingYou run and scale the serverManaged, no servers to run
Long jobsYou babysit the processPoll or webhook when done
Fits a workflowShell out and hopeWorks with n8n, Make, and Zapier

Bitrate targets and presets by resolution

If your delivery needs a fixed bitrate (adaptive streaming ladders, hard bandwidth caps), skip CRF and target a rate. Rough H.264 starting points for web:

ResolutionTarget video bitrateAudio
1080p4,000–6,000 kbps128 kbps AAC
720p2,000–4,000 kbps128 kbps AAC
480p800–1,500 kbps96 kbps AAC

For a true target bitrate, use two-pass encoding so the encoder plans the whole file:

ffmpeg -y -i input.mp4 -c:v libx264 -b:v 4000k -pass 1 -an -f null /dev/null && \
ffmpeg -i input.mp4 -c:v libx264 -b:v 4000k -pass 2 \
  -c:a aac -b:a 128k -movflags +faststart output.mp4

Two passes take roughly twice as long but hit your size budget far more accurately than one pass. For most web pages, CRF is simpler and looks better at a given size. Reach for two-pass only when the byte budget is non-negotiable.

Common pitfalls when compressing web video

These are the ones that actually bite people:

  • Forgetting +faststart. The most common web-video mistake. Without it the browser downloads the entire file before playing. Always add it for progressive-download MP4.
  • Odd dimensions. libx264 rejects odd width or height. Use scale=-2:1080 instead of scale=-1:1080 to force an even value.
  • Cranking bitrate instead of CRF. A high fixed bitrate on a simple video wastes bytes; a low one on a busy scene smears. CRF avoids both.
  • Upscaling. Compressing a 720p source to 1080p adds size and zero detail. Check the source with ffprobe first.
  • Wrong codec for the audience. Shipping H.265 to the open web means some visitors see a black frame. Default to H.264 unless you control the player.

When NOT to use a video compression API

Be honest about the fit. If you're compressing one video by hand on your laptop, the FFmpeg CLI is free and takes 30 seconds, so just run the command above. If you need frame-accurate creative editing with a timeline and effects, that's an editor, not an API. And if every millisecond of latency matters for a real-time stream, encode at the edge rather than round-tripping to a job API.

The API earns its keep when compression is a step in a pipeline, running dozens or thousands of times, inside code or a no-code workflow, where installing and scaling FFmpeg is the real cost. Same logic applies whether you're shrinking clips for email under Gmail's 25 MB limit or squeezing uploads under the WhatsApp 16 MB cap.

FAQ

What's the best FFmpeg command to compress video for the web?

Encode H.264 with -c:v libx264 -crf 26 -preset slow, downscale with -vf "scale=-2:1080", use -c:a aac -b:a 128k for audio, and add -movflags +faststart so it streams during download. CRF 26 hits the web quality-vs-size sweet spot.

What bitrate should I use for web video?

For quality-based encoding, use CRF and let bitrate float. If you need a fixed target, aim for about 4,000–6,000 kbps for 1080p, 2,000–4,000 kbps for 720p, and 800–1,500 kbps for 480p, all with 128 kbps AAC audio.

H.264 or H.265 for web video?

Use H.264 for anything public: it plays in every browser and on every device. H.265 compresses 25–50% smaller but has patchy browser support and licensing costs, so reserve it for apps where you control the player and audience.

Why does my compressed video still buffer before playing?

You almost certainly forgot -movflags +faststart. Without it, the MP4's metadata (moov atom) sits at the end of the file, so the browser must download the whole thing before playback starts. Re-encode with faststart to fix it.

Can I compress video without installing FFmpeg?

Yes. A video compression API like FFmpeg Micro runs the same FFmpeg operations behind a REST call, so you submit a job and download the output with no binaries, versions, or servers to manage. It also works from n8n, Make, and Zapier.

Ready to skip the install and the babysitting? Sign up free and compress your first video with one API call.

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

Ready to process videos at scale?

Start using FFmpeg Micro's simple API today. No infrastructure required.

Get Started Free