Webhook receives my_chat_member update instead of message when users trigger /start command

I’m working with a Telegram bot that uses webhooks to receive updates. Most of the time when users send the /start command, my server gets the expected message object:

{
   "update_id": 12345678,
   "message": {
      "message_id": 1001,
      "from": {
         "id": 987654321,
         "is_bot": false,
         "first_name": "John",
         "last_name": "Smith",
         "language_code": "en"
      },
      "chat": {
         "id": 987654321,
         "first_name": "John",
         "last_name": "Smith",
         "type": "private"
      },
      "date": 1634567890,
      "text": "/start",
      "entities": [
         {
            "offset": 0,
            "length": 6,
            "type": "bot_command"
         }
      ]
   }
}

But sometimes, especially with first-time users, I get a my_chat_member object instead:

{
   "update_id": 87654321,
   "my_chat_member": {
      "chat": {
         "id": 123456789,
         "first_name": "Alice",
         "type": "private"
      },
      "from": {
         "id": 123456789,
         "is_bot": false,
         "first_name": "Alice",
         "language_code": "es"
      },
      "date": 1634560000,
      "old_chat_member": {
         "user": {
            "id": 111222333,
            "is_bot": true,
            "first_name": "MyBot",
            "username": "my_awesome_bot"
         },
         "status": "member"
      },
      "new_chat_member": {
         "user": {
            "id": 111222333,
            "is_bot": true,
            "first_name": "MyBot",
            "username": "my_awesome_bot"
         },
         "status": "kicked",
         "until_date": 0
      }
   }
}

When this happens, I don’t receive the actual /start command text. This issue occurs across different platforms including mobile apps and web clients. What could be causing this behavior and how can I handle it properly?

This scenario occurs when users are unblocking your bot by issuing the /start command. You’ll receive a my_chat_member update that denotes the status change from ‘kicked’ to ‘member’, but Telegram does not consistently send the corresponding message update immediately. I’ve encountered this issue in production as well. The best approach is to treat my_chat_member updates where the status transitions from ‘kicked’ to ‘member’ as equivalent to a /start command. In your webhook handler, verify if the new_chat_member status is ‘member’ and the previous status was ‘kicked’, then proceed to execute your start command logic. Implementing a brief delay or a queuing mechanism is advisable, as the actual message may arrive a few seconds later, helping to avoid duplicate processing. This is a frequent occurrence when users access your bot via deep links or bot directories.

yeah, i’ve hit this bug too. telegram fires my_chat_member when someone restarts your bot after blocking it. here’s what happens: user blocks bot → status becomes ‘kicked’ → they hit /start → status flips back to ‘member’ but the actual /start message disappears. just watch for that status change in your webhook and handle it like a start command.

Had the exact same issue with my customer service bot last year. Telegram prioritizes membership status updates over messages when users unblock your bot - that’s what’s causing this. Here’s what fixed it for me: handle both regular message updates AND my_chat_member updates in your webhook. The my_chat_member ones show when status changes from kicked to member. The annoying part is avoiding duplicate responses when both updates finally show up. I fixed this by caching user interactions with timestamps - check the cache before running your start logic. Also noticed this happens way more on iOS than Android. Make sure your webhook handles both update types since you’ll miss real user interactions if you only watch for messages.