You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为已发送消息添加Inline Keyboard?及回调中原键盘获取方案咨询

Can I retrieve the original InlineKeyboardMarkup from a CallbackQuery in Telegram Bot API?

Short answer: No, you can't directly get the original InlineKeyboardMarkup from the Message object included in a CallbackQuery. As you noted, the Telegram Bot API intentionally excludes the reply_markup field from this message payload to cut down on unnecessary data transfer.

But don't worry—there are solid workarounds to handle this scenario. Here are the most practical options:

1. Store the keyboard data locally when sending the message

This is the most reliable approach. When you send a message with an inline keyboard, save the keyboard's structure alongside the message's unique identifier (a combination of chat_id and message_id works perfectly as a key) in a database, in-memory cache (like Redis), or even a simple in-memory dictionary (for small, non-distributed bots).

When you receive a CallbackQuery, use the chat_id and message_id from the query's message object to look up the stored keyboard data.

Example (using Python with python-telegram-bot):

# Initialize a simple in-memory cache (replace with Redis/database for production)
keyboard_cache = {}

# When sending the message with inline keyboard
def send_message_with_keyboard(bot, user_id):
    keyboard = InlineKeyboardMarkup([
        [InlineKeyboardButton("First Button", callback_data="btn1")],
        [InlineKeyboardButton("Second Button", callback_data="btn2")]
    ])
    sent_msg = bot.send_message(chat_id=user_id, text="Choose an option:", reply_markup=keyboard)
    # Store the keyboard using chat_id + message_id as the key
    cache_key = f"{sent_msg.chat.id}:{sent_msg.message_id}"
    keyboard_cache[cache_key] = keyboard.to_dict()

# Handling the CallbackQuery
@bot.callback_query_handler(func=lambda call: True)
def handle_callback(call):
    cache_key = f"{call.message.chat.id}:{call.message.message_id}"
    stored_keyboard_data = keyboard_cache.get(cache_key)
    if stored_keyboard_data:
        # Reconstruct the InlineKeyboardMarkup object
        original_keyboard = InlineKeyboardMarkup.de_json(stored_keyboard_data)
        # Now you can use original_keyboard for edits, checks, etc.
        print("Original keyboard retrieved:", original_keyboard)

2. Encode keyboard data into callback_data

If your inline keyboard is relatively simple (no overly complex nested structures), you can encode a simplified version of the keyboard into each button's callback_data. Just make sure to stay within the 64-byte limit for callback_data.

You can serialize the keyboard data to JSON, then encode it to Base64 to save space. When the button is clicked, decode the data from the callback_data to reconstruct the keyboard.

Example:

import json
import base64

def send_encoded_keyboard(bot, user_id):
    # Define the keyboard structure as a plain dict
    keyboard_structure = {
        "buttons": [
            ["First Button", "btn1"],
            ["Second Button", "btn2"]
        ]
    }
    # Serialize and encode
    serialized = json.dumps(keyboard_structure).encode()
    encoded_data = base64.b64encode(serialized).decode()
    # Combine with an action identifier (keep total length under 64)
    callback_data = f"action|{encoded_data}"
    if len(callback_data) > 64:
        # Handle overflow (simplify the structure or use another method)
        raise ValueError("Encoded data too long for callback_data")
    
    # Build the keyboard
    keyboard = InlineKeyboardMarkup([
        [InlineKeyboardButton(text, callback_data=f"action|{encoded_data}") for text, _ in row]
        for row in keyboard_structure["buttons"]
    ])
    bot.send_message(chat_id=user_id, text="Choose:", reply_markup=keyboard)

@bot.callback_query_handler(func=lambda call: call.data.startswith("action|"))
def handle_encoded_callback(call):
    _, encoded_data = call.data.split("|", 1)
    # Decode and reconstruct
    serialized = base64.b64decode(encoded_data).decode()
    keyboard_structure = json.loads(serialized)
    original_keyboard = InlineKeyboardMarkup([
        [InlineKeyboardButton(text, data) for text, data in row]
        for row in keyboard_structure["buttons"]
    ])
    print("Reconstructed keyboard:", original_keyboard)

You could use the getChatHistory or getMessage API methods to retrieve the full original message, which includes the reply_markup. However, this approach has major downsides:

  • If the user deleted the message, you won't be able to fetch it.
  • Your bot needs the appropriate permissions to access chat history.
  • Frequent API calls can lead to rate limiting, which disrupts bot performance.

This should only be used as a last-resort fallback, not a primary solution.


内容的提问来源于stack exchange,提问作者Ivan Vinogradov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 04:00:34