FFmpeg Compress Video for Telegram: The Command, Explained

Sep 23, 2026

On Telegram, the file size cap is almost never why your video needs re-encoding. Telegram's FAQ states the per-file limit as "up to 2 GB in size each (or 4 GB with Premium)" — a ceiling most clips never come near. The real reasons are documented in Telegram's own protocol docs: making the file arrive as a playable video rather than a file icon, keeping it from arriving as a silent looping animation, and getting under the much smaller limits that apply to bots. Every choice below is anchored to a specific line in that documentation.

The command

ffmpeg -y -i input.mkv -c:v libx264 -b:v 2000k -pass 1 -an -f mp4 /dev/null
ffmpeg -i input.mkv -c:v libx264 -b:v 2000k -pass 2 -c:a aac -b:a 128k output.mp4

On Windows, replace /dev/null with NUL.

Three things there are Telegram-specific rather than generic advice: the MP4 output, the H.264 codec, and the fact that pass two re-encodes audio instead of dropping it.

Why MP4, not the container you already have

Telegram accepts any file. The FAQ says you can send "files of any type (doc, zip, mp3, etc)" — the extension is not an upload gate.

But whether a file is rendered as a video is a separate question, and the Bot API answers it in one sentence in the sendVideo description:

"Use this method to send video files, Telegram clients support MPEG4 videos (other formats may be sent as Document)."

That one sentence is what the docs offer for the most common complaint about Telegram video: you upload a .mkv or .avi, it transfers fine, and the chat shows a grey file row with a download arrow instead of a player. Nothing failed. Telegram's sendVideo note says a file that is not an MPEG4 video may be sent as a Document — so this is the likely cause, not a certainty.

Two qualifiers: that wording is from the Bot API docs, and "may be sent as Document" is not a published blacklist. But it is the only official statement on the subject, and it points one direction. If your source is a QuickTime file, the container change alone may be enough — see MOV to MP4.

Why H.264 specifically

The MTProto constructor documentAttributeVideo carries a video_codec field, documented as:

video_codec  flags.5?string  Codec used for the video, i.e. "h264", "h265", or "av1"

Note the "i.e." — those are examples, not a closed whitelist, so this is not proof that nothing else works. What it does mean is that libx264 produces the codec with the fewest unknowns attached, and Telegram publishes no reason to prefer H.265 or AV1 for a normal chat send. There is exactly one documented case where Telegram requires H.265, and it is not chat: posting a Story through the Bot API, under Variations below.

Why you must not strip the audio

This is the choice that separates a Telegram command from a generic one, and it explains a symptom people describe constantly without ever getting an answer: "my MP4 turned into a GIF." The relevant flag is on inputMediaUploadedDocument:

"nosound_video | flags.3?true | Whether to send the file as a video even if it doesn't have an audio track (i.e. if set, the documentAttributeAnimated attribute will not be set even for videos without audio)"

Read the parenthesis carefully: for videos without audio, documentAttributeAnimated is set unless something overrides it. A silent video is treated as an animation by default — which is why it comes back as a small, looping, muted tile instead of a video with a scrub bar.

The Bot API corroborates this from the other side: sendAnimation is the method for "animation files (GIF or H.264/MPEG-4 AVC video without sound)". In Telegram's model, H.264 video without sound is a kind of animation.

The practical rule: do not put -an in the output pass. It belongs on the first run only. Carrying it into the output produces a file Telegram classifies as an animation. If your source genuinely has no audio, Telegram's help centre documents no user-side control — the override exists only at the protocol level.

Try it right here

Runs in your browser. Your file is not uploaded anywhere.

Loading tool…

That preset outputs H.264 in MP4, the combination the two rules above point at. For manual control over resolution and bitrate, the video compressor exposes both, and all Clapr tools are listed there.

What each flag does

  • -c:v libx264 — encode video with x264, producing H.264, one of the three codecs named in video_codec.
  • -b:v 2000k — the target video bitrate; see the arithmetic below.
  • -an (pass one only) — no audio in the first run.
  • -f mp4 /dev/null — force the format for the first run's output.
  • -c:a aac -b:a 128k — the audio stream Telegram needs in order to treat this as a video.
  • output.mp4 — the MPEG4 container the sendVideo note points at.

Flag names and defaults move between FFmpeg releases, so confirm anything surprising against your own build with ffmpeg -h encoder=libx264. More command breakdowns are in the FFmpeg guides hub.

Hitting a size target on purpose

If you need a specific size — a bot upload, a Story, an enormous source — turn the target into a bitrate:

total bitrate (kbit/s) = target size (MB) × 8192 ÷ duration (seconds)

