How to Add Telegram Bot Notifications to Your Web Application


January 15, 2026

7 min read

telegrambotnotificationsweb-developmentapiserver-sidetypescriptjavascript

Telegram Bot Notifications Guide

Introduction: Why Telegram Notifications?

Telegram bots are one of the easiest ways to add real-time notifications to your web application. Unlike email (which can end up in spam) or SMS (which costs money), Telegram notifications are instant, free, and reliable. They're perfect for:

  • Admin alerts when important actions happen
  • System status updates
  • User activity notifications
  • Error alerts and monitoring

The best part? You can set it up in about 10 minutes, and it works from any server-side code - Node.js, Python, PHP, you name it.

Step 1: Create Your Bot

First, you need to create a bot and get your authentication token.

  1. Open Telegram and search for @BotFather (the official bot for creating bots)
  2. Send the command /newbot
  3. Follow the prompts to name your bot (e.g., "My App Notifications")
  4. Choose a unique username ending in bot (e.g., myapp_notifications_bot)
  5. @BotFather will give you an HTTP API token - save this immediately!

The token looks like: 123456789:ABCdefGHIjklMNOpqrsTUVwxyz

⚠️ Important: Keep this token secret. Anyone with it can control your bot.

Step 2: Configure Bot Privacy

If you want your bot to work in groups (which is common for notifications), you need to disable privacy mode:

  1. Go to @BotFather/mybots
  2. Select your bot
  3. Choose Bot SettingsAllow Groups?Allow

Now add your bot to the group where you want to receive notifications. For full functionality, you can make it an administrator, but for basic notifications, a regular member is fine.

Step 3: Get Your Chat ID

Your web application needs to know which chat (group or user) to send messages to. The chat ID is a unique identifier.

Method 1: Using Telegram Web (Easiest)

  1. Visit web.telegram.org in your browser
  2. Open the group where you added your bot
  3. Look at the URL in your browser's address bar
  4. The chat ID is in the URL - it will be a negative number like -1001234567890

Getting Chat ID from Telegram Web

The chat ID is visible in the URL when viewing a group on Telegram Web

Method 2: Using the Bot API

  1. Make sure your bot is in the group
  2. Send a message in the group (mentioning the bot is optional)
  3. In your browser or using curl, visit:
    https://api.telegram.org/bot<YOUR_BOT_TOKEN>/getUpdates
    
  4. Look for the "chat" object in the JSON response
  5. Copy the "id" value (it will be negative for groups)

Note: For groups, the chat ID always starts with a minus sign. For direct messages to users, it's a positive number.

Step 4: Basic Implementation

Now let's write the code. Here's a minimal, clean implementation:

// lib/telegram.ts
"use server";

interface TelegramNotification {
  message: string;
  chatId?: string; // Optional, defaults to env var
}

export async function sendTelegramNotification({
  message,
  chatId,
}: TelegramNotification) {
  const botToken = process.env.TELEGRAM_BOT_TOKEN;
  const defaultChatId = process.env.TELEGRAM_CHAT_ID;

  // Use provided chatId or fall back to env var
  const targetChatId = chatId || defaultChatId;

  if (!botToken || !targetChatId) {
    console.warn("Telegram not configured");
    return { success: false, reason: "not_configured" };
  }

  const telegramUrl = `https://api.telegram.org/bot${botToken}/sendMessage`;

  try {
    const response = await fetch(telegramUrl, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        chat_id: targetChatId,
        text: message,
      }),
    });

    const data = await response.json();

    if (!data.ok) {
      console.error("Telegram API error:", data);
      return { success: false, error: data.description };
    }

    return { success: true, messageId: data.result.message_id };
  } catch (error) {
    console.error("Error sending Telegram message:", error);
    return {
      success: false,
      error: error instanceof Error ? error.message : "Unknown error",
    };
  }
}

That's it! This is a minimal, production-ready implementation. Let's break it down:

  • Server-only: The "use server" directive ensures this only runs on the server
  • Environment variables: Uses TELEGRAM_BOT_TOKEN and TELEGRAM_CHAT_ID from your .env file
  • Error handling: Gracefully handles missing config or API errors
  • Simple API: Just pass a message string

