Guides

Working with Messages

Main Walkthrough 6 of 22

Message Updates

There are three updates that are directly related to messages:

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 ignoreOutgoing option 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.

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);
});