The Telegram Bot Video Size Limit Isn't 50 MB. It's Three Caps.

Your bot works on test clips and then dies on a real one. sendVideo comes back with Request Entity Too Large, or the Telegram node in n8n throws a 400, and the file sitting on disk is 74 MB. Telegram is not going to raise that ceiling for you, so the file has to come down to meet it.
Quick answer: The telegram bot video size limit is 50 MB per file when your bot uploads withmultipart/form-data, and only 20 MB when you hand Telegram a URL and let it fetch the video itself. You can lift the ceiling to 2000 MB by self-hosting the Telegram Bot API server, which means running and maintaining another service; the alternative is to read the clip's duration withffprobe, set the video bitrate to(384000 / duration_in_seconds) - audio_bitratekbps so the output lands under a 48 MB ceiling, and re-encode with libx264. If you'd rather not ship an FFmpeg binary inside your bot, send the clip to FFmpeg Micro as one API call and pass the result tosendVideo.
Telegram's 50 MB cap is really three different caps
The Bot API applies a different ceiling depending on how the bytes reach Telegram, and most "50 MB" answers only mention one of them. This is the part that bites automation builders, because n8n, Make, and Zapier workflows tend to pass URLs around rather than binary data, and the URL path is the strictest one.
| What your bot is doing | Ceiling | Where it shows up |
|---|---|---|
| Uploading bytes with `multipart/form-data` | 50 MB | `sendVideo`, `sendDocument`, `sendAudio` |
| Passing an HTTPS URL for Telegram to fetch | 20 MB | `sendVideo` with a URL string |
| Passing an HTTPS URL for a photo | 5 MB | `sendPhoto` |
| Downloading a file a user sent your bot | 20 MB | `getFile` |
| Resending something already on Telegram | no limit | `file_id` reuse |
| Uploading through a self-hosted Bot API server | 2000 MB | any send method |
A bot can only download files up to 20 MB through getFile, no matter how large the file was when a user sent it, which is why "just have the bot re-upload what the user posted" falls apart on long videos. And the 2000 MB figure from the self-hosted server is real, but it costs you a Docker service, an API ID and hash from my.telegram.org, and a local file path handoff instead of a normal upload. The thread on the telegram-bot-api repo asking whether uploads up to 4 GB are supported has been open long enough that treating self-hosting as the only answer is a choice, not a requirement.
Read the file before you encode it
Compression targets are arithmetic, and the arithmetic needs duration. Pull it with ffprobe in one call, along with the current size and bitrate so you know how far you have to travel:
ffprobe -v error \
-show_entries format=duration,size,bit_rate \
-select_streams v:0 -show_entries stream=codec_name,width,height \
-of default=noprint_wrappers=1 input.mp4
A 12-minute 1080p screen recording at 6 Mbps comes back as roughly 540 MB. That is an 11x reduction to fit under 50 MB, which tells you immediately that bitrate alone won't save it. You're going to drop resolution too.
Compute the bitrate budget for a 48 MB ceiling
Aim for 48 MB, not 50. MP4 container overhead, the moov atom, and muxer variance all add bytes after the encoder has hit its target, and it's never clear whether a platform means 50,000,000 bytes or 52,428,800. A 48 MB decimal target gives you about 8 percent of slack in either reading.
48 MB is 384,000 kilobits. So:
total_kbps = 384000 / duration_seconds
video_kbps = total_kbps - audio_kbps
For that 12-minute clip, 384000 / 720 gives 533 kbps total. Subtract 96 kbps for AAC audio and you have 437 kbps of video. Nobody watches 1080p at 437 kbps, so scale down as well: below about 1500 kbps keep 720p, below about 800 kbps go to 854x480, and below 400 kbps drop to 640x360 and accept it. Telegram plays back in a phone-sized viewport anyway.
Two-pass when you must hit the number
Two-pass x264 is how you land on a file size rather than near it. The first pass writes a stats file, the second spends the budget where the motion is:
DUR=$(ffprobe -v error -show_entries format=duration -of csv=p=0 input.mp4)
TOTAL=$(echo "384000 / $DUR" | bc)
AUDIO=96
VIDEO=$((TOTAL - AUDIO))
ffmpeg -y -i input.mp4 -c:v libx264 -b:v ${VIDEO}k -vf scale=-2:720 \
-preset medium -pass 1 -passlogfile tg_$ -an -f mp4 /dev/null
ffmpeg -i input.mp4 -c:v libx264 -b:v ${VIDEO}k -vf scale=-2:720 \
-preset medium -pass 2 -passlogfile tg_$ \
-c:a aac -b:a ${AUDIO}k -movflags +faststart output.mp4
The -passlogfile tg_$ matters if your bot ever handles two videos at once. Without it, both jobs write to ffmpeg2pass-0.log in the working directory and corrupt each other's stats.
CRF with a hard cap when you have headroom
When the source is already close to the line, say 60 MB, two passes is wasted wall clock. Use CRF with a ceiling instead and take one pass:
ffmpeg -i input.mp4 -c:v libx264 -crf 28 -maxrate 900k -bufsize 1800k \
-preset veryfast -c:a aac -b:a 96k -movflags +faststart \
-fs 48M output.mp4
-fs 48M is a hard stop: FFmpeg quits writing at 48 MB. That protects you from an overshoot, but it truncates the video rather than compressing it further, so treat a truncated output as a signal to fall back to the two-pass path, not as a success.
-movflags +faststart moves the moov atom to the front of the file. Skip it and supports_streaming=true on sendVideo does nothing useful, because the Telegram client has to pull the whole file before playback starts.
When the clip is genuinely too long, split it
Some videos can't be compressed into 48 MB and stay watchable. A 90-minute webinar at 48 MB is 71 kbps total, which is a slideshow. Split it instead, using the segment muxer with stream copy so no re-encode happens:
ffmpeg -i input.mp4 -c copy -map 0 \
-f segment -segment_time 600 -reset_timestamps 1 \
part_%03d.mp4
Pick segment_time from the measured bitrate, not from a round number of minutes. At 3000 kbps, 48 MB buys you 128 seconds, so -segment_time 128. The catch with -c copy is that the segment muxer cuts on keyframes, so a requested 128-second segment becomes whatever the next keyframe allows, sometimes 20 percent longer and therefore 20 percent larger. Either leave a wider margin, target 40 MB per part, or re-encode with -force_key_frames "expr:gte(t,n_forced*128)" so the cut points exist where you asked for them.
Then send the parts in order with Part 1/5 in the caption. Telegram has no concept of a multi-part video, so the numbering is the only thing telling the recipient not to watch them out of order.
Doing this without FFmpeg inside your bot
Running FFmpeg next to your bot is fine until the bot lives somewhere that won't have it. n8n disabled the Execute Command node by default in v2.0 for security reasons, its distroless image broke the usual "apt-get install ffmpeg" Dockerfile patch, and there's a live feature request asking n8n to just bundle the binary. On Make and Zapier there was never a shell to begin with. Even where you can install it, routing a 50 MB binary through an n8n execution is how instances run out of memory.
This is where the work moves out of the bot. Send FFmpeg Micro the source URL and the same encoder arguments you'd have typed locally, get back a URL, and hand that to sendVideo. No binaries, no servers to run, no 12-minute encode blocking your webhook handler:
curl -X POST https://api.ffmpeg-micro.com/v1/jobs \
-H "Authorization: Bearer $FFMPEG_MICRO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"input": "https://example.com/raw-clip.mp4",
"args": "-vf scale=-2:720 -c:v libx264 -b:v 437k -maxrate 500k -bufsize 1000k -c:a aac -b:a 96k -movflags +faststart",
"output": "telegram-ready.mp4"
}'
Check the docs for the current field names, and try the arguments against your own clip in the playground before you wire the job into a workflow. The free tier covers enough jobs to find out whether 437 kbps at 720p looks acceptable for your content. Passing URLs instead of binary data is the same pattern that fixes Google Drive video steps in n8n.
Pitfalls that cost people an afternoon
A handful of Telegram bot send failures look like platform bugs and aren't:
- Passing an HTTPS URL to
sendVideoand sizing the output for 50 MB. Telegram fetches at 20 MB for video. If your bot passes URLs, your encode target is 19 MB, not 48. - Omitting
-movflags +faststartand then wondering whysupports_streaming=truemakes no difference. - Two concurrent two-pass encodes sharing
ffmpeg2pass-0.log. Always set-passlogfile. - Cutting audio to 64 kbps while leaving the video at 1080p. Audio is a rounding error in your budget; resolution isn't.
- Re-uploading the same file on every send. Telegram returns a
file_idafter the first successful upload, and resending byfile_idhas no size limit and no upload cost. - Assuming the source is the problem when a user-sent video fails.
getFilecaps at 20 MB, so your bot may not be able to download the file at all, which is a different error from not being able to send it.
FAQ
How do I send a video larger than 50 MB with a Telegram bot?
You have two workable options: compress the video below 50 MB before calling sendVideo, or self-host the Telegram Bot API server, which raises the upload limit to 2000 MB. Compression is the faster path for most bots because it needs no new infrastructure, and for a talking-head or screen-recording clip under about 20 minutes it produces a file people will actually watch.
Why does my bot fail at 20 MB when the limit is 50 MB?
The 20 MB failures happen when Telegram is doing the downloading rather than your bot doing the uploading. Passing a URL to sendVideo caps at 20 MB, and getFile caps at 20 MB for files your bot receives. Upload the bytes yourself with multipart/form-data to get the full 50 MB.
What bitrate gets a video under 50 MB?
Total bitrate in kbps should be 384000 divided by the video's duration in seconds, which targets a 48 MB file and leaves room for container overhead. Subtract your audio bitrate, usually 96 kbps for AAC, to get the video bitrate. A 5-minute clip gets 1280 kbps total, a 20-minute clip gets 320 kbps and needs to be scaled down to 640x360 to stay watchable.
Does compressing hurt quality enough to matter for Telegram?
Telegram clients play video in a phone-sized viewport, and Telegram may transcode again on its side for streaming, so a 720p file at 800 kbps to 1200 kbps looks essentially the same in the app as the 1080p master. The quality loss becomes obvious below roughly 400 kbps, or when fine text in a screen recording stops being legible. Checking the result with VMAF scoring is more reliable than eyeballing it.
Is the Telegram limit the same as other platforms?
No, every platform picks its own number and its own rules for measuring it. WhatsApp caps at 16 MB for media messages, Gmail at 25 MB per attachment, Webflow at 30 MB for background video, and the Whisper API at 25 MB per request. The encode math is identical in all of them; only the number in the numerator changes.
Point one job at a clip that's currently too big, watch what 48 MB actually looks like, and wire it into your bot from there. Sign up free and the first compress runs on the free tier.
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.
You might also like

The Webflow video size limit isn't your plan. It's 30 MB, flat.
The Webflow video size limit is 10 MB per upload and 30 MB for background video, on every plan. Target-size math and the FFmpeg commands that fit the cap.

Convert Video to Animated WebP with FFmpeg (10x Smaller Than GIF)
Convert video to animated WebP with FFmpeg: the libwebp flags that matter, quality and frame rate trade-offs, transparent alpha, looping, and GIF fallbacks.

FFmpeg container error? It's the subtitle track: -c:s mov_text
FFmpeg's codec not currently supported in container error is a subtitle mux failure. Fix it with -c:s mov_text, burn in bitmap subtitles, or switch to MKV.
Ready to process videos at scale?
Start using FFmpeg Micro's simple API today. No infrastructure required.
Get Started Free