Skip to main content
Telebot provides a unified API for constructing both inline keyboards (attached to messages) and reply keyboards (shown below the input field).

ReplyMarkup

ReplyMarkup is the single struct used for all keyboard types. Populate either InlineKeyboard or ReplyKeyboard, not both.
type ReplyMarkup struct {
    InlineKeyboard  [][]InlineButton `json:"inline_keyboard,omitempty"`
    ReplyKeyboard   [][]ReplyButton  `json:"keyboard,omitempty"`
    ForceReply      bool             `json:"force_reply,omitempty"`
    ResizeKeyboard  bool             `json:"resize_keyboard,omitempty"`
    OneTimeKeyboard bool             `json:"one_time_keyboard,omitempty"`
    RemoveKeyboard  bool             `json:"remove_keyboard,omitempty"`
    Selective       bool             `json:"selective,omitempty"`
    Placeholder     string           `json:"input_field_placeholder,omitempty"`
    IsPersistent    bool             `json:"is_persistent,omitempty"`
}

Fields

InlineKeyboard
[][]InlineButton
Grid of inline buttons rendered inside the message.
ReplyKeyboard
[][]ReplyButton
Grid of reply keyboard buttons shown below the text input.
ForceReply
bool
Forces the client to display a reply interface as if the user tapped “Reply”.
ResizeKeyboard
bool
Requests the client to resize the reply keyboard vertically for optimal fit.
OneTimeKeyboard
bool
Hides the reply keyboard after it has been used once.
RemoveKeyboard
bool
Requests the client to remove the reply keyboard.
Selective
bool
When true, the keyboard is shown only to mentioned users and the sender of the original message (when replying).
Placeholder
string
Placeholder text shown in the input field when the reply keyboard is active. JSON: input_field_placeholder.
IsPersistent
bool
When true, the reply keyboard is always shown (not collapsed).

Btn

Btn is a constructor button type that becomes either an InlineButton or a ReplyButton when you call .Inline() or .Reply() on it.
type Btn struct {
    Unique          string          `json:"unique,omitempty"`
    Text            string          `json:"text,omitempty"`
    URL             string          `json:"url,omitempty"`
    Data            string          `json:"callback_data,omitempty"`
    InlineQuery     string          `json:"switch_inline_query,omitempty"`
    InlineQueryChat string          `json:"switch_inline_query_current_chat,omitempty"`
    Login           *Login          `json:"login_url,omitempty"`
    WebApp          *WebApp         `json:"web_app,omitempty"`
    Contact         bool            `json:"request_contact,omitempty"`
    Location        bool            `json:"request_location,omitempty"`
    Poll            PollType        `json:"request_poll,omitempty"`
    User            *ReplyRecipient `json:"request_user,omitempty"`
    Chat            *ReplyRecipient `json:"request_chat,omitempty"`
    CopyText        *CopyTextButton `json:"copy_text,omitempty"`
}
Unique
string
Callback endpoint unique name. Set this to make the button an inline callback button that routes to a registered handler.
Text
string
Button label text.
URL
string
URL to open when the button is pressed (inline only).
Data
string
Raw callback data string (inline only). When Unique is set, this becomes the payload appended after the unique identifier.
InlineQuery
string
Switches to inline mode with the given query in the chosen chat.
InlineQueryChat
string
Switches to inline mode with the given query in the current chat.
Login
*Login
Telegram Login Widget parameters.
WebApp
*WebApp
Web App to launch.
Contact
bool
Request the user’s phone number (reply keyboard only).
Location
bool
Request the user’s current location (reply keyboard only).
Poll
PollType
Request a poll creation (reply keyboard only). Use PollAny, PollQuiz, or PollRegular.
User
*ReplyRecipient
Request user sharing (reply keyboard only).
Chat
*ReplyRecipient
Request chat sharing (reply keyboard only).
CopyText
*CopyTextButton
Copy the given text to clipboard when pressed.

Button Constructors

All constructors are methods on *ReplyMarkup and return a Btn.

Text

func (r *ReplyMarkup) Text(text string) Btn
Creates a plain reply keyboard button.

Contact

func (r *ReplyMarkup) Contact(text string) Btn
Creates a button that requests the user’s phone number.

Location

func (r *ReplyMarkup) Location(text string) Btn
Creates a button that requests the user’s location.

Poll

func (r *ReplyMarkup) Poll(text string, poll PollType) Btn
Creates a button that requests a poll creation of the given type.

Data

func (r *ReplyMarkup) Data(text, unique string, data ...string) Btn
Creates an inline callback button. unique is the endpoint name registered with b.Handle. The optional data strings are joined with | and become the callback payload.
btnSettings := rm.Data("\u2699 Settings", "settings")
btnDelete   := rm.Data("Delete", "delete", strconv.Itoa(itemID))

b.Handle(&btnSettings, func(c tele.Context) error {
    return c.Edit("Settings menu")
})

