Skip to main content

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.

No watermarkFree & unlimited
Upload limit

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.

Container

MP4 (H.264 + AAC)

Height cap

Fewer pixels for the same bitrate means each pixel gets more bits.

Audio

Dropping audio hands 96 kbps back to the picture.

Your video is never uploaded: it is encoded by ffmpeg compiled to WebAssembly, running in a worker in this tab. One thing does leave the browser — on the first encode the page downloads the ffmpeg core itself (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

Key facts about Compress video for Discord
Default ceiling10 MB — Discord's per-file limit on a free account; 50 MB (Nitro Basic) and 500 MB (Nitro) are one-click presets
The budget formulatarget bytes x 8 / 1000 / duration, times 0.94 for container overhead, minus the audio bitrate
Worked example10 MB across a 15-second clip = 5,592 kbps total, leaving 5,160 kbps for video after 96 kbps of audio
Two-pass, not CRFpass 1 analyses the whole clip and writes a stats log; pass 2 distributes the fixed bitrate using it
Measured runan 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 tookabout 6 seconds of wall time in a desktop browser, including the first-run engine download
WebM is slowerthe same clip and budget as VP8/WebM produced 1,496,098 bytes and took roughly 18 seconds
MP4 codecsH.264 (libx264, preset veryfast) with AAC audio, plus -movflags +faststart so it streams in the Discord player
WebM codecsVP8 (libvpx) with Opus audio. VP9 is never used — it is present in this ffmpeg build but fails at runtime and writes empty files
Corrective roundsup to two, each re-running two-pass at the budget scaled by the measured overshoot times 0.92
Refusal floorbelow 60 kbps of video the encode is refused rather than run, with the arithmetic shown
Input ceiling200 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. 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. 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. 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. 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. 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. 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. 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.

Specs & compatibility
Input formatsMP4, WebM, MOV, AVI, MKV, M4V — anything the browser can read metadata from and ffmpeg can decode
Input ceiling200 MB, the shared client-side video cap (D-011)
Output containersMP4 (H.264 + AAC) or WebM (VP8 + Opus)
Height capsoriginal, 1080p, 720p or 480p; never upscales, and always rounds to an even height for yuv420
Audio96 kbps, or dropped entirely to hand those 96 kbps back to the picture
Duration probea hidden video element, with the seek-to-end fallback for WebM files that carry no duration header
Threadingsingle-threaded ffmpeg.wasm — no SharedArrayBuffer, so no COOP/COEP headers are needed sitewide
Speed expectationroughly real-time to 3x real-time per pass on a desktop, and two passes are always run
Cancellationa running encode can be cancelled, which terminates the worker and frees the heap
Account or installnone — 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.
Because CRF is a quality target and cannot promise a size. The encoder holds the quality constant and lets the bitrate vary with the content, so the same CRF gives wildly different file sizes for a static screen recording and a fast-panning gameplay clip. Hitting a hard limit that way means encoding, checking, adjusting and encoding again, with each attempt costing a full pass. Starting from the limit and deriving a bitrate budget usually gets there in one two-pass run, and the measured example did exactly that: 8.54 MB down to 1.46 MB against a 1.5 MB ceiling, first try.
10 MB per file on a free account, 50 MB with Nitro Basic and 500 MB with Nitro; all three are presets on this page. Server boosts no longer raise the per-file upload limit, so a boosted server does not help a free account. If you are unsure which tier applies, aim at 10 MB — a file under the free limit uploads on every tier. Note that the tool targets binary megabytes, so 10 MB here means 10,485,760 bytes.
With a fixed average bitrate, a single pass has to guess how to spend the budget as it goes and typically wastes bits on the opening seconds before it learns what the clip looks like. Two-pass runs the encoder over the whole clip first, writes a statistics log describing where the motion and complexity are, and then encodes for real using that log to distribute the same total bitrate intelligently. On a clip with a quiet start and a busy ending — most gameplay highlights — the difference is obvious. The cost is that the clip is encoded twice, which is why the progress bar runs to 45% and then continues.
No. The encoding happens in this tab through ffmpeg compiled to WebAssembly; your file is written into an in-memory filesystem that only this page can see, and both passes read and write there. The one genuine network request is the engine itself: the first encode of your session downloads ffmpeg-core.js and a roughly 32 MB ffmpeg-core.wasm from the public jsDelivr CDN. Your video is not part of that request — it is a public npm package being fetched the way any script is. After it is cached, a run makes no network requests at all.
The WebM option encodes VP8, not VP9, and VP8 works correctly here. VP9 is compiled into the pinned single-threaded ffmpeg core and lists in its encoder table, but it fails at runtime on this build in every configuration tested — aborting, crashing the worker, or exiting successfully having written a header-only file with no frames. Writing an empty file and calling it a result is exactly the silent failure this tool is built to avoid, so VP9 is never selected. VP8 produces a real, universally playable WebM; it is simply larger at equal quality and about three times slower to encode than H.264.
It is the tool refusing to waste your time. Below roughly 60 kbps of video bitrate there is no resolution and no encoder setting that produces something worth watching, so when the arithmetic lands there the page shows the calculation — clip length, ceiling, audio, resulting kbps — and declines to run rather than spending minutes producing mush. A 30-minute recording inside 10 MB is 46 kbps in total, which is the case that triggers it. Trim the clip, drop the audio, or post it somewhere without the limit and share the link.
View all

Updated

We use anonymous analytics to improve ToolChamp. No personal data is stored or sold. Privacy Policy