- Notifications
You must be signed in to change notification settings - Fork5.7k
Arbitrary callback_data
The Telegrams Bot API only accepts strings with length up to 64 bytes ascallback_data
forInlineKeyboardButtons
, which sometimes is quite a limitation.
With PTB, you are able to passany object ascallback_data
. This is achieved by storing the object in a cache and passing a unique identifier for that object to Telegram. When aCallbackQuery
is received, the id in thecallback_data
is replaced with the stored object. To use this feature, setApplication.arbitrary_callback_data
toTrue
. The cache that holds the stored data has limited size (more details on memory usage below). If the cache is full and objects from a newInlineKeyboardMarkup
need to be stored, it will discard the data for the least recently used keyboard.
This means three things for you:
If you don't usepersistence, buttons won't work after restarting your bot, as the stored updates are lost. More precisely, the
callback_data
you will receive is an instance oftelegram.ext.InvalidCallbackData
. If you don't need persistence otherwise, you can setstore_callback_data
toTrue
and all the others toFalse
.If you have a number of keyboards that need to stay valid for a very long time, you might need to do some tweaking manually (see below)
When using the
CallbackQueryHandler
, thepattern
argument can now be either- a regex expression, which will be used, if the
callback_data
is in fact a string - a callable accepting the
callback_data
as only argument. You can perform any kinds of tests on thecallback_data
and returnTrue
orFalse
accordingly - a type. In that case the
CallbackQuery
will be handled, if thecallback_data
is an instance of that type. Btw: This allows you to inform users, when a buttons' data has been dropped from cache. WithCallbackQueryHandler(callback, pattern=InvalidCallbackData)
you can e.g., callawait update.callback_query.answer(text='Button is no longer valid', show_alert=True)
to inform the user.
- a regex expression, which will be used, if the
Note
You can of course also manually implement the idea of storing the object in a cache and passing a unique identifier for that object to Telegram, e.g. with the help of PTBstoring data functionality. PTBs built-in "Arbitrarycallback_data
" provides this mechanism in a way that requires minimal additional implementation effort on your end and that ties in well with the overall PTB framework.
PTB stores the callback data objects in memory. Additionally, to that, it stores a mapping ofCallbackQuery.id
to the corresponding UUID. By default, both storages contain a maximum number of 1024 items. You can change the size by passing an integer to thearbitrary_callback_data
argument ofApplicationBuilder
/ExtBot
.
As PTB can't know when the stored data is no longer needed, it uses an LRU (Least Recently Used) cache. This means that when the cache is full, it will drop the keyboard that has been not used for the longest time. However, if you want to keep memory usage low, you haveadditional options to drop data:
- on receiving a
CallbackQuery
, you can callcontext.drop_callback_data(callback_query)
. This will delete the data associated with the keyboard attached to the message that originated theCallbackQuery
. Callingcontext.drop_callback_data
is safe in any case where you change the keyboard, i.e.callback_query.edit_message_text/reply_markup/…
Note: If the user clicks a button more than one time fast enough, but you callcontext.drop_callback_data
for the first resultingCallbackQuery
, the second one will haveInvalidCallbackData
ascallback_data
. However, this is usually not a problem, because one only wants one button click anyway. - To drop more data from memory, you can call
bot.callback_data_cache.clear_callback_queries()
orbot.callback_data_cache.clear_callback_data()
, which will drop the mapping ofCallbackQuery
ids to the associated UUID and the mapping of UUIDs to data, respectively.clear_callback_data
also accepts atime_cutoff
, allowing you to delete only entries older than a specified time.
Callback updates are not sent by Telegram, but by the client. This means that they can be manipulated by a user. (While Telegram unofficially does try to prevent this, they don't want Bot devs to rely on them doing the security checks).
Most of the time, this is not really a problem, sincecallback_data
often just isYes
,No
, etc. However, if the callback data is something likedelete message_id 123
, the malicious user could delete any message sent by the bot.
When usingarbitrary_callback_data
as described above, PTB replaces the outgoingcallback_data
with aUUID, i.e., a random unique identifier. This makes thecallback_data
safe: If a malicious client alters the sentCallbackQuery
, the invalid UUID can't be resolved. In this caseCallbackQuery.data
will be an instance oftelegram.ext.InvalidCallbackData
. Note that this is also the case, when the UUIDwas valid, but the data has already been dropped from cache - PTB can't distinguish between the two cases.
You may be manually building your updates from JSON-data, e.g., in case you are using a custom webhooks setup. In this case you'll have to make sure that the cached data is inserted back into the buttons yourself, like this:
update=Update.de_json(data,bot)ifbot.arbitrary_callback_data:bot.insert_callback_data(update)
Inline buttons are not only sent, your bot also receives them. In the return value of your bot message, when receiving messages that are replies to messages with an inline keyboard, havemessage.pinned_message
or wheremessage.via_bot
is your bot (i.e., messages sent via your bot in inline mode). PTB tries very hard to insert the corresponding data back into all those keyboards, where appropriate - i.e., where the keyboard was sent byyour bot and not by another bot. There is however one case, where there is no way to tell that: channel posts have nofrom_user
. So unless they have thevia_bot
attribute, there is no way to tell, if they were sent by your bot or another one. This means:
If your bot receives a channel post, which asreply_to_message
orpinned_message
and the latter has a keyboard, but wasnot sent by your bot, allcallback_data
will containInvalidCallbackData
instances. This is of course unfortunate, but we do have a feeling that the cases where this would complicate things are so rare that it doesn't really matter 😉
Wiki ofpython-telegram-bot
© Copyright 2015-2025 – Licensed byCreative Commons
- Architecture Overview
- Builder Pattern for
Application
- Types of Handlers
- Working with Files and Media
- Exceptions, Warnings and Logging
- Concurrency in PTB
- Advanced Filters
- Storing data
- Making your bot persistent
- Adding Defaults
- Job Queue
- Arbitrary
callback_data
- Avoiding flood limits
- Webhooks
- Bot API Forward Compatiblity
- Frequently requested design patterns
- Code snippets
- Performance Optimizations
- Telegram Passport
- Bots built with PTB
- Automated Bot Tests