To use inline buttons with callback data, you need to enable inline mode for your bot. Go to @BotFather, select your bot, go to Bot Settings → Inline Mode and turn it on.
Overview
CallbackQuery represents a callback from an inline button click. It’s triggered when users click inline keyboard buttons with callback data.
Structure
Copy
type CallbackQuery struct {
QueryID int64
Data []byte
OriginalUpdate *UpdateBotCallbackQuery
Sender *UserObj
MessageID int32
SenderID int64
ChatID int64
Chat *ChatObj
Channel *Channel
Peer Peer
Client *Client
}
Basic Properties
Query Information
Unique query identifier
Copy
queryID := c.QueryID
Callback data from button
Copy
data := c.Data
Get callback data as string
Copy
dataStr := c.DataString()
ID of message with the button
Copy
msgID := c.MessageID
Sender Information
Get user ID who clicked button
Copy
userID := c.GetSenderID()
Get full sender object
Copy
sender, err := c.GetSender()
fmt.Println(sender.FirstName)
Chat Information
Get chat/channel ID
Copy
chatID := c.GetChatID()
Get chat type:
user, chat, channelCopy
if c.ChatType() == telegram.EntityUser {
// Private chat
}
Answer Callback
Basic Answer
Copy
// Answer with popup message
c.Answer("Button clicked!", &telegram.CallbackOptions{
Alert: false, // Toast notification
})
Response Methods
Edit Message
- Edit Text
- Edit Markup
- Remove Markup
Copy
// Edit message text
c.Edit("Button was clicked!")
// Edit with options
keyboard := telegram.NewKeyboard()
keyboard.AddRow(telegram.Button.Data("New Button", "new_data"))
c.Edit("Updated text", &telegram.SendOptions{
ParseMode: "HTML",
ReplyMarkup: keyboard,
})
Send Messages
Copy
// Reply to the message with button
msg, err := c.Reply("Replying to your click")
Message Operations
Get Message
Copy
// Get the message that has the button
msg, err := c.GetMessage()
if err == nil {
fmt.Println("Message text:", msg.Text())
}
Delete Message
Copy
// Delete message with button
affected, err := c.Delete()
if err == nil {
fmt.Println("Message deleted")
}
Forward Message
Copy
// Forward message to another chat
msg, err := c.ForwardTo(targetChatID, &telegram.ForwardOptions{
Silent: true,
})
Chat Type Checks
- Private
- Group
- Channel
Copy
if c.IsPrivate() {
c.Answer("Private chat callback")
}
Advanced Features
Conversations
Copy
// Start conversation after callback
response, err := c.Ask("What's your name?")
if err == nil {
c.Respond("Hello, " + response.Text())
}
Get Related Objects
Copy
// Get chat object
chat, err := c.GetChat()
// Get channel object
channel, err := c.GetChannel()
// Get sender user
sender, err := c.GetSender()
Practical Examples
Button Navigation
Copy
client.On("callback", func(c *telegram.CallbackQuery) error {
data := c.DataString()
switch data {
case "menu_main":
keyboard := telegram.NewKeyboard()
keyboard.AddRow(
telegram.Button.Data("📝 Help", "menu_help"),
telegram.Button.Data("ℹ️ About", "menu_about"),
)
c.Edit("Main Menu", &telegram.SendOptions{
ReplyMarkup: keyboard,
})
c.Answer("Main menu opened")
case "menu_help":
keyboard := telegram.NewKeyboard()
keyboard.AddRow(telegram.Button.Data("« Back", "menu_main"))
c.Edit("Help Section\n\nCommands:\n/start\n/help",
&telegram.SendOptions{
ReplyMarkup: keyboard,
})
c.Answer("Help")
case "menu_about":
keyboard := telegram.NewKeyboard()
keyboard.AddRow(telegram.Button.Data("« Back", "menu_main"))
c.Edit("About Bot\n\nVersion 1.0", &telegram.SendOptions{
ReplyMarkup: keyboard,
})
c.Answer("About")
}
return nil
})
Confirmation Dialog
Copy
client.On("callback:delete_", func(c *telegram.CallbackQuery) error {
data := c.DataString()
if data == "delete_confirm" {
c.Delete()
c.Answer("Message deleted!", &telegram.CallbackOptions{
Alert: true,
})
} else if data == "delete_cancel" {
c.Edit("Deletion cancelled")
c.Answer("Cancelled")
}
return nil
})
// Initial message with confirmation
client.On("cmd:delete", func(m *telegram.NewMessage) error {
keyboard := telegram.NewKeyboard()
keyboard.AddRow(
telegram.Button.Data("✅ Yes", "delete_confirm"),
telegram.Button.Data("❌ No", "delete_cancel"),
)
m.Reply("Are you sure?", telegram.SendOptions{
ReplyMarkup: keyboard,
})
return nil
})
Pagination
Copy
client.On("callback:page_", func(c *telegram.CallbackQuery) error {
data := c.DataString()
page := 1
// Parse page number from data
fmt.Sscanf(data, "page_%d", &page)
// Get items for page
items := getItemsForPage(page)
// Build message
text := fmt.Sprintf("Page %d\n\n%s", page, items)
// Build pagination buttons
keyboard := telegram.NewKeyboard()
row := []telegram.Button{}
if page > 1 {
row = append(row, telegram.Button.Data("« Prev", fmt.Sprintf("page_%d", page-1)))
}
row = append(row, telegram.Button.Data(fmt.Sprintf("· %d ·", page), "page_current"))
row = append(row, telegram.Button.Data("Next »", fmt.Sprintf("page_%d", page+1)))
keyboard.Row(row...)
c.Edit(text, &telegram.SendOptions{
ReplyMarkup: keyboard,
})
c.Answer(fmt.Sprintf("Page %d", page))
return nil
})
Admin Actions
Copy
adminIDs := []int64{123456789, 987654321}
client.On("callback:admin_", func(c *telegram.CallbackQuery) error {
// Check if user is admin
isAdmin := false
for _, id := range adminIDs {
if c.GetSenderID() == id {
isAdmin = true
break
}
}
if !isAdmin {
c.Answer("Access denied!", &telegram.CallbackOptions{
Alert: true,
})
return nil
}
data := c.DataString()
switch data {
case "admin_ban":
// Ban user
c.Answer("User banned", &telegram.CallbackOptions{
Alert: true,
})
case "admin_delete":
// Delete message
c.Delete()
c.Answer("Deleted")
case "admin_warn":
// Warn user
c.Answer("User warned", &telegram.CallbackOptions{
Alert: true,
})
}
return nil
})
Loading States
Copy
client.On("callback:process", func(c *telegram.CallbackQuery) error {
// Show loading
c.Edit("Processing... ⏳")
c.Answer("Please wait...")
// Do some work
time.Sleep(2 * time.Second)
// Show result
keyboard := telegram.NewKeyboard()
keyboard.AddRow(telegram.Button.Data("Do Again", "process"))
c.Edit("✅ Complete!", &telegram.SendOptions{
ReplyMarkup: keyboard,
})
c.Answer("Done!")
return nil
})
Data with Parameters
Copy
client.On("callback:action_", func(c *telegram.CallbackQuery) error {
data := c.DataString()
// Parse action and parameter
// Format: "action_TYPE_PARAM"
parts := strings.Split(data, "_")
if len(parts) < 3 {
return nil
}
action := parts[1]
param := parts[2]
switch action {
case "like":
c.Answer(fmt.Sprintf("Liked item %s", param))
case "share":
c.Answer(fmt.Sprintf("Shared item %s", param))
case "delete":
c.Answer(fmt.Sprintf("Deleted item %s", param),
&telegram.CallbackOptions{Alert: true})
}
return nil
})
Complete Example
Copy
package main
import (
"fmt"
"github.com/amarnathcjd/gogram/telegram"
)
func main() {
client, _ := telegram.NewClient(telegram.ClientConfig{
AppID: 6, AppHash: "app_hash",
})
client.LoginBot("bot_token")
// Send button
client.On("cmd:start", func(m *telegram.NewMessage) error {
keyboard := telegram.NewKeyboard()
keyboard.AddRow(
telegram.Button.Data("👍 Like", "action_like"),
telegram.Button.Data("❤️ Love", "action_love"),
)
keyboard.AddRow(
telegram.Button.Data("ℹ️ Info", "action_info"),
)
m.Reply("Welcome! Click a button:", telegram.SendOptions{
ReplyMarkup: keyboard,
})
return nil
})
// Handle callbacks
client.On("callback", func(c *telegram.CallbackQuery) error {
data := c.DataString()
sender, _ := c.GetSender()
fmt.Printf("Callback from %s: %s\n",
sender.FirstName, data)
switch data {
case "action_like":
c.Answer("You clicked Like! 👍")
c.Edit("You liked this message! 👍")
case "action_love":
c.Answer("You clicked Love! ❤️",
&telegram.CallbackOptions{Alert: true})
c.Edit("You loved this message! ❤️")
case "action_info":
keyboard := telegram.NewKeyboard()
keyboard.AddRow(telegram.Button.Data("« Back", "action_back"))
c.Edit("Bot Info\n\nVersion 1.0\nBy @YourBot",
&telegram.SendOptions{
ReplyMarkup: keyboard,
})
c.Answer("Info")
case "action_back":
keyboard := telegram.NewKeyboard()
keyboard.AddRow(
telegram.Button.Data("👍 Like", "action_like"),
telegram.Button.Data("❤️ Love", "action_love"),
)
keyboard.AddRow(
telegram.Button.Data("ℹ️ Info", "action_info"),
)
c.Edit("Welcome! Click a button:", telegram.SendOptions{
ReplyMarkup: keyboard,
})
c.Answer("Main menu")
}
return nil
})
client.Idle()
}