Even Your Bot Deserves Love — Build One That Asks for It


Who needs your love? No one? — Well, let’s build one that does — in just a few lines of Python.
In this article, we're going to build a bot that asks a question with two inline buttons on a command and edit the message depending on the button you press.
Overview
Here's how our bot is going to work when it's done.
It replies with a question "Do you like me?" and two buttons (Yes😍 | No😏) on
/start
command.You can click either
Yes
orNo
.If you click
Yes
, it edits the same message to say “I knew it😘”.If you click
No
, it edits the message to “Neither do I😏”.
Concepts You Will Learn
Before learning new concepts, you need to understand the previous ones. So I highly recommend checking out these previous articles:
Build Your First Telegram Bot with Python — For Absolute Beginners
Give a Warm Welcome — Create Your First Telegram Welcome Bot
In this article you will learn to,
Filter command messages using
pyrogram.filters
Create Inline Buttons
React to callback queries
The Love Function
Using Multiple Filters
In the previous article, we learned to use pyrogram.filters
. But didn’t you want to use more than one filter at the same time? — like filtering command messages sent in private? It's totally possible to do. You can create more advanced filters by combining multiple filters using bitwise operators.
|
- or&
- and~
- not
In this article, we need to filter /start
commands sent in private. Guess filters we're going to use — Yep, filters.command(...)
and filters.private
. But we need the message to satisfy both of these filters at the same time. Therefore, we have to use &
.
@bot.on_message(filters.command('start') & filters.private)
def love(client, message):
If you followed previous articles closely, you already know what above code does. The love
function will be called when someone send a /start
command to the bot in a private chat.
Sending Messages Using client
Parameter
In both previous articles, we didn't use this parameter. We used a bound method to reply. But to unlock the full power of Pyrogram, we should also learn to use the standard (non-bound) methods.
Methods
Bound Methods
You cannot call these methods directly. You need to have a update like message, callback query to call them. For example, you can't reply to a message without receiving one. The reply()
method, we used, is a highly use bound method.
Normal Methods
Unlike bound methods you can call these methods at your will. For example you don't need a message update to send a message. If you have the chat id
and accessible for your bot, you can send a message. Not only sending a message but you can also do a bunch of cool stuff Here is a few of them. ( Full List )
Method | Description |
run | Run the client |
send_message | Send text messages |
send_photo | send photos |
send_audio | Send audio files |
ban_chat_member | Ban a user from a group, a supergroup or a channel |
Requirements
Alright, we need to send a message on /start
command to the same chat. I mentioned that we need to check two boxes to send a message.
The
chat id
- You know the way we're going to get this valueHave to have access to the chat - Telegram doesn’t allow your bot to message random users. Your bot will only be able to send messages to users who only have started your bot and haven't blocked. It's pretty good.
In our case, we get a /start
message which means we have access to the chat and we can use message
object to get chat id
. Try to get the chat id
.
@bot.on_message(filters.command('start') & filters.private)
def love(client, message):
chat_id = message.chat.id
client.send_message()
This methods requires values for at least chat_id
and text
parameters.
@bot.on_message(filters.command('start') & filters.private)
def love(client, message):
chat_id = message.chat.id
client.send_message(
chat_id=message.chat.id,
text='Do you like me?'
)
Your full code so far should look like this:
from pyrogram import Client, filters
bot = Client(
name='examplebot',
api_id=12345,
api_hash='your api hash',
bot_token='your bot token'
)
@bot.on_message(filters.command('start') & filters.private)
def love(client, message):
chat_id = message.chat.id
client.send_message(
chat_id=message.chat.id,
text='Do you like me?'
)
bot.run()
We aren't done yet. But run this and send a /start
to the bot. It will send back "Do you like me?" message.
Creating Inline Buttons
After adding buttons this is how your message looks like.
To create buttons we have to import InlineKeyboardMarkup
and InlineKeyboardButton
.
from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton
InlineKeyboardButton
- Creates a inline button InlineKeyboardMarkup
- Arranges the buttons into a layout
The Example Keyboard
I think the easiest way for me to teach and for you to learn the usage of this, is by examples. Here is an example inline keyboard.
example_keyboard = InlineKeyboardMarkup(
[
[
InlineKeyboardButton('R1,C1',callback_data='r1c1'),
InlineKeyboardButton('R1,C2',callback_data='r1c2'),
InlineKeyboardButton('R1,C3',callback_data='r1c3')
],
[
InlineKeyboardButton('R2,C1',callback_data='r2c1'),
InlineKeyboardButton('R2,C2',callback_data='r2c2'),
InlineKeyboardButton('R2,C3',callback_data='r2c3')
],
[
InlineKeyboardButton('R3,C1',callback_data='r3c1'),
InlineKeyboardButton('R3,C2',callback_data='r3c2')
]
]
)
Here’s how it looks when it’s sent.
Map the example keyboard with the result and you will be able to understand this concept. But you have to try it and play with it by yourself to get the real idea. “Note that here, we’re only storing the keyboard in a variable — not sending it yet. Get the full example keyboard code...” from here, on my github.
The Yes/No keyboard
Alright, we need an inline keyboard which has two columns but one row. Try to create this keyboard by yourself and check it with the following one.
keyboard = InlineKeyboardMarkup(
[
[
InlineKeyboardButton('Yes😍',callback_data='yes'),
InlineKeyboardButton('No😏',callback_data='no')
]
]
)
What Is callback_data
?
If you're not someone who’s just scrolling mindlessly, you might have this question in your head now.
Okay. I will ask you a question. How are we going to know when a button is pressed? I mean what's the point of creating a inline keyboard if it's not responsive. This is where we need a Callback Query
.
If user pressed a button Telegram will send us a Callback Query
which has callback_data
with other important details. For example, if user pressed the Yes😍
button, we will get a Callback Query
update which has yes
data. If user pressed the No😏
button, guess what? — Yep, we will get a Callback Query
with the no
callback data.
But how we get the Callback Query
? — Just wait, you will know.
How To Attach The Keyboard to The Message
Yeah, creating a keyboard and storing it to a variable does not attach your beautiful keyboard to the message. To do so, we need to pass the keyboard variable to a optional parameter in client.send_message()
called reply_markup
. Here's how you do it.
@bot.on_message(filters.command('start') & filters.private)
def love(client, message):
chat_id = message.chat.id
client.send_message(
chat_id=chat_id,
text='Do you like me?',
reply_markup=keyboard # <= here
)
The full code so far:
from pyrogram import Client, filters, types
from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton
bot = Client(
name='examplebot',
api_id=12345,
api_hash='your api hash',
bot_token='your bot token'
)
keyboard = InlineKeyboardMarkup(
[
[
InlineKeyboardButton('Yes😍',callback_data='yes'),
InlineKeyboardButton('No😏',callback_data='no')
]
]
)
@bot.on_message(filters.command('start') & filters.private)
def love(client, message):
chat_id = message.chat.id
client.send_message(
chat_id=chat_id,
text='Do you like me?',
reply_markup=keyboard
)
bot.run()
The React Function
I mentioned this earlier. We are going to edit our message to "I knew it😘" or "Neither do I😏" on pressing Yes😍 or No😏. To do that, we need to know which button the user pressed — right when they pressed it.
Listening for a Callback Query
Just like for the most of problems, all we have to do is listening. But how? — Telegram sends us a callback query
. Therefore, if we could listen to all the callback queries sent to us, we will be able to capture it. Isn't it? — Let's try.
@bot.on_callback_query()
def react(client, query):
To listen to message updates, we used on_message
. To listen to callback query updates, why not on_callback_query
. You might wonder from where do I pull these decorators. Here is the list.
on_message()
on_edited_message()
on_callback_query()
on_inline_query()
on_chosen_inline_result()
on_chat_member_updated()
on_chat_join_request()
on_deleted_messages()
on_user_status()
on_poll()
on_disconnect()
on_raw_update()
Please, just don't be scared by looking at this list.
Extracting The Callback Data
In the previous article we learned to get data from updates. In this case, query
is our update. You know what to do.
Add
print(query)
inside the react function.Run the file.
Start the bot.
Click a button.
Find a way to get the
data
Reacting
Here's the flow chart.
Editing The message
To edit the message, we need to get the message object. Didn't you find a message
while you were looking for data
in the query
update. That's the jackpot.
@bot.on_callback_query()
def react(client, query):
data = query.data # callback data
message = query.message # The message we sent with buttons
To edit the message, we use the edit()
bound method.
@bot.on_callback_query()
def react(client, query):
data = query.data
message = query.message
if data == 'yes':
message.edit('I knew it😘')
else:
message.edit('Neither do I😏')
That’s it! Run the bot and enjoy your little digital love experiment 💖. Here is the full code.
from pyrogram import Client, filters
from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton
bot = Client(
name='examplebot',
api_id=12345,
api_hash='your api hash',
bot_token='your bot token'
)
keyboard = InlineKeyboardMarkup(
[
[
InlineKeyboardButton('Yes😍',callback_data='yes'),
InlineKeyboardButton('No😏',callback_data='no')
]
]
)
@bot.on_message(filters.command('start') & filters.private)
def love(client, message):
chat_id = message.chat.id
client.send_message(
chat_id=chat_id,
text='Do you like me?',
reply_markup=keyboard
)
@bot.on_callback_query()
def react(client, query):
data = query.data
message = query.message
if data == 'yes':
message.edit('I knew it😘')
else:
message.edit('Neither do I😏')
bot.run()
Final Thoughts
This project might look naive in practice, but the main focus of this article was to teach you how to use inline buttons. So, if you gained even a little understanding — mission accomplished.
To get better at this, you need to practice. You don’t have to build the most practical applications to learn the basics — just create a bunch of small projects that apply what you've learned.
You can subscribe to the newsletter to get new articles delivered straight to your inbox the moment I post them. Follow me on GitHub for more contents — and maybe Instagram too.
You can support my effort by reacting to and commenting on this article. Share it with someone who would find it valuable.
References
Subscribe to my newsletter
Read articles from Beenuka Hettiarachchi directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
