How to save images using Python Telegram Bot library (v21+)

Objective: I want to create a bot that can save photos when users send them to the chat.

I’m working with the newer version of python-telegram-bot (v21) and having trouble finding good examples. Most tutorials online are for older versions and don’t work with the current API.

My current implementation:

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

BOT_TOKEN = os.getenv('BOT_TOKEN')

### **Image Saver Function**
async def save_image(update: Update, context: ContextTypes.DEFAULT_TYPE):
    print("Image handler triggered!")
    photo_file = await update.message.effective_attachment[-1].get_file() # Get highest quality
    saved_file = await photo_file.download_to_drive()
    return saved_file

### **Bot Setup**
if __name__ == '__main__':
    app = ApplicationBuilder().token(BOT_TOKEN).build()

    image_handler = MessageHandler(filters.Document.IMAGE, save_image)
    app.add_handler(image_handler)

    app.run_polling()

Issues I’m facing:

  • PDF files seem to work with filters.Document.ALL but save to unknown locations
  • JPEG images don’t trigger the handler at all (no print output)
  • Version compatibility problems with older code examples

Filter types I’ve tested:

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

Main questions:

  • What’s the correct filter for handling JPEG files?
  • Am I missing something in my setup?

Any guidance would be really helpful since the library documentation doesn’t cover this use case thoroughly.

You’re mixing up how Telegram handles different image uploads. Photos sent through the regular photo button come through as photo messages, not documents. Your handler only catches images sent as documents (using the paperclip attachment). I hit this same issue migrating from v20 to v21. You need two handlers - one for filters.PHOTO and another for filters.Document.IMAGE. The photo handler should use update.message.photo[-1] while the document handler uses update.message.document. That download issue happens because download_to_drive() without arguments saves to system temp. Always specify the full path like await photo_file.download_to_drive('./images/photo.jpg') or you’ll lose files.

yeah, telegram sees normal photos and docs differently. go with filters.PHOTO for pics and filters.Document.IMAGE for uploads. also, make sure to set a download path, or it’ll just dump stuff into temp folders that get cleaned up. use await photo_file.download_to_drive('./saved_images/image.jpg').

Your problem is you’re only using filters.Document.IMAGE, which only catches images sent as files, not regular photos. When users send photos normally through Telegram, they’re handled differently than document uploads. You need a separate handler for regular photos using filters.PHOTO. Here’s what worked for me: async def save_photo(update: Update, context: ContextTypes.DEFAULT_TYPE): photo = update.message.photo[-1]; file = await photo.get_file(); file_path = f"photos/{file.file_id}.jpg"; await file.download_to_drive(file_path); add both handlers in your application. The download_to_drive() method without parameters saves to a temp directory by default - that’s why your PDFs disappeared. Always specify the path explicitly and make sure your photos directory exists before running the bot.