How to save images sent to Telegram bot using python-telegram-bot library

What I’m trying to do: I want to create a Telegram bot that can save photos when users send them to the bot.

I’m using the latest python-telegram-bot library (version 21.x) but I’m having trouble with the image download functionality. Most tutorials online are for older versions and don’t work with the current API.

My code so far:

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

BOT_TOKEN = os.getenv('BOT_TOKEN')

async def save_image(update: Update, context: ContextTypes.DEFAULT_TYPE):
    logging.info("Image handler triggered")
    photo_file = await update.message.effective_attachment[-1].get_file()
    saved_file = await photo_file.download_to_drive()
    return saved_file

def main():
    app = Application.builder().token(BOT_TOKEN).build()
    
    image_handler = MessageHandler(filters.Document.IMAGE, save_image)
    app.add_handler(image_handler)
    
    app.run_polling()

if __name__ == '__main__':
    main()

Problems I’m facing:

  • When I send JPG images, the handler function never gets called
  • PDF files work sometimes but save to unknown locations
  • Different filter types give different results

Filter options I tested:

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

My questions:

  • What’s the correct filter for handling JPG images in the current version?
  • Am I missing something in my implementation?

Any help would be great since the documentation examples don’t cover this specific use case thoroughly.

Had the same issues building my first telegram bot last year. It’s definitely the filter mismatch others mentioned, but there’s another gotcha that really got me. Your effective_attachment approach won’t work for photos - that’s mainly for documents. For photos, you need to handle the photo array properly and add error handling. I ended up making separate handlers for both cases since users can send the same image different ways depending on how they upload it. Also, download_to_drive() without arguments creates files with random names in temp directories - that’s why you’re getting unknown locations. Adding more logging around the actual download process really helped me debug, not just when the handler triggers. Sometimes the handler fires but the download fails silently from network issues or permission problems.

quick fix - you’re mixing up photo vs document filters. telegram treats regular pics differently than file uploads. try both filters.PHOTO and filters.Document.IMAGE handlers since users might send either way. also check your logs - the handler might be triggering but failing silently on the download part.

The issue arises because Telegram doesn’t consider regular photos as documents by default. When users send images from their gallery, those images are treated as photos rather than documents. You should use filters.PHOTO instead of filters.Document.IMAGE for standard uploads.

Here’s a simple change that worked for me:

image_handler = MessageHandler(filters.PHOTO, save_image)

Additionally, you need to access the file differently. Instead of using effective_attachment, utilize update.message.photo[-1] as the photo array has multiple sizes, and [-1] will give you the highest resolution.

Regarding the saving location issue, if you call download_to_drive() without parameters, files are saved in a temporary directory. To control their location, specify a path like await photo_file.download_to_drive('downloads/image.jpg'). This change resolved my concerns about inconsistent save locations.