How to save images using Python Telegram Bot library v21

I’m working on a Telegram bot that should save images when users send them to the bot. I’m using the newest version of python-telegram-bot (v21) but having trouble getting it to work properly.

Here’s my current code:

import os
import asyncio
from telegram import Update
from telegram.ext import Application, MessageHandler, filters, ContextTypes

BOT_TOKEN = os.environ['BOT_TOKEN']

async def save_image(update: Update, context: ContextTypes.DEFAULT_TYPE):
    print("Processing image download")
    photo_file = await update.message.effective_attachment[-1].get_file()
    downloaded_file = await photo_file.download_to_drive()
    return downloaded_file

if __name__ == '__main__':
    app = Application.builder().token(BOT_TOKEN).build()
    
    image_handler = MessageHandler(filters.Document.IMAGE, save_image)
    app.add_handler(image_handler)
    
    app.run_polling()

The issues I’m facing:

  • When I use filters.Document.ALL and send a PDF, the function gets called but I can’t find where the file gets saved
  • When I send JPG images, my handler function never gets triggered at all
  • Most online examples are for older versions and don’t work with v21

I’ve tested these filter options:

  • filters.Document.IMAGE
  • filters.Document.JPG
  • filters.Document.ALL

What’s the correct filter to use for receiving JPG images? Am I missing something important in my setup?

your filter’s wrong for jpg images. telegram sends photos as filters.PHOTO, not document filters. use filters.PHOTO and grab the highest resolution with update.message.photo[-1]. document filters only catch images sent as files, not regular photos.

Had this exact problem when I built my first Telegram bot last year. Telegram treats photos and image documents totally differently. Phone photos get sent through the photo pipeline and compressed automatically. But if someone sends the same image as a file attachment, it goes through the document pipeline instead. Your code only catches document images - that’s why regular JPG photos aren’t triggering your handler. You need separate handlers for both. For the download path issue - without specifying a path, files just get dumped in your working directory with random names. I always create a downloads folder first and use file_unique_id as the filename to avoid conflicts. Handle both scenarios since users send images differently based on their habits.

You’re mixing up photo handling with document handling. When users send photos through Telegram, they come through as compressed photos, not documents. Your download_to_drive() method needs a file path parameter too - it doesn’t know where to save otherwise. Here’s what works: async def save_image(update: Update, context: ContextTypes.DEFAULT_TYPE): photo = update.message.photo[-1] # Get highest quality file = await photo.get_file() file_path = f"downloads/{file.file_unique_id}.jpg" await file.download_to_drive(file_path) print(f"Saved to {file_path}"). Use filters.PHOTO for regular photos and filters.Document.IMAGE if you want uncompressed files sent as documents. Most people send photos the normal way, so you’ll probably want both handlers for complete coverage.