Telegram Bots

Handling Files and Media in Telegram Bots

Receive, send, store and process files in Telegram bots — file_id reuse, size limits, downloading safely, media groups, and keeping disk and memory under control.

On this page
  1. file_id: Telegram’s superpower
  2. Size limits
  3. Downloading files
  4. Sending files
  5. Processing media
  6. Keeping disk usage under control
  7. Safety and responsibility
  8. Summary

Photos, voice notes, documents, videos, stickers — media is a big part of Telegram, and many bots exist mainly to process it: converters, downloaders, archivers, moderation bots. Media handling has its own rules and limits, and doing it carelessly fills your disk or exhausts your memory. This article covers the essentials.

file_id: Telegram’s superpower

Every file Telegram stores has a file_id. When a user sends your bot a photo, the update includes its file_id, and you can send that same file anywhere by passing the ID — no download, no re-upload:

@router.message(F.photo)
async def echo_photo(message: Message):
    largest = message.photo[-1]              # photos come in several sizes
    await message.answer_photo(largest.file_id, caption="Here it is again!")

This makes resending instant and free. A few rules:

  • A file_id is specific to your bot. Another bot can’t use it.
  • Save file_ids you’ll reuse. If your bot sends the same welcome image to everyone, upload it once, store the returned file_id, and send by ID from then on.
  • file_unique_id is for deduplication. It’s stable across bots and time, so it’s the right key for “have I seen this file before?” — but it can’t be used to download or send a file.

Size limits

On Telegram’s public Bot API server:

Direction Limit
Bot downloads a file (getFile) 20 MB
Bot uploads a file 50 MB
Photo upload 10 MB

Users can send files up to 2 GB (more with Premium), so your bot will receive files it can’t download through the standard API. Handle this gracefully: check file_size before downloading and tell the user politely if it’s too large.

If you genuinely need bigger files, you can run your own local Bot API server — Telegram’s open-source telegram-bot-api — which lifts the download limit and allows uploads up to 2,000 MB. It’s a separate service you host, so it suits a VPS rather than a small bot plan.

Downloading files

Getting a file is a two-step process: call getFile to obtain a file_path, then download it. Libraries wrap this:

# aiogram 3
file = await bot.get_file(message.document.file_id)
await bot.download_file(file.file_path, destination=f"downloads/{message.document.file_unique_id}")
// grammY (with the files plugin: @grammyjs/files)
const file = await ctx.getFile();
const path = await file.download(`downloads/${file.file_unique_id}`);

Warning: The raw download URL has the form https://api.telegram.org/file/bot<token>/<file_path> — it contains your bot token. Never log it, send it to users or put it in a web page.

Stream to disk, not memory

Downloading into memory is fine for small images. For documents and videos, write straight to disk so a 20 MB file doesn’t become a 20 MB spike in RAM — or several at once when users send files concurrently. Most library download helpers accept a destination path; use it.

Sending files

You can send files three ways:

  1. By file_id — instant, for files already on Telegram.
  2. By URL — Telegram fetches it from the web (with its own size limits, lower than direct uploads).
  3. By upload — from disk or memory.
from aiogram.types import FSInputFile, BufferedInputFile

await message.answer_document(FSInputFile("reports/weekly.pdf"))
await message.answer_photo(BufferedInputFile(png_bytes, filename="chart.png"))

Uploads return a message containing the new file_id — store it if you’ll send the file again.

Albums

sendMediaGroup sends up to ten photos or videos as one album. It counts as one action rather than ten, which is kinder to Telegram’s rate limits and to your users’ chat history.

Processing media

Converting audio, compressing video, generating thumbnails and running OCR are CPU-intensive. A few practices keep your bot responsive:

  • Don’t block the event loop. Run tools like FFmpeg as subprocesses (asyncio.create_subprocess_exec in Python, child_process.spawn in Node.js), not synchronous calls.
  • Limit concurrency. Process a few files at a time with a semaphore or queue; ten simultaneous video conversions will saturate any modest CPU allocation.
  • Tell the user it’s working. Send a chat action (upload_document, record_video) or a “Processing…” message and edit it when done.
  • Time out. A malformed file can make a converter hang. Kill jobs that run too long.
sem = asyncio.Semaphore(2)

async def convert(src, dst):
    async with sem:
        proc = await asyncio.create_subprocess_exec(
            "ffmpeg", "-y", "-i", src, "-vn", "-b:a", "128k", dst,
            stdout=asyncio.subprocess.DEVNULL, stderr=asyncio.subprocess.DEVNULL,
        )
        await asyncio.wait_for(proc.wait(), timeout=120)

Keeping disk usage under control

Media bots fill disks faster than anything else. Plan cleanup from day one:

  • Delete temporary files as soon as a job finishes, in a finally block so failures clean up too.
  • Sweep old files with a scheduled job that removes anything older than a day in your downloads folder.
  • Don’t store what Telegram already stores. If you only need to resend a file, keep the file_id, not the file.
  • Watch the disk graph. A full disk makes databases fail and bots crash in confusing ways.

Kerit Cloud’s Telegram plans include 2 GB of NVMe storage on Free, 5 GB on Starter, 10 GB on Pro and 20 GB on Ultra — plenty for a well-behaved media bot, and disk is fast, which helps conversions.

Safety and responsibility

Bots that accept files from strangers should be careful:

  • Never execute uploaded files, and be cautious with archives (zip bombs) and documents with macros.
  • Check MIME types and extensions before processing, but don’t trust them blindly.
  • Respect copyright. Downloader bots that redistribute copyrighted media can get your bot reported and your hosting suspended. Kerit Cloud’s terms prohibit hosting pirated content.
  • Handle personal data with care. Photos and documents can contain sensitive information; delete them when you no longer need them.

Summary

Reuse files by file_id wherever possible, and use file_unique_id for deduplication. Respect the 20 MB download and 50 MB upload limits — or run a local Bot API server if you truly need more. Stream downloads to disk, keep your token out of download URLs, process media in limited-concurrency subprocesses, clean up temporary files, and keep an eye on disk usage.