DEV Community

unifyport for UnifyPort

Posted on Originally published at unifyport.ai

Telegram Bot Receives DMs but Not Group Messages? Debug Privacy Mode First

Your Telegram bot receives private messages without a problem.

In a group, it receives /help@your_bot and replies directed at it—but ordinary messages never reach your application.

The first instinct is often to rebuild the webhook, switch to getUpdates, or promote the bot to administrator.

Those changes may be unnecessary.

Telegram enables Privacy Mode for bots by default. A privacy-enabled bot does not receive a complete stream of ordinary group conversation.

The important distinction is:

Group-message visibility and update delivery are separate layers.

A working webhook cannot deliver a message Telegram does not expose to the bot. Disabling Privacy Mode also cannot repair a broken webhook, an incorrect bot token, or an application filter that discards message updates.

Diagnose the layers independently.

Start with the observed behavior

Different symptoms point to different parts of the system.

Observation Likely area to inspect
Private messages arrive, but ordinary group text does not Privacy Mode and group role
Addressed group commands arrive, but ordinary text does not Broad group visibility
Neither private messages nor addressed commands arrive Bot identity, active receiver and update filters
Telegram update reaches the HTTP endpoint, but the app shows nothing Application filtering or queue processing
Privacy Mode was disabled, but behavior did not change Remove and re-add the bot, then retest
Only one group is affected Membership and role in that specific group

Treat these as diagnostic hypotheses rather than guaranteed conclusions.

Before changing settings, record which test messages reached the raw receiver.

What Privacy Mode controls

Privacy Mode controls which group messages Telegram makes available to a bot.

With Privacy Mode enabled, a bot can receive interactions relevant to it, including commands explicitly addressed to its username and replies to the bot’s messages.

For example:

/help@support_example_bot
Enter fullscreen mode Exit fullscreen mode

An ordinary group message such as:

Has anyone received their order?
Enter fullscreen mode Exit fullscreen mode

may not be exposed to a privacy-enabled, non-admin bot.

That behavior is different from private chat, where the user is communicating directly with the bot.

A successful private-message test therefore proves only that:

  • the bot token can identify a bot;
  • at least one receiving path works;
  • the application can process that private update.

It does not prove that the bot is entitled to receive ordinary conversation from a particular group.

Visibility and delivery are different layers

Think of the system as a pipeline:

User sends a group message
        ↓
Telegram evaluates bot visibility
        ↓
Telegram creates an eligible update
        ↓
getUpdates or setWebhook delivers it
        ↓
Application filters the update
        ↓
Business logic processes it
Enter fullscreen mode Exit fullscreen mode

A failure at each layer looks different.

Visibility failure

Telegram never exposes the ordinary group message to the bot.

Changing webhook code does not fix this.

Delivery failure

The bot is eligible to receive the update, but the configured polling or webhook receiver does not deliver it correctly.

Privacy settings do not fix this.

Application-filtering failure

The update reaches your endpoint, but your code ignores it.

Changing the bot’s permissions does not fix this.

Good troubleshooting identifies the failed layer before modifying the next one.

Step 1: confirm the bot identity

A surprisingly common cause is deploying the wrong bot token.

Use getMe from a trusted environment:

curl \
  "https://api.telegram.org/bot$BOT_TOKEN/getMe"
Enter fullscreen mode Exit fullscreen mode

Do not paste the bot token into:

  • screenshots;
  • shared shell logs;
  • support tickets;
  • source code;
  • chat messages.

Check the returned bot identity against the username added to the affected group.

A staging bot and a production bot may have similar names while using completely different tokens and privacy settings.

Check can_read_all_group_messages

The getMe response may include:

{
  "ok": true,
  "result": {
    "id": 123456789,
    "is_bot": true,
    "first_name": "Support Bot",
    "username": "support_example_bot",
    "can_join_groups": true,
    "can_read_all_group_messages": false
  }
}
Enter fullscreen mode Exit fullscreen mode

The relevant field is:

can_read_all_group_messages
Enter fullscreen mode Exit fullscreen mode

According to the Telegram Bot API, true means Privacy Mode is disabled.

This field describes the bot’s Privacy Mode status. It is not a report of the bot’s role in every group.

You must still inspect its membership and permissions in the affected group.

Step 2: run a controlled group test

Use a dedicated test group with informed participants.

Send new messages from a human Telegram account in this order:

  1. A private text message to the bot.
  2. A command addressed to the bot’s exact username.
  3. A reply to a message previously sent by the bot.
  4. An ordinary group text message.
  5. A new ordinary message after any approved configuration change.

Example test messages:

Private chat:
privacy-test-private-001
Enter fullscreen mode Exit fullscreen mode
Group:
 /status@support_example_bot
Enter fullscreen mode Exit fullscreen mode
Reply to bot:
privacy-test-reply-001
Enter fullscreen mode Exit fullscreen mode
Ordinary group text:
privacy-test-group-001
Enter fullscreen mode Exit fullscreen mode

Use distinct values so you can search logs and queue records unambiguously.

Do not use historical messages as the test. Changing permissions does not imply recovery of messages that were never delivered.

