npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@hectorg321/hbot-whatsapp

v1.3.4

Published

Bot de WhatsApp con sistema de comandos addKeyword, interfaz web y reconexión automática

Readme

HBot - WhatsApp Bot

Bot de WhatsApp desarrollado con Baileys que incluye una interfaz web en tiempo real para escanear códigos QR y gestionar la conexión.

🚀 Características

  • ✅ Conexión a WhatsApp mediante QR Code
  • 🌐 Interfaz web moderna para escanear QR
  • ⚡ Actualizaciones en tiempo real con Socket.IO
  • 🔄 Reconexión automática
  • 📱 Responsive design
  • 🎯 Respuestas automáticas configurables
  • 🔧 Variables de entorno configurables

📋 Requisitos

  • Node.js >= 16.0.0
  • npm >= 7.0.0
  • WhatsApp en dispositivo móvil

🛠️ Instalación

  1. Clonar o descargar el proyecto
git clone <url-del-repositorio>
cd HBot
  1. Instalar dependencias
npm install
  1. Configurar variables de entorno (opcional)
# Crear archivo .env
echo "PORT=3000" > .env

🏃‍♂️ Uso

Iniciar el bot

node bot.js

Acceder a la interfaz web

  1. Abrir navegador en: http://localhost:3000
  2. Esperar a que aparezca el código QR
  3. Abrir WhatsApp → Configuración → Dispositivos vinculados
  4. Tocar "Vincular un dispositivo"
  5. Escanear el código QR mostrado en la página web

Estados de conexión

  • ⏳ Esperando conexión... - Bot iniciándose
  • 📱 Escanea el código QR - QR disponible para escanear
  • ✅ ¡Conectado exitosamente! - Bot conectado y funcionando
  • ❌ Desconectado - Reconectando... - Conexión perdida, reintentando

🔧 Configuración

Variables de entorno

Crear archivo .env en la raíz del proyecto:

# Puerto del servidor web (default: 3000)
PORT=3000

# Otros configuraciones futuras...

Puerto personalizado

# Opción 1: Variable de entorno temporal
PORT=8080 node bot.js

# Opción 2: Modificar .env
echo "PORT=8080" > .env
node bot.js

📁 Estructura del proyecto

HBot/
├── src/
│   ├── index.js           # Clase WhatsAppBot principal
│   └── commandHandler.js  # Sistema de comandos addKeyword
├── public/
│   └── index.html         # Interfaz web
├── bot_sessions/          # Sesiones de autenticación (auto-generado)
├── bot.js                 # Servidor principal y configuración de comandos
├── package.json           # Dependencias
├── .env                   # Variables de entorno
└── README.md              # Esta documentación

🔌 API Endpoints

HTTP Endpoints

  • GET / - Interfaz web principal
  • GET /status - Estado actual del bot (JSON)
  • GET /qr - Imagen PNG del código QR

Socket.IO Events

Eventos del servidor:

  • status - Cambio de estado del bot
  • qr_updated - Nuevo código QR generado

Estados posibles:

  • starting - Bot iniciándose
  • waiting_qr - Esperando escaneo de QR
  • connected - Bot conectado
  • disconnected - Bot desconectado

🤖 Sistema de Comandos

Comandos configurados por defecto

  • "hola", "hello", "hi" → Saludo personalizado con nombre del usuario
  • "ping" → "pong! 🏓"
  • "menu", "menú" → Menú de comandos disponibles
  • "info" → Información del bot con respuestas secuenciales

📋 Usar el sistema addKeyword

El bot incluye un sistema avanzado de comandos que funciona similar a otros frameworks de bots:

// Comando simple
bot.addKeyword('ping').addAction(
    async (ctx, ctxFn) => {
        await ctxFn.reply('pong! 🏓')
    }
)

// Múltiples palabras clave
bot.addKeyword(['hola', 'hello', 'hi']).addAction(
    async (ctx, ctxFn) => {
        await ctxFn.reply(`¡Hola ${ctx.pushName}! 👋`)
    }
)

// Respuestas múltiples secuenciales
bot.addKeyword('info').addAction(
    async (ctx, ctxFn) => {
        await ctxFn.flowDynamic([
            '🤖 *Información del Bot*',
            'Soy un bot de WhatsApp creado con Node.js',
            'Puedo responder a diferentes comandos.',
            'Escribe "menu" para ver los comandos disponibles.'
        ])
    }
)

📝 Objeto ctx (Contexto del mensaje)

El primer parámetro ctx contiene información del mensaje:

{
    from: '[email protected]',    // ID del remitente
    message: 'Hola bot',                  // Texto del mensaje
    body: 'Hola bot',                     // Alias de message
    pushName: 'Juan Pérez',               // Nombre del usuario
    key: { ... },                         // Información de la clave
    originalMessage: { ... }              // Mensaje completo de Baileys
}

