Plugin Class
Understand the Plugin class structure.
Metadata
Metadata should be defined as plain strings. No concatenation or formatting, since it's parsed using AST.
Required fields: __id__ and __name__. The engine also validates __min_version__ if it's present.
__id__: Must be 2-32 characters long, start with a letter, and contain only latin letters, numbers, dashes (-) and underscores (_).
__author__: Supports plain text names or Telegram usernames/channel links (e.g., @yourUsername or @yourPluginChannel). These may be displayed as clickable links in the UI.
__description__: Supports basic markdown for formatting.
__version__: If not defined, your plugin will have version 1.0 by default.
__icon__: To fill this field, use the short name of a sticker pack followed by the index of the sticker, separated by a slash (/). The index starts from 0. For example, if your sticker pack's link is https://t.me/addstickers/MyPackName, its short name is MyPackName, and to use the second sticker you would write MyPackName/1.
Settings
You can create a settings screen for your plugin to allow users to configure its behavior. This is done by implementing the create_settings method in your plugin class.
For detailed information on how to create settings, what UI components are available, and how to handle user input, please refer to the dedicated Plugin Settings page.
Plugin events
Load and unload
on_plugin_loadoccurs when user enables the plugin or on application startup.on_plugin_unloadoccurs when user disables the plugin or on application shutdown.
Application events
The AppEvent enum provides the following events:
START- Application is startingSTOP- Application is stoppingPAUSE- Application is paused (e.g., backgrounded)RESUME- Application is resumed (e.g., brought to foreground)
Menu Items
You can add custom actions to various menus within the application, such as the context menu for messages or the action menu in a user's profile. This is done by adding a MenuItemData object.
MenuItemData
To add a menu item, you call self.add_menu_item() with a MenuItemData object, which has the following properties:
menu_type: MenuItemType: Required. Specifies which menu to add the item to. The available types are:MenuItemType.MESSAGE_CONTEXT_MENU: Menu when pressing a message.MenuItemType.DRAWER_MENU: The main navigation drawer (hamburger menu).MenuItemType.CHAT_ACTION_MENU: The three-dot menu inside a chat screen.MenuItemType.PROFILE_ACTION_MENU: The three-dot menu on a user, bot, or channel profile screen.
text: str: Required. The text displayed for the menu item.on_click: Callable[[Dict[str, Any]], None]: Required. A function that will be called when the user taps the item. It receives a dictionary containing context-specific data.item_id: str: Optional. A unique ID for this item. Useful if you need to remove it later withremove_menu_item(). If not provided, a unique ID is generated.icon: str: Optional. The name of a drawable resource to use as an icon for the item (e.g.,"msg_info","msg_delete").subtext: str: Optional. Additional text displayed below the main text.condition: str: Optional. A MVEL expression to conditionally show the item. (e.g.,"message.isOut()").priority: int: Optional. A number to influence the item's position in the menu. Higher numbers appear first.
The on_click Context
The on_click callback receives a dictionary with data relevant to the context where the menu was opened. The available keys depend on the MenuItemType and the specific situation. For example, a message context menu will provide a message object, while a profile menu will provide a user object.
It's best practice to check for the existence of a key before using it. You can log the dictionary's keys to discover what's available: self.log(f"Context keys: {list(context.keys())}").
Here are some of the possible keys you might find in the context dictionary:
account: int: The current user account instance number.context: android.content.Context: The Android application context.fragment: org.telegram.ui.ActionBar.BaseFragment: The current UI fragment.dialog_id: long: The dialog ID for the current chat.user: TLRPC.User: TheUserobject (e.g., in a profile menu).userId: long: The ID of theuser.userFull: TLRPC.UserFull: TheUserFullobject with more details.chat: TLRPC.Chat: TheChatobject for a basic group or channel.chatId: long: The ID of thechat.chatFull: TLRPC.ChatFull: TheChatFullobject with more details.encryptedChat: TLRPC.EncryptedChat: The object for a secret chat.message: org.telegram.messenger.MessageObject: TheMessageObjectthat was clicked on.groupedMessages: org.telegram.messenger.MessageObject.GroupedMessages: Information about grouped media (albums).botInfo: TL_bots.BotInfo: Information about a bot.
Removing Menu Items
If you provided a custom item_id when adding a menu item, you can remove it programmatically using self.remove_menu_item(item_id). However, in most cases, this is not necessary, as all of a plugin's menu items are automatically removed when the plugin is unloaded.
Hooks
To intercept network requests, responses, or client-side events, you first need to register a hook.
You can register hooks for specific Telegram API requests using their TL-schema name:
self.add_hook("TL_messages_readHistory", match_substring: bool = False, priority: int = 0)
name: The name of the event or request (e.g., "TL_messages_readHistory").match_substring: IfTrue, the hook will trigger ifnameis a substring of the actual event/request name. Defaults toFalse.priority: Hooks with higher priority are executed first. Defaults to0.
Examples:
self.add_hook("TL_messages_readHistory")self.add_hook("requestCall")self.add_hook("TL_channels_readHistory")
The list of names for requests could be found here.
For the common case of hooking message sending, you can use a helper:
self.add_on_send_message_hook(priority: int = 0)
API Request Hooks
These hooks allow you to inspect or modify outgoing requests and incoming responses.
Here is a practical example of a "Ghost Mode" plugin that blocks the "typing" status and forces the user to appear offline.
Hook results determine the action to take:
HookStrategy.DEFAULT: No changes to the flow; proceed as normal.HookStrategy.CANCEL: Cancel the request (forpre_request_hookandon_send_message_hook) or suppress further processing of the response/update.HookStrategy.MODIFY: Modify therequest(inpre_request_hook),response(inpost_request_hook),update(inon_update_hook),updates(inon_updates_hook), orparams(inon_send_message_hook). The modified object must be assigned to the corresponding field in theHookResult(e.g.,result.request = modified_request).HookStrategy.MODIFY_FINAL: Same asMODIFY, but no other plugins hooks for this event will be called after this one.
Update Hooks
These hooks are called when the application processes updates received from Telegram.
Message Sending Hook
This hook is specifically for intercepting messages being sent by the user.