iToverDose/Software· 23 APRIL 2026 · 00:06

Build lean Telegram bots with Python and zero dependencies

Learn how to create fast, native Telegram bots using Python’s requests library and Telegram’s HTTP API—no frameworks, no overhead, just direct control and minimal latency.

DEV Community4 min read0 Comments

Telegram bots are quietly powering millions of automated workflows, from customer support to data pipelines—yet many developers start with bulky frameworks. By skipping libraries like python-telegram-bot and using Telegram’s native HTTP API directly, you gain full control over performance, latency, and feature set without sacrificing simplicity. Here’s how to build a high-speed Telegram bot using pure Python and a single dependency: the requests library.

Why go native? Speed, control, and clarity

While high-level libraries abstract away boilerplate, they also introduce overhead through abstraction layers. Telegram’s Bot API communicates over HTTPS, so native HTTP requests let you:

  • Avoid framework startup delays.
  • Tune timeouts and retries precisely.
  • Integrate seamlessly into existing microservices.
  • Stay under Telegram’s strict rate limits without hidden throttling.

For small bots or internal tools, a zero-dependency approach keeps deployment files under 100 KB and startup times under 200 ms. That’s often faster than spinning up a Node.js or Python runtime with heavy packages.

Setting up: three quick prerequisites

Before writing code, collect three essentials:

  • A Telegram account to link your bot.
  • A bot token from @BotFather (issued instantly via Telegram’s CLI-style interface).
  • Python 3.8 or newer with pip and requests installed.

Once you’ve sent /newbot to @BotFather and copied the token, store it securely—never commit it directly to version control. Use environment variables or a local secrets manager instead.

Core workflow: polling vs. webhooks

Telegram offers two update delivery methods: long polling and webhooks. Polling is simpler for local testing; webhooks are mandatory for production workloads.

Long polling: the simplest path

Start with a loop that fetches new messages at 30-second intervals. The following snippet shows how to retrieve updates and extract chat IDs and text:

import requests
import time

TOKEN = "YOUR_BOT_TOKEN"
BASE_URL = f"

def get_updates(offset=None):
    url = f"{BASE_URL}/getUpdates"
    params = {"offset": offset, "timeout": 30}
    response = requests.get(url, params=params)
    return response.json().get("result", [])

def send_message(chat_id, text):
    url = f"{BASE_URL}/sendMessage"
    payload = {"chat_id": chat_id, "text": text}
    requests.post(url, json=payload)

def main():
    offset = None
    while True:
        updates = get_updates(offset)
        if updates:
            for update in updates:
                chat_id = update["message"]["chat"]["id"]
                text = update["message"].get("text", "")
                if text == "/start":
                    send_message(chat_id, "🚀 Bot is online!")
                elif text == "/ping":
                    send_message(chat_id, "🏓 Pong!")
            offset = updates[-1]["update_id"] + 1
        time.sleep(1)

if __name__ == "__main__":
    main()

This loop runs locally and is ideal for prototypes or development servers. It uses long polling, which keeps the connection open for up to 30 seconds and reduces round trips compared to short polling.

Webhooks: instant updates for production

Switching to webhooks eliminates polling entirely. Instead of repeatedly asking Telegram for new messages, Telegram pushes updates directly to your server via HTTPS POST. Here’s how to set it up:

from flask import Flask, request

WEBHOOK_URL = "

# Register once (run in a script or notebook)
requests.get(f"{BASE_URL}/setWebhook?url={WEBHOOK_URL}")

app = Flask(__name__)

@app.route("/webhook", methods=["POST"])
def webhook():
    update = request.get_json()
    chat_id = update["message"]["chat"]["id"]
    text = update["message"].get("text", "")
    if text == "/start":
        send_message(chat_id, "🚀 Bot is online!")
    return "OK"

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5000)

Remember to register your HTTPS endpoint with Telegram. Tools like Ngrok make this trivial during development:

