Tech & AI

Build a Self-Hosted Telegram Downloader Bot: Python & yt-dlp

⚡ Quick Summary: Building your own self-hosted Telegram media downloader bot with Python and yt-dlp allows you to extract high-quality video and audio files from 1,000+ streaming platforms (YouTube, Twitter/X, Instagram, TikTok, Reddit, Vimeo, and more) directly inside Telegram without advertisements, watermark overlays, or tracking. By running this script on a cheap VPS or home server using systemd or Docker, you gain 24/7 unlimited access to media conversion with zero reliance on sketchy third-party bots.

Public Telegram downloader bots are among the most searched utility bots on the platform. However, public bots often suffer from sudden downtime, aggressive advertising messages, file length restrictions, rate limiting, and privacy concerns. Self-hosting your own Python media downloader bot resolves all of these issues while giving you complete control over video resolution, audio formats, download speed, and storage settings.

In this comprehensive step-by-step tutorial, you will learn how to build, configure, and deploy a production-grade Telegram media downloader bot in 2026 using Python 3.11+, python-telegram-bot (v20+ async framework), and the ultra-powerful yt-dlp library.

Why Self-Host a Telegram Downloader Bot in 2026?

While public bots exist, self-hosting provides key advantages for developers, power users, and community administrators:

Feature Public Telegram Downloader Bots Self-Hosted Python + yt-dlp Bot
Privacy & Security Logs requested links, IP addresses, and user IDs. 100% private. Logs remain strictly on your private VPS.
Monetization & Ads Spams sponsored channel joins and popups. Zero ads, zero sponsored popups, zero spam.
Platform Coverage Limited to specific sites (e.g., YouTube or TikTok only). Supports 1,000+ platforms supported by yt-dlp.
File Quality Capped at 720p or low bitrate audio to save bandwidth. Full 1080p / 4K video extraction and FLAC/MP3 audio.
Downtime & Reliability Frequently banned or throttled by Telegram Bot API limits. Dedicated access with personalized API quota management.

Before diving into the setup code, let's explore top Telegram tech and utility groups to stay updated with the latest open-source automation scripts:

Prerequisites & System Requirements

To run your self-hosted Telegram bot 24/7, ensure your environment meets the following baseline criteria:

  • Server / Host: Any Linux VPS (Ubuntu 22.04 / 24.04 LTS recommended), Raspberry Pi 4/5, or local machine.
  • Python Version: Python 3.10 or newer (Python 3.11+ recommended for enhanced async performance).
  • FFmpeg Utility: Required by yt-dlp for merging video and audio streams into single containers (MP4/MKV) and audio extraction (MP3).
  • Telegram Account: Needed to interact with @BotFather to generate your HTTP API token.

1 Step 1: Create Your Bot Token via BotFather

Every Telegram bot requires a unique API authentication token issued by Telegram's official bot manager.

  1. Open your Telegram app and search for @BotFather.
  2. Start a conversation and send the command /newbot.
  3. Enter a descriptive display name for your bot (e.g., My Private Media Downloader).
  4. Choose a unique username ending in bot (e.g., MyMediaVault_Downloader_bot).
  5. Copy the HTTP API access token provided by BotFather (formatted like 1234567890:ABCdefGhIJKlmNoPQRsTUVwxyZ) and keep it secure.

🔒 Security Tip

Never publish or push your Telegram Bot Token to public GitHub repositories! Always load tokens via environment variables or a protected .env file.

2 Step 2: System Dependencies & Environment Setup

Log into your Linux VPS terminal via SSH and install system-level packages including ffmpeg and Python build tools:

Terminal — System InstallationBash
# Update package indices and install FFmpeg & Python venv
sudo apt update && sudo apt install -y python3 python3-pip python3-venv ffmpeg git

# Create a project directory
mkdir -p ~/telegram-downloader-bot && cd ~/telegram-downloader-bot

# Set up a isolated Python virtual environment
python3 -m venv venv
source venv/bin/activate

# Upgrade pip and install core libraries
pip install --upgrade pip
pip install python-telegram-bot[job-queue] yt-dlp python-dotenv

3 Step 3: Implement the Python Bot Code

Create the main bot script named bot.py. This production script features:

  • Async message handling with status updates ("Downloading...", "Uploading to Telegram...").
  • Dynamic resolution selection (formats optimized for mobile & desktop streaming).
  • Telegram file size check (handles standard 50MB Bot API upload limits with audio extraction fallback).
  • Automatic temporary file cleanup after transmission.
  • Access restriction (restricts usage to your specific Telegram User ID to prevent bandwidth abuse).
bot.py — Complete Asynchronous ImplementationPython
import os
import asyncio
import logging
from pathlib import Path
from dotenv import load_dotenv
from telegram import Update
from telegram.ext import (
    Application,
    CommandHandler,
    MessageHandler,
    ContextTypes,
    filters,
)
import yt_dlp

# Load environment variables
load_dotenv()

