Lewati ke konten
Kembali ke Blog

Cara Membuat Telegram Bot dengan Node.js

· · 7 menit baca

Telegram Bot memungkinkan automation dan interaksi dengan user. Mari pelajari cara membuatnya dengan Node.js.

Membuat Bot di Telegram

Daftar Bot dengan BotFather

1. Buka Telegram
2. Cari @BotFather
3. Kirim /newbot
4. Masukkan nama bot (display name)
5. Masukkan username (harus berakhir 'bot')
6. Simpan token yang diberikan

Bot Commands Setup

Kirim ke BotFather:
/setcommands

Pilih bot, lalu kirim:
start - Memulai bot
help - Bantuan
menu - Tampilkan menu

Setup Project Node.js

Initialize Project

mkdir telegram-bot
cd telegram-bot
npm init -y

# Install dependencies
npm install node-telegram-bot-api dotenv

Environment Setup

# .env
TELEGRAM_BOT_TOKEN=your_bot_token_here

Basic Bot

// index.js
require("dotenv").config();
const TelegramBot = require("node-telegram-bot-api");

const token = process.env.TELEGRAM_BOT_TOKEN;
const bot = new TelegramBot(token, { polling: true });

// Handle /start command
bot.onText(/\/start/, (msg) => {
  const chatId = msg.chat.id;
  const name = msg.from.first_name;

  bot.sendMessage(chatId, `Halo ${name}! 👋\nSelamat datang di bot saya.`);
});

// Handle /help command
bot.onText(/\/help/, (msg) => {
  const chatId = msg.chat.id;
  const helpText = `
📚 *Daftar Perintah:*

/start - Memulai bot
/help - Tampilkan bantuan
/menu - Tampilkan menu
/info - Info bot

_Kirim pesan apa saja untuk berinteraksi._
    `;
  bot.sendMessage(chatId, helpText, { parse_mode: "Markdown" });
});

console.log("Bot is running...");

Handling Messages

Text Messages

// Handle any text message
bot.on("message", (msg) => {
  const chatId = msg.chat.id;
  const text = msg.text;

  // Skip commands
  if (text && text.startsWith("/")) return;

  bot.sendMessage(chatId, `Kamu mengirim: ${text}`);
});

// Handle specific text
bot.onText(/halo|hai|hi/i, (msg) => {
  const chatId = msg.chat.id;
  bot.sendMessage(chatId, "Halo juga! 😊");
});

// Handle with regex groups
bot.onText(/\/echo (.+)/, (msg, match) => {
  const chatId = msg.chat.id;
  const response = match[1]; // Captured text
  bot.sendMessage(chatId, response);
});

Send Different Content Types

// Send photo
bot.sendPhoto(chatId, "https://example.com/photo.jpg", {
  caption: "Ini adalah foto",
});

// Send from file
bot.sendPhoto(chatId, "./images/photo.jpg");

// Send document
bot.sendDocument(chatId, "./files/document.pdf");

// Send location
bot.sendLocation(chatId, -6.2088, 106.8456); // Jakarta

// Send contact
bot.sendContact(chatId, "+62812345678", "John Doe");

// Send sticker
bot.sendSticker(chatId, "sticker_file_id");

Inline Keyboards

Basic Keyboard

bot.onText(/\/menu/, (msg) => {
  const chatId = msg.chat.id;

  const keyboard = {
    reply_markup: {
      inline_keyboard: [
        [
          { text: "📊 Status", callback_data: "status" },
          { text: "⚙️ Settings", callback_data: "settings" },
        ],
        [
          { text: "❓ Help", callback_data: "help" },
          { text: "📞 Contact", callback_data: "contact" },
        ],
        [{ text: "🌐 Visit Website", url: "https://example.com" }],
      ],
    },
  };

  bot.sendMessage(chatId, "Pilih menu:", keyboard);
});

// Handle callback query
bot.on("callback_query", async (query) => {
  const chatId = query.message.chat.id;
  const data = query.data;

  // Answer callback to remove loading
  await bot.answerCallbackQuery(query.id);

  switch (data) {
    case "status":
      bot.sendMessage(chatId, "✅ Bot berjalan normal");
      break;
    case "settings":
      bot.sendMessage(chatId, "⚙️ Menu settings");
      break;
    case "help":
      bot.sendMessage(chatId, "❓ Bantuan...");
      break;
    case "contact":
      bot.sendMessage(chatId, "📞 Hubungi: @username");
      break;
  }
});

Reply Keyboard

bot.onText(/\/keyboard/, (msg) => {
  const chatId = msg.chat.id;

  const keyboard = {
    reply_markup: {
      keyboard: [
        ["📊 Status", "⚙️ Settings"],
        ["❓ Help", "📞 Contact"],
        ["❌ Close"],
      ],
      resize_keyboard: true,
      one_time_keyboard: false,
    },
  };

  bot.sendMessage(chatId, "Keyboard tersedia:", keyboard);
});

// Remove keyboard
bot.onText(/❌ Close/, (msg) => {
  const chatId = msg.chat.id;
  bot.sendMessage(chatId, "Keyboard dihapus", {
    reply_markup: { remove_keyboard: true },
  });
});

Conversation Flow

Simple State Management

// Store user states
const userStates = {};

bot.onText(/\/feedback/, (msg) => {
  const chatId = msg.chat.id;
  userStates[chatId] = { step: "waiting_feedback" };
  bot.sendMessage(chatId, "Silakan kirim feedback Anda:");
});

bot.on("message", (msg) => {
  const chatId = msg.chat.id;
  const text = msg.text;

  if (text.startsWith("/")) return;

  const state = userStates[chatId];

  if (state && state.step === "waiting_feedback") {
    // Save feedback
    console.log(`Feedback from ${chatId}: ${text}`);

    bot.sendMessage(chatId, "Terima kasih atas feedback Anda! 🙏");
    delete userStates[chatId];
  }
});

