Skip to content

sendChatAction

Returns: TrueOfficial docs ↗

Use this method when you need to tell the user that something is happening on the bot's side. The status is set for 5 seconds or less (when a message arrives from your bot, Telegram clients clear its typing status). Returns True on success.

Example: The ImageBot needs some time to process a request and upload the image. Instead of sending a text message along the lines of “Retrieving image, please wait…”, the bot may use sendChatAction with action = upload_photo. The user will see a “sending photo” status for the bot.

We only recommend using this method when a response from the bot will take a noticeable amount of time to arrive.

Parameters

business_connection_idStringOptional
Unique identifier of the business connection on behalf of which the action will be sent
chat_idIntegerStringRequired
Unique identifier for the target chat or username of the target supergroup (in the format @supergroupusername). Channel chats and channel direct messages chats aren't supported.
message_thread_idIntegerOptional
Unique identifier for the target message thread or topic of a forum; for supergroups and private chats of bots with forum topic mode enabled only
actionStringRequired
Values:typingupload_photorecord_videoupload_videorecord_voiceupload_voiceupload_documentchoose_stickerfind_locationrecord_video_noteupload_video_note
Type of action to broadcast. Choose one, depending on what the user is about to receive: typing for text messages, upload\photo for photos, record\video or upload\video for videos, record\voice or upload\voice for voice notes, upload\document for general files, choose\sticker for stickers, find\location for location data, record\video\note or upload\video\note for video notes.

Returns

On success, True is returned.

GramIO Usage

Show a "typing..." indicator before sending a slow response:

ts
bot
.
on
("message", async (
ctx
) => {
await
ctx
.
sendChatAction
("typing");
// Simulate a slow operation await new
Promise
((
resolve
) =>
setTimeout
(
resolve
, 2000));
await
ctx
.
send
("Here is your answer after processing!");
});

Show upload_document while preparing a file to send:

ts
bot
.
on
("message", async (
ctx
) => {
await
ctx
.
sendChatAction
("upload_document");
const
file
= await
MediaUpload
.
path
("./reports/report.pdf");
await
ctx
.
sendDocument
(
file
, {
caption
: "Your report is ready." });
});

Repeat the action every 4 seconds for a long-running task using a loop:

ts
bot
.
on
("message", async (
ctx
) => {
// sendChatAction expires after ~5 s; refresh it periodically const
interval
=
setInterval
(
() =>
ctx
.
sendChatAction
("typing").
catch
(() => {}),
4000 ); try { // Long operation (e.g., external API call) await new
Promise
((
resolve
) =>
setTimeout
(
resolve
, 10000));
await
ctx
.
send
("Done!");
} finally {
clearInterval
(
interval
);
} });

Direct API call with bot.api.sendChatAction (useful outside message handlers):

ts
await 
bot
.
api
.
sendChatAction
({
chat_id
: 123456789,
action
: "upload_photo",
});

Errors

CodeErrorCause
400Bad Request: chat not foundThe chat_id is invalid, the bot has never interacted with the user, or the chat does not exist.
400Bad Request: not enough rightsThe bot lacks permission to send messages in the target group or channel.
403Forbidden: bot was blocked by the userThe user blocked the bot. Remove them from your active user list.
403Forbidden: bot is not a member of the channel chatThe bot is not a member of the target channel.
429Too Many Requests: retry after NFlood control triggered. Back off for the specified number of seconds.

TIP

Use GramIO's auto-retry plugin to handle 429 errors automatically.

Tips & Gotchas

  • The indicator lasts at most 5 seconds. Once your bot sends any message, Telegram immediately clears the indicator. For operations longer than 5 seconds, call sendChatAction in a loop every ~4 seconds.
  • Choose the matching action. Pick the action that corresponds to what you are about to send — upload_document for files, upload_photo for images, record_video for video processing, etc. Using typing for everything is misleading to users.
  • Channels are not supported. The chat_id must be a private chat, group, or supergroup. Channel chat IDs will return an error.
  • Errors in the loop should be swallowed. If you run sendChatAction in an interval, wrap each call in .catch(() => {}) so a transient error does not kill the loop.
  • Use message_thread_id for forum topics. In supergroups with topics enabled, pass message_thread_id to show the indicator inside the correct topic thread.

See Also