Working with Messages
Message Updates
There are three updates that are directly related to messages:
- UpdateNewMessage — Received when a message is received or sent.
- UpdateEditedMessage — Received when a message is edited.
- UpdateDeletedMessages — Received when one or more messages are deleted.
Here are some examples on adding listeners for each of them:
client.on("message", (ctx) => {
// called when a message is received or sent
});
client.on("editedMessage", (ctx) => {
// called when a message is edited
});
client.on("deletedMessages", (ctx) => {
// called when one or more messages are deleted
});
To see how the context object would look like for each update, you can refer to their specific documentation pages linked above.
Filtering Message Types
There is a significant number of different types of messages, which makes processing all of them in a single handler a little harder.
Fortunately, you can easily filter out messages by their types when assigning your handler. Here are some examples:
client.on("message:text", (ctx) => {
// This handler is called only when text messages are received.
// So ctx.msg.text is always set.
});
client.on("editedMessage:photo", (ctx) => {
// This handler is called only when photo messages are edited.
// So ctx.msg.photo is always set.
});
Accessing the Message in Handlers
You can access the received message through ctx.msg or ctx.update.message.
client.on("message", (ctx) => {
// Both ctx.msg and ctx.update.message are referring to the received message.
});
Edited messages are accessed through ctx.msg and ctx.update.editedMessage.
client.on("editedMessage", (ctx) => {
// Both ctx.msg and ctx.update.editedMessage are referring to the edited message.
});
ctx.msg is just a shortcut that resolves to ctx.update.message ?? ctx.update.editedMessage. See Message.
Updates for deleted messages don’t include full message objects, only references to them (see MessageReference).
client.on("deletedMessages", (ctx) => {
// ctx.update.deletedMessages is an array of MessageReference.
});
NotesBOT-ONLY
- UpdateDeletedMessages is not always sent to bots, so it is recommended that you don’t depend on it for bots.
- Updates for outgoing messages are not sent for bots by default, but you can disable the
ignoreOutgoingoption to receive them:
const client = new Client({
outgoingMessages: false,
/* ... */
});
Sending Messages
There are multiple methods that can be used to send messages. Each of them is used for sending a specific type of message.
- sendMessage — For sending text messages.
- sendPhoto — For sending photos.
- sendDocument — For sending files.
- sendVideo — For sending videos.
- sendAnimation — For sending animations.
- sendAudio — For sending audio files.
- sendVoice — For sending voice messages.
- sendVideoNote — For sending video notes.
- sendDice — For sending dice messages.
- sendLocation — For sending locations.
- sendVenue — For sending venues.
- sendPoll — For sending polls.
- sendContact — For sending contacts.
- sendChecklist — For sending checklists.
Here are some example calls:
const chat = /* ... */; // ID
const file = /* ... */; // FileSource
await client.sendMessage(
chat,
"Hey!",
{ isSilent: true, /* other optional options */ }
);
await client.sendPhoto(chat, file, { caption: "Optional Caption", /* other optional options */ });
await client.sendDocument(chat, file, { caption: "Optional Caption", /* ooo */ });
await client.sendVideo(chat, file, { caption: "Optional Caption", /* ooo */ });
await client.sendAnimation(chat, file, { caption: "Optional Caption", /* ooo */ });
await client.sendAudio(chat, file, { caption: "Optional Caption", /* ooo */ });
await client.sendVoice(chat, file, { caption: "Optional Caption", /* ooo */ });
await client.sendDice(chat); // defaults to 🎲
await client.sendDice(chat, { emoji: "🏀" }); // but you can send any valid dice
To use the above example calls, chat must be replaced with a valid ID, and file must be replaced with a valid FileSource.
As previously said, the last parameters are optional and can always be omitted, so for example you can do just await client.sendMessage(chat, "Hey!"); if you don’t specify any optional parameter. Optional parameters are those parameters marked with ? in the method documentation.
Inside handlers, you can call the respective reply* shortcuts to easily reply the context message:
client.on("message", async (ctx) => {
await ctx.reply(text); // same as client.sendMessage(ctx.chat.id, text, { replyToMessageId: ctx.msg.id });
await ctx.replyPhoto(file); // same as client.sendPhoto(ctx.chat.id, file, { replyToMessageId: ctx.msg.id });
});
Editing Messages
You can edit messages that have already been sent. Each method targets a specific part of the message, and the referenced message must already be of a matching type.
Editing Text
Use editMessageText to change the text of a text message.
await client.editMessageText(chatId, messageId, "Updated text");
Like sendMessage, it accepts formatting options.
await client.editMessageText(chatId, messageId, "*Updated* text", {
parseMode: "Markdown",
});
Editing Captions
Use editMessageCaption to change the caption of a media message.
await client.editMessageCaption(chatId, messageId, {
caption: "New caption",
});
Replacing Media
Use editMessageMedia to replace the media of a media message. Pass an InputMedia describing the new media.
await client.editMessageMedia(chatId, messageId, {
type: "photo",
photo: new URL("https://example.com/photo.jpg"),
caption: "New caption",
});
Editing Reply Markup
Use editMessageReplyMarkup to update the buttons attached to a message without changing its content.
await client.editMessageReplyMarkup(chatId, messageId, {
replyMarkup: {/* ... */},
});
Live locations can be updated with editMessageLiveLocation, and rich text messages with editMessageRichText.
Deleting Messages
You can delete messages by calling either deleteMessage or deleteMessages.
await ctx.deleteMessage(messageId);
await ctx.deleteMessages([...messageIds]);
You can delete the context message with delete:
client.on("message", async (ctx) => {
await ctx.delete(); // This deletes the received message.
});
Forwarding Messages
You can forward messages by calling either forwardMessage or forwardMessages.
await ctx.forwardMessage(toChat, messageId);
await ctx.forwardMessages(toChat, messageIds);
You can forward the context message with forward:
client.on("message", async (ctx) => {
await ctx.forward(toChat); // This forwards the received message.
});
Pinned Messages
Pinning a message keeps it at the top of a chat so members can find it easily. Both users and bots can pin messages, provided they have the rights to do so in the chat.
Pinning a Message
Use pinMessage to pin a message.
await client.pinMessage(chatId, messageId);
In private chats, the pin is visible to both participants by default. Pass isForBothSides as false to pin it only for the current account.
await client.pinMessage(chatId, messageId, {
isForBothSides: false,
});
Pass isSilent to pin without notifying the chat.
await client.pinMessage(chatId, messageId, {
isSilent: true,
});
Unpinning Messages
Use unpinMessage to unpin a single message.
await client.unpinMessage(chatId, messageId);
Use unpinMessages to unpin every pinned message in a chat at once.
await client.unpinMessages(chatId);
In a forum, pass a topicId to unpin only the messages in that topic.
await client.unpinMessages(chatId, {
topicId,
});
Receiving Pin Notifications
When a message is pinned in a group, a service message of type pinnedMessage is added to the chat. Listen for it like any other message, and read the pinned message through ctx.msg.pinnedMessage.
client.on("message:pinnedMessage", (ctx) => {
const pinned = ctx.msg.pinnedMessage;
console.log("Pinned:", pinned.id);
});