Tutorial

Crea un bot de Telegram en 10 minutos con grammY (Node.js)

Vas a crear un bot, escribir unas 25 líneas de JavaScript y hablar con él desde tu teléfono.

Tutorial2 min de lecturaActualizado

Tu códigonode bot.jsgetUpdates (long polling)sendMessageBot APIapi.telegram.orgTelegramusuarios1un solo proceso: dos procesos con polling dan 409 Conflict
Figura 1. Con long polling tu proceso le pide a Telegram los updates nuevos; no necesitas URL pública.
  1. Crea el bot con @BotFather

    Abre un chat con @BotFather (revisa la marca azul de verificación), envía /newbot, elige un nombre visible y un username que termine en bot. BotFather te responde con un token.

    @BotFather/newbotMuy bien, un bot nuevo. ¿Cómo lo vamos a llamar?Mi Primer BotAhora elige un username. Debe terminar en bot.mi_primer_demo_bot¡Listo! Usa este token: 123456789:AA...1token = contraseña
    Figura 2. Creación del bot con @BotFather (ilustración). El último mensaje contiene el token: trátalo como una contraseña.
  2. Crea el proyecto

    mkdir mi-bot && cd mi-bot
    npm init -y
    npm pkg set type=module
    npm install grammy

    type=module te permite usar import y await en el nivel superior.

  3. Guarda el token fuera del código

    printf 'BOT_TOKEN=123456789:replace-me\n' > .env
    printf '.env\nnode_modules\n' > .gitignore

    Pega tu token real en .env. Si alguna vez se filtra, usa /revoke en BotFather para obtener uno nuevo.

  4. Escribe el bot

    bot.js

    import { Bot } from "grammy";
    
    const token = process.env.BOT_TOKEN;
    if (!token) throw new Error("BOT_TOKEN is missing (see .env)");
    const bot = new Bot(token);
    
    bot.command("start", (ctx) => ctx.reply(`Hola, ${ctx.from?.first_name ?? "!"} Send /help.`));
    bot.command("help", (ctx) => ctx.reply("/start - greet\n/help - this list\n/ping - check the bot"));
    bot.command("ping", (ctx) => ctx.reply("pong"));
    
    // Echo any other text message
    bot.on("message:text", (ctx) => ctx.reply(`You said: ${ctx.message.text}`));
    
    // Never crash on a handler error; never log the token
    bot.catch((err) => console.error("handler error:", err.error?.message ?? err.message));
    
    await bot.api.setMyCommands([
      { command: "start", description: "Start the bot" },
      { command: "help", description: "Show commands" },
      { command: "ping", description: "Check the bot is alive" },
    ]);
    bot.start({ onStart: (me) => console.log(`@${me.username} running with long polling`) });
    process.once("SIGINT", () => bot.stop());
    process.once("SIGTERM", () => bot.stop());

    Los manejadores se evalúan en orden: primero los comandos y luego el de texto genérico. bot.catch evita que un update con error detenga el bot.

  5. Ejecútalo y pruébalo desde tu teléfono

    node --env-file=.env bot.js
    ~/mi-bot$ node --env-file=.env bot.js@mi_primer_demo_bot running with long polling(envía /start desde tu teléfono)update 1: /start from chat 55512341el bot está en línea
    Figura 3. Salida esperada al iniciar el bot (ilustración).

    Abre tu bot por su username, presiona Iniciar y prueba /ping. Detenlo con Ctrl+C.

  6. Mantenlo encendido

    Tu laptop no va a estar prendida siempre. Despliega el mismo código en un hosting que corra 24/7: sigue el tutorial de Railway (sin servidor que administrar) o el tutorial de VPS en Vultr (control total). Compara opciones en el comparador de hosting.

Solución de problemas

  • 401 Unauthorized: el token es incorrecto o fue revocado. Cópialo de nuevo desde BotFather.
  • 409 Conflict: otro proceso está haciendo polling con el mismo token, o hay un webhook configurado. Detén la otra copia; si había webhook, llama a deleteWebhook antes de start().
  • El bot no responde en grupos: por defecto el modo de privacidad solo entrega comandos y respuestas al bot. Cámbialo con /setprivacy en BotFather solo si de verdad necesitas todos los mensajes.

Documentación oficial: primeros pasos de grammY, Telegram Bot API.