URL

func (r *ReplyMarkup) URL(text, url string) Btn
Creates an inline button that opens a URL.

Query

func (r *ReplyMarkup) Query(text, query string) Btn
Creates an inline button that switches to inline mode with the given query.

QueryChat

func (r *ReplyMarkup) QueryChat(text, query string) Btn
Creates an inline button that switches to inline mode in the current chat.

Login

func (r *ReplyMarkup) Login(text string, login *Login) Btn
Creates an inline button for Telegram Login.

WebApp

func (r *ReplyMarkup) WebApp(text string, app *WebApp) Btn
Creates an inline button that launches a Web App.

User

func (r *ReplyMarkup) User(text string, user *ReplyRecipient) Btn
Creates a reply keyboard button that requests user sharing.

Chat

func (r *ReplyMarkup) Chat(text string, chat *ReplyRecipient) Btn
Creates a reply keyboard button that requests chat sharing.

CopyText

func (r *ReplyMarkup) CopyText(text, copyText string) Btn
Creates an inline button that copies copyText to the clipboard.

Layout Builders

Row

func (r *ReplyMarkup) Row(many ...Btn) Row
Groups buttons into a single row.

Split

func (r *ReplyMarkup) Split(max int, btns []Btn) []Row
Splits a flat slice of buttons into rows with at most max buttons each.
rows := rm.Split(3, []tele.Btn{b1, b2, b3, b4, b5, b6})
// -> [[b1, b2, b3], [b4, b5, b6]]

Inline

func (r *ReplyMarkup) Inline(rows ...Row)
Populates r.InlineKeyboard from the given rows. Panics if any button is not a valid inline button (i.e. has no Unique, URL, Data, or other inline field).

Reply

func (r *ReplyMarkup) Reply(rows ...Row)
Populates r.ReplyKeyboard from the given rows. Panics if any button cannot be a reply button (e.g. has a Unique field set).

Usage Pattern

rm := &tele.ReplyMarkup{}

btnHelp := rm.Text("Help")
btnSettings := rm.Data("Settings", "settings")
btnURL := rm.URL("Visit site", "https://example.com")

// Reply keyboard
rm.Reply(
    rm.Row(btnHelp),
)

// Inline keyboard
rm.Inline(
    rm.Row(btnSettings, btnURL),
)

b.Send(recipient, "Choose an option:", rm)
Callback buttons registered via Data() must be handled with b.Handle(&btn, handler) using a pointer to the Btn value, or via the unique string prefixed with \f.

InlineButton

The low-level inline button type used inside ReplyMarkup.InlineKeyboard.
type InlineButton struct {
    Unique                string             `json:"unique,omitempty"`
    Text                  string             `json:"text"`
    URL                   string             `json:"url,omitempty"`
    Data                  string             `json:"callback_data,omitempty"`
    InlineQuery           string             `json:"switch_inline_query,omitempty"`
    InlineQueryChat       string             `json:"switch_inline_query_current_chat"`
    InlineQueryChosenChat *SwitchInlineQuery `json:"switch_inline_query_chosen_chat,omitempty"`
    Login                 *Login             `json:"login_url,omitempty"`
    WebApp                *WebApp            `json:"web_app,omitempty"`
    CallbackGame          *CallbackGame      `json:"callback_game,omitempty"`
    Pay                   bool               `json:"pay,omitempty"`
    CopyText              *CopyTextButton    `json:"copy_text,omitempty"`
}

With

func (t *InlineButton) With(data string) *InlineButton
Returns a copy of the button with the given callback data. Useful for reusing the same button definition with different payloads.

ReplyButton

The low-level reply keyboard button type.
type ReplyButton struct {
    Text     string          `json:"text"`
    Contact  bool            `json:"request_contact,omitempty"`
    Location bool            `json:"request_location,omitempty"`
    Poll     PollType        `json:"request_poll,omitempty"`
    User     *ReplyRecipient `json:"request_users,omitempty"`
    Chat     *ReplyRecipient `json:"request_chat,omitempty"`
    WebApp   *WebApp         `json:"web_app,omitempty"`
}

Login

Parameters for a Telegram Login inline button.
type Login struct {
    URL         string `json:"url"`
    Text        string `json:"forward_text,omitempty"`
    Username    string `json:"bot_username,omitempty"`
    WriteAccess bool   `json:"request_write_access,omitempty"`
}

Describes the bot’s menu button in a private chat.
type MenuButton struct {
    Type   MenuButtonType `json:"type"`
    Text   string         `json:"text,omitempty"`
    WebApp *WebApp        `json:"web_app,omitempty"`
}

const (
    MenuButtonDefault  MenuButtonType = "default"
    MenuButtonCommands MenuButtonType = "commands"
    MenuButtonWebApp   MenuButtonType = "web_app"
)

Build docs developers (and LLMs) love