Step 5: Set Up Environment Variables

Add these to your .env.local file:

TELEGRAM_BOT_TOKEN=123456789:ABCdefGHIjklMNOpqrsTUVwxyz
TELEGRAM_CHAT_ID=-1001234567890

Important: Make sure the chat ID includes the minus sign for groups!

Step 6: Use It in Your Application

Now you can call it from anywhere in your server-side code:

// Example: Send notification when user signs up
import { sendTelegramNotification } from "@/lib/telegram";

export async function createUser(userData: UserData) {
  // ... create user logic ...

  // Send notification (non-blocking)
  sendTelegramNotification({
    message: `New user signed up: ${userData.email}`,
  }).catch((error) => {
    // Don't break user creation if notification fails
    console.error("Failed to send notification:", error);
  });

  return { success: true };
}

Advanced: Formatted Messages

Telegram supports Markdown formatting. Here's an enhanced version:

export async function sendFormattedNotification({
  title,
  message,
  metadata,
}: {
  title: string;
  message: string;
  metadata?: Record<string, string>;
}) {
  const botToken = process.env.TELEGRAM_BOT_TOKEN;
  const chatId = process.env.TELEGRAM_CHAT_ID;

  if (!botToken || !chatId) {
    return { success: false, reason: "not_configured" };
  }

  // Build formatted message
  let formattedMessage = `*${title}*\n\n${message}`;

  if (metadata) {
    formattedMessage += "\n\n";
    Object.entries(metadata).forEach(([key, value]) => {
      formattedMessage += `${key}: ${value}\n`;
    });
  }

  const telegramUrl = `https://api.telegram.org/bot${botToken}/sendMessage`;

  const response = await fetch(telegramUrl, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      chat_id: chatId,
      text: formattedMessage,
      parse_mode: "MarkdownV2", // Enable Markdown formatting
    }),
  });

  const data = await response.json();
  return data.ok
    ? { success: true }
    : { success: false, error: data.description };
}

Note: When using MarkdownV2, you need to escape special characters. For simplicity, you can use parse_mode: "HTML" instead, which is more forgiving.

Common Issues and Solutions

"Bad Request: chat not found"

This usually means:

  • The bot isn't in the group
  • The chat ID is wrong (missing the minus sign for groups)
  • The chat ID is for a different chat

Solution: Double-check your chat ID and make sure the bot is in the group.

"Unauthorized"

This means your bot token is invalid or expired.

Solution: Get a new token from @BotFather using /token.

Messages Not Appearing

If your code runs but you don't see messages:

  1. Check the API response - look for error messages
  2. Verify the bot is still in the group (it might have been removed)
  3. Check if the group has restrictions on bot messages
  4. Make sure you're checking the right chat/group

Rate Limiting

Telegram allows about 30 messages per second per bot. If you're sending many notifications:

// Add a small delay between messages
for (const notification of notifications) {
  await sendTelegramNotification(notification);
  await new Promise((resolve) => setTimeout(resolve, 50)); // 50ms delay
}

Quick Checklist

Before you finish, make sure:

  1. ✅ Bot created and token saved
  2. ✅ Bot added to your notification group
  3. ✅ Chat ID obtained (with minus sign for groups)
  4. ✅ Environment variables set in .env.local
  5. ✅ Test notification sent successfully
  6. ✅ Error handling in place
  7. ✅ Bot token not committed to git

Real-World Example: Audit Logging

Here's how you might use it for audit logging:

// lib/audit.ts
import { sendTelegramNotification } from "@/lib/telegram";

export async function logActivity(
  action: string,
  actor: string,
  details?: string
) {
  // Log to database
  await saveToDatabase({ action, actor, details });

  // Send Telegram notification
  const message = `🔔 *${action}*\n\n👤 Actor: ${actor}${
    details ? `\n📝 ${details}` : ""
  }`;

  sendTelegramNotification({ message }).catch((error) => {
    // Don't break logging if Telegram fails
    console.error("Notification failed:", error);
  });
}

Now every important action in your app can trigger a Telegram notification automatically.

Share: