A client once asked me for a short screen recording of a bug. The capture was 212 MB for four minutes, which is what a retina display at 60 frames a second costs you, and their mail server bounced it twice before I worked out that the 25 MB limit in the error message was not the number I had to beat. Attachments are base64 encoded, so the file arrives about a third larger than it left. I needed to be under roughly 18 MB, not 25. The recording went out at 6 MB, 720p, no audio, and looked perfectly sharp, because a screen recording of a bug is mostly a static page with a cursor moving across it and that compresses beautifully. The useful lesson was not a setting. It was that every one of these jobs is the same three-line calculation, and once you can do it you stop guessing.
TL;DR: A quality level does not give you a file size, because a constant-rate factor is a quality target and the resulting size depends on how much motion the footage carries. To hit a hard limit, work backwards from it: target bitrate in kilobits per second is the size in bytes times 8, divided by the duration in seconds, divided by 1000. Then pick the resolution whose normal bitrate sits under that number. Dropping 1080p to 720p saves more than any quality slider, and dropping audio you do not need saves more than people expect. The video compressor on toolz.dev runs the encode through ffmpeg compiled to WebAssembly in your own browser tab, shows the estimate before it starts, and never uploads the file.
Why does a quality setting never promise you a size?
Because the two most common ways to compress a video answer different questions, and the one that produces better results is the one that cannot tell you the size in advance.
Target bitrate mode says: use 2 megabits per second, whatever that takes. The size is then arithmetic, exactly predictable, and the quality swings wildly. A still title card and a handheld shot of rain both get 2 Mbps, so the title card wastes most of it and the rain looks like wet gravel.
Constant rate factor mode says: hold this quality, spend whatever bits that needs. Easy frames get few bits, hard frames get many, and the picture stays visually even from start to finish. The size is whatever it is.
Every modern encoder recommends the second one for anything that is not being streamed live, and it is what the compressor here uses. The cost is that the number on the page before you press the button is an estimate, derived from the typical bitrate for that resolution and quality, and the real figure moves with the footage. A static screen recording routinely lands at half the estimate. Handheld footage of moving water can land over it. Confetti, snow, foliage in wind and camera grain are the four things that blow past any estimate, because all of them are close to random noise and noise is the one thing compression cannot do anything with.
What is CRF choosing when you pick a level?
The scale runs 0 to 51 for 8-bit H.264, where 0 is lossless and 51 is unwatchable, and the FFmpeg H.264 encoding guide puts the default at 23 and the sane working range at roughly 17 to 28. The property worth memorising is that the scale is logarithmic: a change of 6 roughly halves or doubles the bitrate. That single fact tells you what each level does before you try it.
The compressor offers three, not a slider, because the difference between CRF 26 and 27 is invisible while the difference between 23 and 33 is the entire point.
| Level | H.264 CRF | VP9 CRF | Audio | What it is for |
|---|---|---|---|---|
| Light | 23 | 31 | 160 kbps | Archive copies and footage you will edit again. Near enough visually lossless. |
| Balanced | 28 | 36 | 128 kbps | The ordinary answer. Roughly half the bitrate of light, and on a laptop screen you have to look for the difference. |
| Strong | 33 | 42 | 96 kbps | Hitting a hard limit. Artefacts begin to show on detailed footage, and nobody minds on a chat upload. |
The VP9 numbers are a separate scale, which is why they look unrelated. The light level's 31 is exactly what Google's VP9 encoding recommendations for video on demand list as the target quality for 1080p, and the rest of that table is worth keeping bookmarked: 32 for 720p, 33 or 34 for 480p, 15 for 4K.
Which saves more space, lower quality or fewer pixels?
Fewer pixels, by a wide margin, and it is not close.
Resolution is a two-dimensional quantity. Going from 1080p to 720p is not a third off, it is 2.07 million pixels down to 0.92 million, so the encoder has 56% fewer pixels to describe before it makes a single quality decision. The file follows, roughly. Going from 4K to 1080p removes three quarters of them.
Here is what a one-minute clip lands at, by source height and level, using the typical bitrates the tool estimates from. Audio is included.
| Source | Light | Balanced | Strong |
|---|---|---|---|
| 4K (2160p) | 106 MB | 61 MB | 35 MB |
| 1080p | 35 MB | 20 MB | 11 MB |
| 720p | 20 MB | 12 MB | 7 MB |
| 480p | 10 MB | 6 MB | 4 MB |
Read it across and down. Moving one step down the quality column saves about 43%. Moving one step down the resolution column saves about 42% as well, which looks like a tie until you notice that quality steps run out after three and cost you visible artefacts, while a resolution step costs nothing at all on the screen most people will watch on. A 1080p clip shown in a Slack message is being displayed in a box about 400 pixels wide.
The order to try, then: drop the resolution to whatever the viewer will realistically use, keep quality at balanced, and only reach for strong if you still have not made it.
How do you land under a hard limit like 8 MB?
Work backwards. The whole calculation is one line, and it is the only piece of video arithmetic worth learning.
# total bitrate (kbps) = target size (bytes) x 8 / duration (s) / 1000
#
# 8 MB, 45-second clip:
# 8,000,000 x 8 / 45 / 1000 = 1,422 kbps total
# minus 96 kbps of audio = 1,326 kbps for video
#
# 1080p strong is ~1,400 kbps video -> about 8.4 MB. Just over.
# 720p strong is ~800 kbps video -> about 5.0 MB. Comfortable.
#
# the equivalent single pass, if you have ffmpeg installed:
ffmpeg -i input.mp4 -c:v libx264 -crf 33 -preset fast \
-vf scale=-2:720 -c:a aac -b:a 96k \
-movflags +faststart -pix_fmt yuv420p output.mp4
Three things make this reliable in practice.
- Leave headroom. Aim for 80% of the limit. CRF does not hit a size target, and the one time it overshoots is the time you are sending the file.
- Count the encoding overhead if it is going by email. Base64 represents every 24 bits of input as 4 characters, by RFC 2045, so an attachment inflates by a third on the wire. A 25 MB mailbox limit is about 18 MB of actual file.
- Do not trust a number you remembered. Discord's free upload limit has been 8 MB, then 25 MB, then 10 MB, then 20 MB as of August 2026. Gmail has held at 25 MB for years. WhatsApp re-compresses anything you send regardless. Check the limit the day you need it, then do the arithmetic.
If the clip is longer than the thing you want to show, the better move is to cut it rather than squeeze it. Halving the duration halves the size at full quality, which no setting can match. The video trimmer will take the range out without re-encoding at all when the cut lands near a keyframe, and the result is byte-identical footage at half the size.
Does lowering the frame rate help?
Less than you would think, and it looks worse than anything else on the list.
The reason is that consecutive frames already compress against each other. A video codec stores one full frame and then describes the differences, so frame 31 in a 60 fps clip is nearly free, because it is almost identical to frame 30. Throwing it away does not save the bits you imagine it saves. At typical rates the saving is closer to linear than free, so 60 fps to 30 fps takes off perhaps a third rather than half, and 30 fps to 15 fps gives you visible judder on any camera movement.
There are two cases where it is the right call. A screen recording of mostly static content loses nothing legible at 15 fps, and that is exactly the case where you are usually trying hardest to get under a limit. And footage you are converting to an animation for a page, where the viewer is not watching motion so much as noticing it, survives 12 to 15 fps fine.
For everything with a person or a camera move in it, leave the frame rate alone and take the resolution down instead.
Should the audio survive?
Ask what the audio is for, because it is not free.
A 10-minute recording with audio at 128 kbps carries 9.6 MB of sound before the picture gets a single bit. If that audio is a silent screen capture with room hum in it, or music you are going to replace, or a voice track you have already transcribed, dropping it is the easiest saving available and it costs the viewer nothing. The compressor has a switch for exactly that, which passes -an and omits the audio stream entirely.
When the sound matters, the levels drop it from 160 to 128 to 96 kbps, which are the conventional points. 96 kbps AAC is adequate for speech and audibly thin on music. If you want the audio alone, as a file to transcribe or edit, the audio extractor pulls the track out without touching the video, and the audio converter will re-encode it on its own terms.
One detail catches people out. A video with no audio track plays silently in most players and fails to autoplay in a few old mobile browsers that expect a track to mute. If the clip is going into a web page, a silent 8 kbps track is sometimes safer than none, though every browser shipping today handles a video-only MP4 correctly.
Is WebM worth the extra wait?
It depends entirely on who opens the file.
VP9 in a WebM container lands roughly a quarter smaller than H.264 at a comparable visible quality. That is a real gain, and on your own site, where the only requirement is that a browser can play it, WebM is usually the better file. Chrome, Firefox and Edge have supported VP9 for a decade, and Safari has since version 14.
The cost shows up twice. VP9 encoding is slower than x264, substantially so in a browser, and one detail trips up anyone running the command by hand: VP9 only honours a quality target when the bitrate is explicitly zero. Pass -crf 36 on its own and the encoder quietly uses a default bitrate instead and ignores you. It needs -crf 36 -b:v 0, which is what the tool sends.
The second cost is everything that is not a browser. Chat apps, CMS upload fields, video editors, PowerPoint, the preview pane in a file manager, your client's phone: many of these accept MP4 and shrug at WebM. If the file is going to a person, send MP4 with H.264. If it is going into a page you control, WebM. That same split runs through the whole format question, which the remux guide covers from the conversion side.
Why does a compressed MP4 sometimes refuse to start playing?
Because of where the index ended up, and it is the one flag you should never leave off.
An MP4 keeps a table of contents describing where every frame starts. Written normally, the encoder discovers all of that as it goes and writes the table at the end of the file. For playback from a disk that is fine. Served over HTTP, it means the player cannot begin until it has the whole file, so a 40 MB video in a chat app or a CMS sits there doing nothing while it downloads, then starts.
-movflags +faststart does a second pass over the finished file and moves that table to the front. The encode takes a moment longer and the video starts playing after a second. Every MP4 the compressor produces has it.
Two more flags in that command are there for compatibility rather than size. -pix_fmt yuv420p forces 4:2:0 chroma subsampling, because a 4:2:2 or 4:4:4 MP4 is valid and refuses to play on a long list of hardware decoders. And the scale filter is written scale=-2:720 rather than scale=-1:720, because H.264 requires even pixel dimensions and -2 rounds the computed width to an even number. Ask for an odd width and the encode fails with "width not divisible by 2" rather than scaling to something close.
Why does compressing twice look so much worse?
Generation loss, and it is steeper than people expect because lossy compression is not idempotent.
The first encode throws away detail it judges the eye will not miss and leaves behind its own artefacts: slight blocking at edges, smoothed gradients, ringing around high contrast. The second encode has no way to know those artefacts are not the picture. It treats them as content worth preserving, spends bits describing them, and adds its own on top. Three rounds of balanced compression on the same clip looks worse than one round of strong, at a larger file size.
So the practical rules are short. Compress from the original every time, never from the copy you already made. If you need both a light archive version and a small version to send, make both from the source. And if a file has already been through a platform that re-compresses on upload, which is most of them, treat what you downloaded as a second generation already.
This is the same arithmetic that governs image compression and the reason a JPEG saved repeatedly turns to mud, and the same reason the PDF compressor works on the images inside a document rather than on the document as a whole.
Does the file leave your machine?
No, and for video that changes what the tool is usable for.
The encode runs through ffmpeg compiled to WebAssembly, executing in the browser tab. The file is read from your disk into page memory, encoded there, and handed back as a download. Open devtools, switch to the network panel, compress something, and watch: no request carries the video.
Three consequences follow.
Nothing is uploaded, so nothing is retained. No copy sits on a server waiting for a retention policy to delete it, because no copy was made. For an unreleased product demo, footage under NDA, or anything with a person in it who did not agree to a third-party upload, that is the difference between usable and not.
The limits are the browser's, not a plan's. The whole file goes into tab memory, so the page accepts up to 500 MB and caps a single pass at 30 minutes, and it checks both when you pick the file rather than after a four-megabyte engine download and two minutes of encoding. There is no queue, no watermark, no account and no size tier to buy.
The first run is slower. The ffmpeg WebAssembly bundle downloads once, which takes a few seconds, and is cached afterwards. The tool loads it on the first compression rather than when the page opens, so the page itself stays fast.
When is a desktop encoder the right tool?
When the numbers above stop being the constraint. A browser tab is a reasonable encoder and a bad video pipeline, and it is worth being clear about where the line falls.
Go native for files over 500 MB or clips over half an hour, where tab memory is the real limit. Go native for a batch, because 40 clips through a loop in a shell beats 40 trips through any interface. Go native when you need two-pass encoding to hit an exact size, which a single CRF pass cannot promise. And go native for hardware encoding, where a GPU will do in 20 seconds what WebAssembly takes four minutes over.
For one clip that needs to get under a limit in the next five minutes, on a laptop, without installing anything or handing the footage to a stranger, the browser is the faster path by a distance. That is the job the compressor is built for, alongside the converter for changing format and the image compressor for the same problem one dimension down.