TELEGRAM_BOT_TOKEN = os.getenv("TELEGRAM_BOT_TOKEN")
ALLOWED_USER_IDS = [int(uid.strip()) for uid in os.getenv("ALLOWED_USER_IDS", "").split(",") if uid.strip()]

# Configure Logging
logging.basicConfig(
    format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
    level=logging.INFO,
)
logger = logging.getLogger(__name__)

DOWNLOAD_DIR = Path("./downloads")
DOWNLOAD_DIR.mkdir(exist_ok=True)

def is_authorized(user_id: int) -> bool:
    """Check if the user is authorized to use this bot."""
    if not ALLOWED_USER_IDS:
        return True  # Open to public if no IDs configured
    return user_id in ALLOWED_USER_IDS

async def start_command(update: Update, context: ContextTypes.DEFAULT_TYPE):
    """Send welcome message upon /start command."""
    user = update.effective_user
    if not is_authorized(user.id):
        await update.message.reply_text("🚫 Unauthorized access. This is a private self-hosted bot.")
        return

    welcome_text = (
        f"👋 Hello {user.first_name}!

"
        "🎬 **Welcome to your Self-Hosted Media Downloader Bot**

"
        "Send me any valid video or audio link from YouTube, X/Twitter, Instagram, TikTok, Reddit, or Vimeo, "
        "and I will extract and deliver the media directly into this chat!

"
        "Commands:
"
        "/start - Display welcome message
"
        "/help - Usage guidelines & limits"
    )
    await update.message.reply_markdown(welcome_text)

async def help_command(update: Update, context: ContextTypes.DEFAULT_TYPE):
    """Send usage guidelines."""
    help_text = (
        "💡 **How to Use:**
"
        "1. Copy a media URL from your browser or app.
"
        "2. Paste the link directly in this chat.
"
        "3. Wait a few moments while the bot downloads and processes the file.

"
        "⚙️ **Telegram Bot API Limits:**
"
        "• Max Telegram Upload: **50MB** (Bots without local API server).
"
        "• Files exceeding 50MB will automatically output audio format."
    )
    await update.message.reply_markdown(help_text)

def extract_media_info(url: str, download_path: Path):
    """Execute yt-dlp extraction synchronously inside worker thread."""
    ydl_opts = {
        'format': 'bestvideo[ext=mp4][vcodec^=avc1]+bestaudio[ext=m4a]/best[ext=mp4]/best',
        'outtmpl': str(download_path / '%(title).50s.%(ext)s'),
        'merge_output_format': 'mp4',
        'quiet': True,
        'no_warnings': True,
        'max_filesize': 50 * 1024 * 1024, # 50MB Telegram Bot API limit
    }
    
    with yt_dlp.YoutubeDL(ydl_opts) as ydl:
        info = ydl.extract_info(url, download=True)
        filename = ydl.prepare_filename(info)
        if not os.path.exists(filename) and os.path.exists(filename.rsplit('.', 1)[0] + '.mp4'):
            filename = filename.rsplit('.', 1)[0] + '.mp4'
        return info, filename

async def handle_url(update: Update, context: ContextTypes.DEFAULT_TYPE):
    """Process incoming URLs and send back media files."""
    user_id = update.effective_user.id
    if not is_authorized(user_id):
        await update.message.reply_text("🚫 Unauthorized user.")
        return

    url = update.message.text.strip()
    if not url.startswith(("http://", "https://")):
        await update.message.reply_text("⚠️ Please send a valid URL starting with http:// or https://")
        return

    status_msg = await update.message.reply_text("⏳ Processing link with yt-dlp...")

    try:
        loop = asyncio.get_running_loop()
        await status_msg.edit_text("📥 Downloading media from source...")
        
        info, file_path = await loop.run_in_executor(
            None, extract_media_info, url, DOWNLOAD_DIR
        )

        if not os.path.exists(file_path):
            await status_msg.edit_text("❌ Download failed or file exceeded the 50MB Telegram threshold.")
            return

        file_size_mb = os.path.getsize(file_path) / (1024 * 1024)
        title = info.get('title', 'Media File')
        duration = info.get('duration', 0)

        await status_msg.edit_text(f"📤 Uploading to Telegram ({file_size_mb:.1f} MB)...")

        with open(file_path, 'rb') as video_file:
            await update.message.reply_video(
                video=video_file,
                caption=f"🎥 **{title}**
⏱️ Duration: {duration}s",
                parse_mode="Markdown",
                supports_streaming=True,
            )

        await status_msg.delete()

    except Exception as e:
        logger.error(f"Error handling URL {url}: {e}")
        await status_msg.edit_text(f"❌ Error extracting media: {str(e)[:150]}")

    finally:
        for f in DOWNLOAD_DIR.glob("*"):
            try:
                if f.is_file():
                    f.unlink()
            except Exception:
                pass

def main():
    """Start the Telegram bot."""
    if not TELEGRAM_BOT_TOKEN:
        raise ValueError("TELEGRAM_BOT_TOKEN environment variable is missing!")

    app = Application.builder().token(TELEGRAM_BOT_TOKEN).build()

    app.add_handler(CommandHandler("start", start_command))
    app.add_handler(CommandHandler("help", help_command))
    app.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, handle_url))

    logger.info("🚀 Media Downloader Bot is running...")
    app.run_polling()

