How to Make a Telegram Bot in Python (with Shingram)
This is a complete, production-grade guide on how to make a Telegram bot in Python using Shingram, a minimalist and explicit Telegram Bot API wrapper.
Official resources:
- https://github.com/nouzumoto/shingram
- https://nouzumoto.github.io/shingram/
- https://pypi.org/project/shingram/
How to Create a Telegram Bot in Python (Quick Steps)
- Create a bot with @BotFather
- Install Shingram
- Register event handlers
- Start polling with
bot.run()
This guide explains each step in depth.
How Telegram Bots Work
A Telegram bot works by processing updates sent by Telegram.
Each update represents an event such as:
- A message
- A command
- A callback query
- An inline query
Shingram uses long polling, meaning:
- No webhook
- No server setup required
- The bot continuously fetches updates from Telegram
This makes Shingram ideal for local development, VPS deployments, and simple production setups.
Why Use Shingram
Shingram focuses on explicitness and simplicity.
Key Characteristics
- Single normalized
Eventobject - Synchronous API (no async/await)
- No hardcoded Telegram methods
- Automatic support for new Telegram API methods
- Full access to raw Telegram JSON
Shingram is ideal if you want control, clarity, and predictable behavior.
Requirements
- Python 3.8+
- A Telegram account
- A bot token from @BotFather
Install Shingram:
pip install shingram
Creating a Bot Token with BotFather
- Open Telegram
- Search for @BotFather
- Send
/start - Run
/newbot - Choose a name and username
- Copy the BOT TOKEN
Basic Bot Setup
Create a file called bot.py:
from shingram import Bot
bot = Bot("YOUR_BOT_TOKEN")
This initializes a Telegram bot using long polling.
Event Object Explained
Shingram provides a single normalized Event object for all updates.
Event Structure
@dataclass
class Event:
type: str
name: str
chat_id: int
user_id: int
text: str
raw: dict
reply_to: Optional[int]
chat_type: Optional[str]
inline_query_id: Optional[str]
callback_query_id: Optional[str]
message_id: Optional[int]
username: Optional[str]
first_name: Optional[str]
chat_title: Optional[str]
- Only 14 fields
- Covers 80% of use cases
- Full Telegram data is always available in
event.raw
Handling the /start Command
@bot.on("command:start")
def handle_start(event):
bot.send_message(
chat_id=event.chat_id,
text="Hello! This bot is running with Shingram."
)
Handling Messages (Echo Bot)
@bot.on("message")
def echo(event):
bot.send_message(
chat_id=event.chat_id,
text=event.text
)
Handling Callback Queries
Callback queries occur when users press inline buttons.
@bot.on("callback")
def handle_callback(event):
bot.answer_callback_query(
callback_query_id=event.callback_query_id,
text="Action received"
)
Access callback data:
callback_data = event.text
Handling Inline Queries
Inline queries do not have a chat_id.
@bot.on("inline_query")
def handle_inline(event):
bot.answer_inline_query(
inline_query_id=event.inline_query_id,
results=[]
)
Using event.raw for Advanced Data
event.raw contains the full Telegram update.
Example: Message Entities
entities = event.raw["message"].get("entities", [])
Example: Media Access
message = event.raw["message"]
if "photo" in message:
file_id = message["photo"][-1]["file_id"]
Dynamic Telegram API Methods
Shingram dynamically converts Python method names to Telegram API calls.
bot.send_message(chat_id=123, text="Hello")
Automatically maps to:
sendMessage
No methods are hardcoded.
If Telegram adds a new method, it works instantly.
Full Minimal Working Bot
from shingram import Bot
bot = Bot("YOUR_BOT_TOKEN")
@bot.on("command:start")
def start(event):
bot.send_message(event.chat_id, "Bot started")
@bot.on("message")
def echo(event):
bot.send_message(event.chat_id, event.text)
bot.run()
Deploying a Telegram Bot
Common deployment options:
- VPS (Hetzner, DigitalOcean)
systemdtmuxorscreen- Docker
Shingram works without webhooks.
Polling vs Webhook
| Feature | Polling | Webhook |
|---|---|---|
| Setup | Simple | Complex |
| Server | Not required | Required |
| Shingram | ✅ Supported | ❌ Not native |
| Use case | Small/medium bots | Large scale |
Common Problems and Fixes
Bot Not Responding
- Check bot token
- Ensure
bot.run()is called - Ensure only one instance is polling
- Check logs for exceptions
Shingram vs Other Frameworks
| Feature | Shingram | python-telegram-bot | aiogram |
|---|---|---|---|
| Async | ❌ | ✅ | ✅ |
| Complexity | Low | Medium | High |
| Abstractions | Minimal | Many | Many |
| Learning | Easy | Medium | Hard |
Frequently Asked Questions
Is Shingram asynchronous?
No. Shingram is synchronous.
Is Shingram production-ready?
Yes. Many bots benefit from explicit control.
Does Shingram support all Telegram API methods?
Yes. Methods are resolved dynamically.
Do Telegram bots need a server?
No. Polling works on any machine.
Can I access full Telegram updates?
Yes, via event.raw.
Is Shingram beginner-friendly?
Yes, especially if you want to learn how updates work.