That 8192 is one arithmetic convention — 1024 kilobytes per megabyte, 8 kilobits per kilobyte — and not a Telegram figure; Telegram's documentation publishes no byte count for its limits. Get the duration from ffprobe input.mkv.

For a 90-second clip aimed at 45 MB: 45 × 8192 ÷ 90 = 4096 kbit/s total. Subtract the audio — at -b:a 128k, video gets 4096 − 128 = 3968, which is your -b:v.

The ceiling is not an exact number you can compute against either. The FAQ writes "2 GB" as a string and never publishes a byte count, and the MTProto config docs describe that ceiling as extrapolated from the allowed number of file parts times 524288.

Variations

Sending through a bot. Bot limits are a completely different set of numbers from the user-facing 2 GB. The Bot API's "Sending files" section gives "50 MB for other files" on multipart uploads and "20 MB max for other types of content" when Telegram fetches an HTTP URL. Each send* method repeats "this limit may be changed in the future".

The bot has to download it, not send it. getFile says "For the moment, bots can download files of up to 20MB in size." A bot can send 50 MB and only retrieve 20 MB — if your pipeline downloads, target 20 MB. Running your own Bot API server changes both sides: "Download files without a size limit." and "Upload files up to 2000 MB." Telegram writes 2000 MB, not 2 GB.

Posting a Story via the Bot API. The one place with a hard spec. InputStoryContentVideo requires video "of the size 720x1280, streamable, encoded with H.265 codec, with key frames added each second in the MPEG4 format, and must not exceed 30 MB", duration "0-60" seconds. That is the Bot API requirement; Telegram publishes nothing equivalent for Stories posted in the app.

Only the container is wrong. If the video is already H.264, remux instead of re-encoding. FFmpeg's documentation says stream copy is "useful for changing the elementary stream count, container format, or modifying container-level metadata. Since there is no decoding or encoding, it is very fast and there is no quality loss." Read that scope literally: it cannot change codec, resolution, or bitrate.

ffmpeg -i input.mkv -c copy output.mp4

The bitrate is too low to look acceptable. Scale down so the bits cover fewer pixels: -vf scale=-2:720 before the output filename.

Troubleshooting

It sent, but appears as a file with a download arrow. The Bot API's sendVideo note is the documented possibility here — "Telegram clients support MPEG4 videos (other formats may be sent as Document)" — and may is the word Telegram uses, so treat it as the likely cause rather than a rule. Re-running so the output is MP4/H.264 removes the one variable the docs name.

It plays, but loops silently like a GIF. No audio track, so documentAttributeAnimated was applied. Check for a stray -an in the output pass. More on the size side of this in Telegram video too large.

The upload finished but the post never appeared in my channel. Documented behaviour: "When sending videos to big channels, Telegram will automatically convert them, generating multiple versions in multiple qualities and formats". Because that takes time, those videos "will not be sent immediately" — they "will be added to the schedule queue". Telegram does not publish what counts as a "big" channel.

The upload crawls. The documented throttle, FLOOD_PREMIUM_WAIT_X, carries a threshold: "This error can only be received when the user has uploaded tens of gigabytes or more." A slow one-off upload is not that.

I found a 1.5 GB limit on telegram.org. That is telegram.org/blog/files-on-steroids, dated March 25, 2015: "Many of you love Telegram for the ability to send huge files up to 1.5 Gb." Old post, still ranking. The FAQ figure is current — see Telegram's file size limit.

FAQ

What is the best FFmpeg command to compress video for Telegram? Two-pass x264 into MP4 with the audio re-encoded, not dropped. Adjust -b:v to your target using target MB × 8192 ÷ duration in seconds, minus your audio bitrate.

Why does my video show up as a file instead of playing in Telegram? Because Telegram clients support MPEG4 videos, and other formats, per the Bot API, "may be sent as Document". Re-encode to H.264 in an MP4 container.

Why did my MP4 turn into a GIF on Telegram? It has no audio track. Telegram's protocol docs state that for videos without audio the documentAttributeAnimated attribute is applied unless the nosound_video flag overrides it, and the Bot API classes "H.264/MPEG-4 AVC video without sound" as an animation. Keep audio in the output.

Do I even need to compress for Telegram? Usually not for the cap — the FAQ says "up to 2 GB in size each (or 4 GB with Premium)". Compress when you are going through a bot (50 MB multipart, 20 MB by URL, 20 MB to download), posting a Story via the Bot API (30 MB), or genuinely over the ceiling.


Cited from telegram.org/faq, faq_premium, the Bot API, api/files and api/config, checked 16 September 2026. Telegram has changed these numbers before — verify against the official pages before relying on them.

Clapr team

Clapr team

FFmpeg Compress Video for Telegram: The Command, Explained | Clapr Blog