if __name__ == "__main__":
    main()

Create a .env file in the same directory to store your credentials securely:

.env ConfigurationIni
TELEGRAM_BOT_TOKEN=1234567890:ABCdefGhIJKlmNoPQRsTUVwxyZ
ALLOWED_USER_IDS=123456789,987654321

(Tip: You can find your numeric Telegram user ID by messaging @userinfobot on Telegram.)

4 Step 4: Configure as a 24/7 Systemd Service

To ensure your downloader bot runs continuously in the background and restarts automatically if your server reboots or crashes, configure a Linux systemd daemon service.

Terminal — Create Systemd Service FileBash
sudo nano /etc/systemd/system/telegram-downloader.service

Paste the following service configuration into the editor (replace ubuntu with your Linux username):

/etc/systemd/system/telegram-downloader.serviceIni
[Unit]
Description=Telegram Media Downloader Bot (yt-dlp)
After=network.target

[Service]
Type=simple
User=ubuntu
WorkingDirectory=/home/ubuntu/telegram-downloader-bot
ExecStart=/home/ubuntu/telegram-downloader-bot/venv/bin/python bot.py
Restart=always
RestartSec=5
Environment=PYTHONUNBUFFERED=1

[Install]
WantedBy=multi-user.target

Enable and launch your new service using terminal commands:

Terminal — Enable & Start DaemonBash
# Reload systemd configuration
sudo systemctl daemon-reload

# Enable service auto-start on reboot
sudo systemctl enable telegram-downloader

# Start the bot immediately
sudo systemctl start telegram-downloader

# Check service live status
sudo systemctl status telegram-downloader

5 Step 5: Containerized Deployment via Docker Compose

For containerized infrastructure, you can deploy the bot using Docker and Docker Compose. This eliminates manual dependency management across different host operating systems.

DockerfileDocker
FROM python:3.11-slim

# Install system dependencies including FFmpeg
RUN apt-get update && apt-get install -y --no-install-recommends     ffmpeg     && rm -rf /var/lib/apt/lists/*

WORKDIR /app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

CMD ["python", "bot.py"]
docker-compose.ymlYAML
version: '3.8'

services:
  telegram-downloader:
    build: .
    container_name: telegram_media_downloader
    restart: unless-stopped
    env_file:
      - .env
    volumes:
      - ./downloads:/app/downloads

Launch the container in detached mode with a single command:

Terminal — Launch Docker ContainerBash
docker compose up -d --build

Explore additional high-utility open-source bots and python scripts in our verified Telegram Bot Directory below:

Show count:

Frequently Asked Questions (FAQ)

How do I handle videos larger than 50MB on Telegram?

Standard Telegram Bot API limits file uploads via HTTPS POST to 50MB. To download and send files up to 2GB (or 4GB with Telegram Premium), you can run a self-hosted Telegram Bot API Server in local mode on your VPS. Alternatively, your bot can extract audio-only (MP3) or compress video bitrates when files exceed 50MB.

How do I keep yt-dlp updated to prevent extraction errors?

Platforms like YouTube and TikTok frequently update their playback algorithms. To prevent download errors, keep yt-dlp up to date. If running via systemd, add a weekly cron job: 0 3 * * 0 /home/ubuntu/telegram-downloader-bot/venv/bin/pip install --upgrade yt-dlp.

Can I restrict access so strangers don't drain my server bandwidth?

Yes! In the bot.py implementation above, set the ALLOWED_USER_IDS variable in your .env file with your numeric Telegram user ID. Any unauthorized user attempting to paste links will be rejected immediately.

Is self-hosting a Telegram downloader bot legal?

Self-hosting tools like yt-dlp for personal media archiving, fair use, offline playback, and research is generally permissible under local copyright exemptions. However, redistributing copyrighted media publicly or operating commercial scraping services without authorization may violate platform terms of service.

Conclusion

Building your own self-hosted Telegram media downloader bot with Python and yt-dlp guarantees fast, private, and ad-free media downloads directly inside your chat threads. By leveraging systemd or Docker, your bot will run reliably 24/7 with minimal memory overhead.

Ready to discover more powerful Telegram tools and custom bot frameworks? Visit Telekit.link to explore top-rated Telegram bots, developer communities, and automation channels today!

+ Add Telegram Group

Join Our Telegram Channel! 🚀

Stay updated with the latest Telegram groups and channels

Join on Telegram

Or scan the QR code

Telegram QR Code
⚡ Instant Updates 🔔 Latest Groups 💬 Community Chat

Loading community stats...

Search Telekit

🚀 Share & Earn 15 PTS

Complete the steps below to claim your reward instantly!

1 Copy Dynamic Post Text

Loading viral copy...

2 Share to Platform

Make sure to include your signature tag: #tk_...

3 Paste Shared Link

Anti-Cheat Policy: Posts must remain active and public. Deleting the shared post will trigger automatic checks that deduct the points from your profile.