Also avoid using another bot as the sender. Bot-to-bot behavior introduces a different set of rules.

Step 3: inspect the raw receiver

Before investigating business logic, determine whether the Telegram update reached your receiving boundary.

For a webhook-based service, temporarily record safe metadata:

app.post("/telegram/webhook", async (req, res) => {
  const update = req.body;

  console.info("telegram_update_received", {
    updateId: update.update_id,
    hasMessage: Boolean(update.message),
    chatId: update.message?.chat?.id,
    chatType: update.message?.chat?.type,
  });

  await storeUpdateIfAbsent(update);

  return res.status(200).end();
});
Enter fullscreen mode Exit fullscreen mode

Do not log the bot token or unnecessary message content.

If the update exists in raw storage but not in the product UI, Privacy Mode is not the immediate cause. The problem is now inside the application.

Inspect:

  • event-type conditions;
  • chat-type filters;
  • queue insertion;
  • duplicate detection;
  • worker failures;
  • database transactions;
  • downstream routing.

Step 4: audit application filters

A handler may accidentally accept only private chats:

if (update.message?.chat?.type !== "private") {
  return;
}
Enter fullscreen mode Exit fullscreen mode

Or it may accept only commands:

if (!update.message?.text?.startsWith("/")) {
  return;
}
Enter fullscreen mode Exit fullscreen mode

A more explicit router makes the boundary easier to inspect:

function classifyTelegramUpdate(update) {
  const message = update.message;

  if (!message) {
    return { kind: "unsupported_update" };
  }

  switch (message.chat.type) {
    case "private":
      return {
        kind: "private_message",
        message,
      };

    case "group":
    case "supergroup":
      return {
        kind: "group_message",
        message,
      };

    default:
      return {
        kind: "unsupported_chat_type",
        message,
      };
  }
}
Enter fullscreen mode Exit fullscreen mode

The application should make its supported chat types visible rather than silently discarding them.

Step 5: check allowed_updates

Telegram’s allowed_updates parameter controls which update types are delivered through the Bot API receiver.

For a group text-message test, the configuration must allow:

message
Enter fullscreen mode Exit fullscreen mode

A conceptual configuration looks like this:

{
  "allowed_updates": [
    "message"
  ]
}
Enter fullscreen mode Exit fullscreen mode

Privacy Mode and allowed_updates solve different problems:

Privacy Mode:
Is the bot eligible to see this group message?

allowed_updates:
Should this eligible update type be delivered to the receiver?
Enter fullscreen mode Exit fullscreen mode

Broader group visibility cannot fix an allowed_updates configuration that excludes message.

Similarly, adding message cannot grant visibility that Telegram has not given the bot.

Telegram also documents that omitting allowed_updates can preserve the previous configuration. Do not assume omission resets it to every update type.

Audit the configuration used by the currently active receiver.

Step 6: verify the receiving mode

Telegram Bot API supports two mutually exclusive receiving modes:

  • getUpdates
  • setWebhook

If private messages and addressed commands arrive through the same receiver, transport is probably not the first problem to change.

If nothing arrives at all, inspect the active receiver with:

curl \
  "https://api.telegram.org/bot$BOT_TOKEN/getWebhookInfo"
Enter fullscreen mode Exit fullscreen mode

A non-empty webhook URL means a webhook is configured.

Do not switch between polling and webhook delivery merely to test Privacy Mode. Delivery transport does not expand group visibility.

Diagnose transport separately using a controlled migration runbook.

Step 7: choose the minimum required access

Before disabling Privacy Mode, ask whether the bot truly needs every ordinary group message.

A command-driven bot may need only:

/help@bot
/status@bot
/assign@bot
Enter fullscreen mode Exit fullscreen mode

A reply-based workflow may need only messages explicitly directed at the bot.

In those cases, keeping Privacy Mode enabled reduces unnecessary data collection.

Consider disabling it only when the product genuinely needs broad group observation, for example:

  • support triage across all group conversation;
  • moderation of ordinary user messages;
  • group analytics with informed participants;
  • workflows triggered by non-command text.

Treat broader visibility as a privacy and access decision, not as a performance optimization.

Do not promote the bot to administrator just for testing

Administrator status carries permissions and responsibilities beyond receiving messages.

Promoting the bot may change behavior, but it also changes the security model.

Do not combine all these changes in one experiment:

Disable Privacy Mode
Promote bot to administrator
Replace webhook
Change allowed_updates
Deploy new handler
Enter fullscreen mode Exit fullscreen mode

If the test starts working, you will not know which change mattered.

Change one layer at a time:

1. Confirm identity
2. Record baseline tests
3. Check Privacy Mode
4. Check group role
5. Check allowed_updates
6. Inspect raw delivery
7. Inspect application filters
Enter fullscreen mode Exit fullscreen mode

This preserves causal evidence.

Disabling Privacy Mode safely

If ordinary group conversation is required:

  1. Confirm the correct bot with getMe.
  2. Explain the broader collection scope to group owners.
  3. Change Privacy Mode through BotFather using /setprivacy.
  4. Remove the bot from the test group.
  5. Re-add the bot to the group.
  6. Verify its intended role.
  7. Send a new human-authored test message.
  8. Inspect the raw receiver before application output.

