Compress video for Discord
Pick the upload limit you have to fit under. The clip's duration becomes a bitrate budget, the budget is encoded two-pass, and the result is measured against the limit before you download it.
Discord accepts 10 MB per file on a free account, 50 MB on Nitro Basic and 500 MB on Nitro. Encoding a 500 MB target in the browser is possible but slow — the 10 MB case is what this page is built for.
MP4 (H.264 + AAC)
Fewer pixels for the same bitrate means each pixel gets more bits.
Dropping audio hands 96 kbps back to the picture.
ffmpeg-core.js and a ~32 MB ffmpeg-core.wasm) from the public jsDelivr CDN at cdn.jsdelivr.net/npm/@ffmpeg/[email protected]. That request carries no part of your file — only the CDN sees that a browser asked for the engine. After that it is cached and every pass runs offline.Discord rejects your clip because of its size, not its quality — so a quality setting is the wrong control. A CRF of 28 produces three megabytes of a talking head and forty megabytes of gameplay from the same slider position, which is why guessing at CRF until something fits wastes so many encodes. This page starts from the limit instead. It reads the clip's duration, divides the byte ceiling by it to get a total bitrate, subtracts the audio track and a container-overhead allowance, and hands the remainder to a genuine two-pass encode so the encoder can spend the budget where the motion actually is. Then it measures the finished file and, if it still overshot, re-runs with the budget scaled by the miss. Everything happens in this tab through ffmpeg compiled to WebAssembly.
Key facts about Compress video for Discord
| Default ceiling | 10 MB — Discord's per-file limit on a free account; 50 MB (Nitro Basic) and 500 MB (Nitro) are one-click presets |
|---|---|
| The budget formula | target bytes x 8 / 1000 / duration, times 0.94 for container overhead, minus the audio bitrate |
| Worked example | 10 MB across a 15-second clip = 5,592 kbps total, leaving 5,160 kbps for video after 96 kbps of audio |
| Two-pass, not CRF | pass 1 analyses the whole clip and writes a stats log; pass 2 distributes the fixed bitrate using it |
| Measured run | an 8.54 MB 6-second 640x360 clip to a 1.5 MB ceiling finished at 1,458,149 bytes in one two-pass run |
| How long that took | about 6 seconds of wall time in a desktop browser, including the first-run engine download |
| WebM is slower | the same clip and budget as VP8/WebM produced 1,496,098 bytes and took roughly 18 seconds |
| MP4 codecs | H.264 (libx264, preset veryfast) with AAC audio, plus -movflags +faststart so it streams in the Discord player |
| WebM codecs | VP8 (libvpx) with Opus audio. VP9 is never used — it is present in this ffmpeg build but fails at runtime and writes empty files |
| Corrective rounds | up to two, each re-running two-pass at the budget scaled by the measured overshoot times 0.92 |
| Refusal floor | below 60 kbps of video the encode is refused rather than run, with the arithmetic shown |
| Input ceiling | 200 MB — ffmpeg.wasm holds the whole clip in a single WebAssembly heap in this tab |
What happens to your file
Your video is never uploaded: it is encoded by ffmpeg compiled to WebAssembly, running in a worker inside this tab, and both passes read and write files in an in-memory filesystem that exists only in this page. One thing does leave the browser, and it is worth being exact about. On the first encode of your session the page downloads the ffmpeg engine itself — ffmpeg-core.js and a roughly 32 MB ffmpeg-core.wasm — from the public jsDelivr CDN at cdn.jsdelivr.net/npm/@ffmpeg/[email protected]. That request carries the engine only; no part of your file is in it, and jsDelivr learns nothing except that a browser asked for a public npm asset. The core is then cached and every subsequent pass runs with no network access at all. The finished clip is a blob: URL in this tab and is discarded when you close it.
About this tool
- 1
Pick the limit that applies to you
10 MB for a free Discord account, 50 MB on Nitro Basic, 500 MB on Nitro. The page defaults to 10 MB because that is the case that needs a tool.
- 2
Drop the clip in
Up to 200 MB. The duration and dimensions are read immediately by a hidden video element, before any encoding starts.
- 3
Read the bitrate budget
The grey strip shows the arithmetic: the ceiling divided by the duration, minus audio, minus overhead, equals the kbps the encoder will be given. If the number is red, the clip is too long for the limit and it says so instead of running.
- 4
Cap the height if the budget is tight
Under about 1,500 kbps, 1080p is a waste — the same bits spread over 720p or 480p look considerably better. The height cap never upscales.
- 5
Drop the audio if you do not need it
That returns 96 kbps to the picture, which matters on short ceilings and is invisible on long ones.
- 6
Encode and check the achieved size
Pass 1 runs to 45%, pass 2 to 95%. The verdict strip states the measured output size against the ceiling, and the encode log lists the bitrate each run used.
- 7
Play it before you post it
The result is previewed in place. If the motion looks smeared, cap the height one step lower and re-run — same ceiling, better-spent bits.
| Input formats | MP4, WebM, MOV, AVI, MKV, M4V — anything the browser can read metadata from and ffmpeg can decode |
|---|---|
| Input ceiling | 200 MB, the shared client-side video cap (D-011) |
| Output containers | MP4 (H.264 + AAC) or WebM (VP8 + Opus) |
| Height caps | original, 1080p, 720p or 480p; never upscales, and always rounds to an even height for yuv420 |
| Audio | 96 kbps, or dropped entirely to hand those 96 kbps back to the picture |
| Duration probe | a hidden video element, with the seek-to-end fallback for WebM files that carry no duration header |
| Threading | single-threaded ffmpeg.wasm — no SharedArrayBuffer, so no COOP/COEP headers are needed sitewide |
| Speed expectation | roughly real-time to 3x real-time per pass on a desktop, and two passes are always run |
| Cancellation | a running encode can be cancelled, which terminates the worker and frees the heap |
| Account or install | none — no signup, no watermark, no desktop app |
- Trim before you compress. Halving the clip doubles the bitrate budget for everything that remains, which is the only free quality in this whole process.
- Gameplay and camera pans are the expensive cases; a static screen recording will look fine at a bitrate that makes an action clip unwatchable.
- MP4 is the safer choice for Discord — it previews inline everywhere and encodes about three times faster than VP8 in this build.
- A clip longer than about three minutes cannot be made watchable inside 10 MB at any resolution; trim it or upload it somewhere else and post the link.
- The first encode of a session pauses while the 32 MB WebAssembly engine downloads; every encode after that starts immediately.
- If the verdict is amber after three runs, cap the height at 480p and drop the audio before raising the limit — those two levers are worth more than any encoder flag.
- Byte ceiling converted to a bitrate budget from the real duration
- Genuine two-pass encoding, not a CRF guess
- Up to two corrective runs when the first overshoots
- H.264/AAC MP4 with faststart, or VP8/Opus WebM
- Visible encode log with the bitrate each run used
- Refuses impossible budgets instead of producing mush
- Posting a clip in a Discord server on a free account, where the per-file limit is 10 MB.
- Fitting a gameplay highlight under the limit without installing a desktop encoder.
- Getting a screen recording small enough to attach to a bug report in a Discord support channel.
- Preparing a short clip for any upload form with a hard megabyte ceiling, not just Discord.
- Shrinking a phone video before sending it over a messaging app with its own limit.
- Testing how a clip looks at a given bitrate before committing to a longer export elsewhere.
Related tools
View allWorks well with this6
More in Audio & Video12
Updated