🔧 Objeto ctxFn (Funciones de respuesta)

El segundo parámetro ctxFn contiene métodos para enviar respuestas:

ctxFn.reply(texto)

Envía una respuesta simple:

await ctxFn.reply('¡Hola! ¿Cómo estás?')

ctxFn.send(texto)

Alias de reply, envía un mensaje:

await ctxFn.send('Mensaje enviado')

ctxFn.flowDynamic(array)

Envía múltiples mensajes secuenciales con delay automático:

await ctxFn.flowDynamic([
    'Primera línea',
    'Segunda línea',
    'Tercera línea'
])

// También acepta objetos con propiedades
await ctxFn.flowDynamic([
    { body: 'Mensaje 1' },
    { body: 'Mensaje 2' }
])

⚙️ Tipos de coincidencias de palabras clave

// Coincidencia exacta
bot.addKeyword('ping')  // Solo responde a "ping"

// Múltiples palabras clave
bot.addKeyword(['hola', 'hello', 'hi'])  // Cualquiera de las tres

// Coincidencia que empiece con la palabra
bot.addKeyword('help')  // Responde a "help", "help me", etc.

// Para coincidencias que contengan la palabra (usar asteriscos)
bot.addKeyword('*ayuda*')  // Responde si el mensaje contiene "ayuda"

💡 Ejemplos avanzados

// Comando con validaciones
bot.addKeyword('edad').addAction(
    async (ctx, ctxFn) => {
        const edad = ctx.body.split(' ')[1]
        if (!edad || isNaN(edad)) {
            await ctxFn.reply('Por favor, envía tu edad así: "edad 25"')
            return
        }
        await ctxFn.reply(`Tu edad es ${edad} años`)
    }
)

// Comando con respuesta personalizada según el usuario
bot.addKeyword('perfil').addAction(
    async (ctx, ctxFn) => {
        await ctxFn.flowDynamic([
            `👤 *Perfil de ${ctx.pushName}*`,
            `📱 Número: ${ctx.from}`,
            `💬 Último mensaje: "${ctx.body}"`,
            'Gracias por usar el bot!'
        ])
    }
)

// Comando con respuesta condicional
bot.addKeyword('tiempo').addAction(
    async (ctx, ctxFn) => {
        const hora = new Date().getHours()
        let saludo
        
        if (hora < 12) saludo = 'Buenos días'
        else if (hora < 18) saludo = 'Buenas tardes'
        else saludo = 'Buenas noches'
        
        await ctxFn.reply(`${saludo}, ${ctx.pushName}! Son las ${new Date().toLocaleTimeString()}`)
    }
)

🔄 Migración desde el sistema anterior

Si tenías respuestas en el listener de eventos:

// ❌ Sistema anterior
bot.on('message', async (msg) => {
    if (mensaje?.toLowerCase() === 'hola') {
        await bot.enviarMensaje(from, '¡Hola!')
    }
})

// ✅ Nuevo sistema
bot.addKeyword('hola').addAction(
    async (ctx, ctxFn) => {
        await ctxFn.reply('¡Hola!')
    }
)

🏗️ Arquitectura técnica

Tecnologías utilizadas

  • Baileys v6.7.18 - Biblioteca para WhatsApp Web API
  • Express.js v5.1.0 - Servidor web
  • Socket.IO v4.8.1 - Comunicación en tiempo real
  • QRCode v1.5.4 - Generación de códigos QR
  • dotenv v17.2.1 - Variables de entorno

Clase WhatsAppBot

const { WhatsAppBot } = require('./src/index.js')

const bot = new WhatsAppBot()

// Eventos disponibles
bot.on('qr', (qr) => { /* QR generado */ })
bot.on('connected', () => { /* Bot conectado */ })
bot.on('disconnected', (error) => { /* Bot desconectado */ })
bot.on('message', (msg) => { /* Mensaje recibido */ })

// Métodos disponibles
await bot.conectar()
await bot.enviarMensaje(jid, mensaje)
const socket = bot.getSocket()

// Sistema de comandos
bot.addKeyword(['palabra1', 'palabra2']).addAction(async (ctx, ctxFn) => {
    await ctxFn.reply('Respuesta')
})

Clase CommandHandler

const { CommandHandler } = require('./src/commandHandler.js')

// Se instancia automáticamente dentro de WhatsAppBot
// Maneja el procesamiento de mensajes y coincidencias de palabras clave
// Proporciona ctx (contexto) y ctxFn (funciones de respuesta)

Flujo de conexión

  1. Bot se inicia y carga sesión guardada
  2. Si no hay sesión, genera nuevo QR
  3. QR se emite vía Socket.IO a clientes web
  4. Usuario escanea QR desde interfaz web
  5. WhatsApp valida y establece conexión
  6. Bot queda listo para recibir/enviar mensajes