Telegram documents that the bot must be re-added to the group after Privacy Mode is disabled for the change to take effect.

Do not skip the re-add step and conclude that the setting failed.

Build an acceptance-test matrix

Record results instead of relying on memory.

Test Privacy enabled Privacy disabled and bot re-added
Private text Expected Expected
Addressed command Expected Expected
Reply to bot message Expected Expected
Ordinary human group text Restricted by Privacy Mode Expected when other configuration is correct
Message visible in raw receiver Record result Record result
Message processed by application Record result Record result

The rightmost column is not a guarantee that every application will work. The receiving mode, update filters, group role and handler must still be correct.

Preserve updates idempotently

Once a message reaches the application, use update_id as the delivery-level idempotency key.

async function storeUpdateIfAbsent(update) {
  const inserted = await database.telegramUpdates.insertIfAbsent({
    updateId: update.update_id,
    payload: update,
    receivedAt: new Date(),
  });

  if (!inserted) {
    return false;
  }

  await enqueueTelegramUpdate(update.update_id);
  return true;
}
Enter fullscreen mode Exit fullscreen mode

This prevents webhook retries or polling restarts from creating duplicate downstream work.

Business operations may need their own idempotency keys:

support-ticket:{botId}:{updateId}
moderation-action:{botId}:{updateId}
notification:{botId}:{updateId}
Enter fullscreen mode Exit fullscreen mode

Receiving the same update twice should not create two tickets or apply the same moderation action twice.

A compact diagnostic function

You can turn the troubleshooting logic into an internal checklist:

function diagnoseGroupVisibility({
  privateMessageReceived,
  addressedCommandReceived,
  ordinaryGroupMessageReceived,
  rawUpdateReceived,
  privacyDisabled,
  botReadded,
  messageAllowed,
}) {
  if (!privateMessageReceived && !addressedCommandReceived) {
    return "Check bot identity, receiver mode and allowed_updates";
  }

  if (
    addressedCommandReceived &&
    !ordinaryGroupMessageReceived &&
    !privacyDisabled
  ) {
    return "Behavior is consistent with Privacy Mode";
  }

  if (privacyDisabled && !botReadded) {
    return "Remove and re-add the bot, then send a new test message";
  }

  if (!messageAllowed) {
    return "Update configuration must include message";
  }

  if (rawUpdateReceived && !ordinaryGroupMessageReceived) {
    return "Inspect application filtering and downstream processing";
  }

  return "Inspect group role and compare raw updates with application records";
}
Enter fullscreen mode Exit fullscreen mode

This does not replace Telegram’s documentation, but it stops incident responders from making unrelated changes simultaneously.

Bot identity versus account-based intake

This guide concerns Telegram Bot API bots.

A bot is the right model when users should interact with a bot identity through commands, replies and bot-specific workflows.

An account-based intake system solves a different problem:

Existing Telegram account
        ↓
Authorized account connection
        ↓
Normalized inbound events
        ↓
Shared multi-channel queue
Enter fullscreen mode Exit fullscreen mode

UnifyPort’s unofficial interface can connect a Telegram account and emit normalized message.received events alongside WhatsApp, LINE, TikTok, Zalo and X.

That architecture is not a way to change BotFather settings or repair a Bot API webhook.

It also does not grant access to arbitrary groups or guarantee recovery of historical messages.

Choose based on the required identity:

Users should talk to a bot
    → Telegram Bot API

Team needs intake from an authorized existing account
    → Evaluate an account-based integration
Enter fullscreen mode Exit fullscreen mode

Production checklist

Before declaring the issue fixed, verify:

  • [ ] getMe returns the expected bot identity.
  • [ ] can_read_all_group_messages matches the intended Privacy Mode.
  • [ ] The bot belongs to the affected group.
  • [ ] Its group role is intentional.
  • [ ] The test uses a human sender.
  • [ ] The command includes the correct bot username.
  • [ ] allowed_updates includes message.
  • [ ] The intended receiver is active.
  • [ ] New tests reach raw update storage.
  • [ ] Application filters accept group and supergroup where required.
  • [ ] Update IDs are stored idempotently.
  • [ ] The bot was re-added after disabling Privacy Mode.
  • [ ] Broader access was approved by the group owner.
  • [ ] Logs exclude the bot token and unnecessary message content.

Takeaway

When a Telegram bot receives private messages but misses ordinary group conversation, do not rebuild the webhook first.

Diagnose the pipeline in order:

Bot identity
    ↓
Privacy Mode
    ↓
Group role
    ↓
allowed_updates
    ↓
Delivery transport
    ↓
Application filters
Enter fullscreen mode Exit fullscreen mode

An addressed command arriving while ordinary group text does not is strong evidence that the receiver works for at least one eligible group interaction.

Decide whether broader visibility is actually required. If it is, disable Privacy Mode deliberately, re-add the bot, and retest with new human-authored messages.

Change permissions, transport and application code separately so each test tells you something useful.

References


This article was adapted from an original UnifyPort technical guide with AI-assisted editing.

Top comments (0)