Multi-Step Form

const forms = {};

bot.onText(/\/register/, (msg) => {
  const chatId = msg.chat.id;
  forms[chatId] = { step: 1, data: {} };
  bot.sendMessage(chatId, "Langkah 1/3: Masukkan nama Anda:");
});

bot.on("message", (msg) => {
  const chatId = msg.chat.id;
  const text = msg.text;

  if (text.startsWith("/")) return;
  if (!forms[chatId]) return;

  const form = forms[chatId];

  switch (form.step) {
    case 1:
      form.data.name = text;
      form.step = 2;
      bot.sendMessage(chatId, "Langkah 2/3: Masukkan email:");
      break;

    case 2:
      if (!text.includes("@")) {
        bot.sendMessage(chatId, "Email tidak valid. Coba lagi:");
        return;
      }
      form.data.email = text;
      form.step = 3;
      bot.sendMessage(chatId, "Langkah 3/3: Masukkan nomor HP:");
      break;

    case 3:
      form.data.phone = text;

      // Complete registration
      const summary = `
✅ *Registrasi Selesai!*

Nama: ${form.data.name}
Email: ${form.data.email}
Phone: ${form.data.phone}
            `;
      bot.sendMessage(chatId, summary, { parse_mode: "Markdown" });
      delete forms[chatId];
      break;
  }
});

Webhook Mode (Production)

Setup with Express

const express = require("express");
const TelegramBot = require("node-telegram-bot-api");

const token = process.env.TELEGRAM_BOT_TOKEN;
const url = process.env.WEBHOOK_URL; // Your server URL

const app = express();
app.use(express.json());

// Create bot without polling
const bot = new TelegramBot(token);
bot.setWebHook(`${url}/bot${token}`);

// Webhook endpoint
app.post(`/bot${token}`, (req, res) => {
  bot.processUpdate(req.body);
  res.sendStatus(200);
});

// Your bot logic here
bot.onText(/\/start/, (msg) => {
  bot.sendMessage(msg.chat.id, "Hello!");
});

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`);
});

Advanced Features

Broadcast Message

// Store subscribers
const subscribers = new Set();

bot.onText(/\/subscribe/, (msg) => {
  const chatId = msg.chat.id;
  subscribers.add(chatId);
  bot.sendMessage(chatId, "✅ Berhasil subscribe!");
});

bot.onText(/\/unsubscribe/, (msg) => {
  const chatId = msg.chat.id;
  subscribers.delete(chatId);
  bot.sendMessage(chatId, "❌ Berhasil unsubscribe");
});

// Admin broadcast
bot.onText(/\/broadcast (.+)/, async (msg, match) => {
  const adminId = 123456789; // Your Telegram ID
  if (msg.from.id !== adminId) return;

  const message = match[1];
  let sent = 0;

  for (const chatId of subscribers) {
    try {
      await bot.sendMessage(chatId, message);
      sent++;
    } catch (error) {
      subscribers.delete(chatId); // Remove invalid
    }
  }

  bot.sendMessage(msg.chat.id, `Broadcast terkirim ke ${sent} users`);
});

Rate Limiting

const rateLimits = {};
const RATE_LIMIT = 5; // messages per minute

function checkRateLimit(chatId) {
  const now = Date.now();

  if (!rateLimits[chatId]) {
    rateLimits[chatId] = { count: 1, resetAt: now + 60000 };
    return true;
  }

  if (now > rateLimits[chatId].resetAt) {
    rateLimits[chatId] = { count: 1, resetAt: now + 60000 };
    return true;
  }

  if (rateLimits[chatId].count >= RATE_LIMIT) {
    return false;
  }

  rateLimits[chatId].count++;
  return true;
}

bot.on("message", (msg) => {
  if (!checkRateLimit(msg.chat.id)) {
    bot.sendMessage(msg.chat.id, "Terlalu banyak request. Tunggu sebentar.");
    return;
  }

  // Process message
});

Database Integration

With MongoDB

const mongoose = require("mongoose");

mongoose.connect("mongodb://localhost:27017/telegram_bot");

const userSchema = new mongoose.Schema({
  chatId: { type: Number, unique: true },
  username: String,
  firstName: String,
  createdAt: { type: Date, default: Date.now },
  settings: {
    notifications: { type: Boolean, default: true },
  },
});

const User = mongoose.model("User", userSchema);

// Save user on /start
bot.onText(/\/start/, async (msg) => {
  const chatId = msg.chat.id;

  await User.findOneAndUpdate(
    { chatId },
    {
      chatId,
      username: msg.from.username,
      firstName: msg.from.first_name,
    },
    { upsert: true }
  );

  bot.sendMessage(chatId, "Selamat datang!");
});

Error Handling

Robust Error Handling

bot.on("polling_error", (error) => {
  console.error("Polling error:", error);
});

bot.on("webhook_error", (error) => {
  console.error("Webhook error:", error);
});

// Wrap handlers
function safeHandler(handler) {
  return async (msg, match) => {
    try {
      await handler(msg, match);
    } catch (error) {
      console.error("Handler error:", error);
      bot.sendMessage(msg.chat.id, "Terjadi kesalahan. Coba lagi nanti.");
    }
  };
}

bot.onText(
  /\/risky/,
  safeHandler(async (msg) => {
    // Your code that might throw
  })
);

Kesimpulan

Telegram Bot dengan Node.js sangat versatile untuk berbagai automation. Mulai dengan bot sederhana lalu tambahkan fitur sesuai kebutuhan.

Ditulis oleh

Hendra Wijaya

Tinggalkan Komentar

Email tidak akan ditampilkan.