ngrok http 5000

Copy the HTTPS ngrok URL, append /webhook, and pass it to setWebhook. Telegram will verify the endpoint within seconds.

Scaling up: async, queues, and rate limits

As your bot gains traction, three optimizations become critical:

  • Async I/O: Replace synchronous requests with httpx or aiohttp to handle concurrent updates without blocking.
  • Queues: Use a thread or process to manage outgoing messages and avoid rate limit spikes.
  • State: Offload session data to Redis when your bot tracks user progress across multiple updates.

Here’s a minimal async send function:

import httpx

async def async_send_message(chat_id, text):
    async with httpx.AsyncClient(timeout=10) as client:
        await client.post(
            f"{BASE_URL}/sendMessage",
            json={"chat_id": chat_id, "text": text}
        )

For outgoing queues, spawn a daemon thread to drain messages at a steady 25 per second—well below Telegram’s 30-message ceiling:

from queue import Queue
import threading

message_queue = Queue(maxsize=1000)

def message_worker():
    while True:
        chat_id, text = message_queue.get()
        send_message(chat_id, text)
        message_queue.task_done()

threading.Thread(target=message_worker, daemon=True).start()

Enqueue messages instead of calling send_message directly:

message_queue.put((chat_id, "Your reply here"))

Beyond text: keyboards, files, and callbacks

Native bots aren’t limited to plain text. You can attach inline keyboards for quick interactions:

from json import dumps

def send_keyboard(chat_id):
    keyboard = {
        "inline_keyboard": [[
            {"text": "Option 1", "callback_data": "opt1"},
            {"text": "Option 2", "callback_data": "opt2"}
        ]]
    }
    payload = {
        "chat_id": chat_id,
        "text": "Choose an option:",
        "reply_markup": dumps(keyboard)
    }
    requests.post(f"{BASE_URL}/sendMessage", json=payload)

Handling callback queries requires another endpoint:

@app.route("/callback", methods=["POST"])
def handle_callback():
    query = request.get_json()
    if query["data"] == "opt1":
        send_message(query["from"]["id"], "You chose Option 1!")
    return "OK"

File uploads follow a similar pattern—stream the file directly in the POST body:

def send_photo(chat_id, photo_path):
    with open(photo_path, "rb") as photo:
        requests.post(
            f"{BASE_URL}/sendPhoto",
            files={"photo": photo},
            data={"chat_id": chat_id}
        )

From laptop to cloud: deployment blueprints

Local development is only the first step. For scalable, always-on bots, consider these patterns:

  • Serverless: Deploy a Python Flask or FastAPI handler on AWS Lambda with API Gateway, using webhooks as the trigger.
  • Containers: Package your bot in a lightweight Docker image and run it on Kubernetes or a cloud VM.
  • Edge functions: Use Cloudflare Workers or Deno Deploy to cut cold starts to near-zero.

A minimal AWS Lambda handler:

def lambda_handler(event, context):
    from urllib.parse import parse_qs
    body = parse_qs(event["body"])
    update = json.loads(body["update"][0])
    handle_updates([update])
    return {"statusCode": 200}

Looking ahead: where native shines brightest

Native bots excel in constrained environments—edge devices, serverless platforms, and low-latency pipelines. As your feature set grows, layer on async I/O, Redis for state, and monitoring via getWebhookInfo to stay within Telegram’s policies.

Start small, measure latency with tools like cURL, and scale deliberately. The fastest Telegram bot isn’t the one with the most libraries—it’s the one with the least overhead between user action and bot response.

AI summary

Discover how to create lightning-fast Telegram bots using Python’s requests library and Telegram’s HTTP API for maximum control and minimal latency.

Comments

00
LEAVE A COMMENT
ID #4PSA45

0 / 1200 CHARACTERS

Human check

9 + 5 = ?

Will appear after editor review

Moderation · Spam protection active

No approved comments yet. Be first.