🚨 Resolución de problemas

El bot no se conecta

  1. Verificar QR actualizado: El QR expira cada ~30 segundos
  2. Limpiar sesión: Eliminar carpeta bot_sessions/
  3. Verificar WhatsApp: Asegurar que WhatsApp esté actualizado

Error de puerto ocupado

# Cambiar puerto
PORT=3001 node bot.js

# O verificar procesos usando el puerto
netstat -ano | findstr :3000

Página web no carga

  1. Verificar URL: http://localhost:3000 (no HTTPS)
  2. Firewall: Permitir conexiones en el puerto configurado
  3. Logs del servidor: Revisar mensajes en consola

Socket.IO no conecta

  1. Verificar JavaScript habilitado en navegador
  2. Limpiar caché del navegador
  3. Verificar consola del navegador (F12)

📊 Logs y monitoreo

Mensajes de log importantes

🌐 Servidor web iniciado en http://localhost:3000  # Servidor listo
🔗 Cliente conectado: <socket-id>                   # Cliente web conectado
📱 QR generado para escanear                       # Nuevo QR disponible
🚀 Bot conectado y listo!                          # WhatsApp conectado
📨 Mensaje de <número>: <texto>                    # Mensaje recibido
❌ Bot desconectado: <error>                       # Error de conexión

Monitoreo en producción

Para uso en producción, considerar:

  • PM2 para gestión de procesos
  • Log rotation para archivos de log
  • Health checks para verificar estado
  • Reverse proxy (nginx) para HTTPS
# Instalar PM2
npm install -g pm2

# Iniciar con PM2
pm2 start bot.js --name "hbot"

# Monitorear
pm2 monit

🔒 Seguridad

Datos sensibles

  • Sesiones: Carpeta bot_sessions/ contiene tokens de autenticación
  • Números: Los mensajes incluyen números de teléfono
  • QR Codes: No compartir códigos QR públicamente

Recomendaciones

  1. No commitear bot_sessions/ al repositorio
  2. Usar HTTPS en producción
  3. Validar mensajes antes de procesar
  4. Rate limiting para evitar spam

📝 Desarrollo

Agregar nuevos comandos

// Agregar comandos con el sistema addKeyword
bot.addKeyword('/comando').addAction(
    async (ctx, ctxFn) => {
        await ctxFn.reply('Respuesta del comando')
    }
)

// Comando con múltiples acciones
bot.addKeyword('ayuda')
    .addAction(async (ctx, ctxFn) => {
        await ctxFn.reply('¡Hola! Te ayudo')
    })
    .addAction(async (ctx, ctxFn) => {
        await ctxFn.flowDynamic([
            'Comandos disponibles:',
            '• ping - Prueba de conexión',
            '• menu - Ver menú principal'
        ])
    })

// Comando con lógica compleja
bot.addKeyword('calcular').addAction(
    async (ctx, ctxFn) => {
        const partes = ctx.body.split(' ')
        if (partes.length < 4) {
            await ctxFn.reply('Uso: calcular [número] [operador] [número]')
            return
        }
        
        const [, num1, operador, num2] = partes
        const resultado = eval(`${num1} ${operador} ${num2}`)
        await ctxFn.reply(`Resultado: ${resultado}`)
    }
)

Variables útiles del contexto (ctx)

// Información disponible en ctx dentro de addAction
ctx.from                    // Número/ID del remitente (ej: '[email protected]')
ctx.message || ctx.body     // Texto completo del mensaje
ctx.pushName               // Nombre del usuario en WhatsApp
ctx.key                    // Información de la clave del mensaje
ctx.originalMessage        // Objeto mensaje completo de Baileys

// Tipos de chat (usando ctx.from)
ctx.from.endsWith('@s.whatsapp.net')    // Chat individual
ctx.from.endsWith('@g.us')              // Grupo

// Ejemplo de uso
bot.addKeyword('whoami').addAction(
    async (ctx, ctxFn) => {
        const tipoChat = ctx.from.endsWith('@g.us') ? 'grupo' : 'chat individual'
        await ctxFn.reply(`Eres ${ctx.pushName} en un ${tipoChat}`)
    }
)

📚 Referencias


Versión: 1.0.0 - Con sistema de comandos addKeyword
Autor: HBot Team
Licencia: ISC

🆕 Changelog

v1.0.0

  • ✅ Agregado sistema de comandos addKeyword() y addAction()
  • ✅ Soporte para múltiples palabras clave por comando
  • ✅ Objeto ctx con contexto completo del mensaje
  • ✅ Objeto ctxFn con métodos reply(), send() y flowDynamic()
  • ✅ Coincidencias exactas y por contenido con asteriscos
  • ✅ Respuestas secuenciales con delay automático
  • ✅ Compatibilidad con el sistema anterior de eventos