BuilderBot Framework
website·Indexed 30 days ago
https://builderbot.vercel.appA framework for creating chatbots focused on low-frequency communication channels such as WhatsApp and Telegram. It features a modular system with support for multiple providers including Meta, Twilio, and Baileys, as well as database integrations like Supabase and Postgres. The framework includes plugins for OpenAI, LangChain, and Shopify, and provides tools for managing conversation flows, context, and deployment to platforms like Railway.
What's inside BuilderBot
- Baileys is a free WhatsApp provider that operates via WhatsApp Web using WebSockets. It does not require Selenium or Chromium, making it more RAM-efficient. Note: Buttons and lists are not fully compatible and may not function as intended on all devices.
Overview of the BuilderBot Framework
BuilderBot is a framework designed for creating chatbots for low-frequency communication channels such as WhatsApp and Telegram. Its architecture is built around three key components to ensure developer experience and logic reuse: Flows for conversation context, Providers for channel connectivity, and Databases for state persistence.Overview of BuilderBot Providers
Providers act as the communication bridge between the bot logic and the messaging platform (WhatsApp, Telegram, or custom providers). BuilderBot allows you to switch providers by implementing the corresponding connector without affecting the core bot logic. Each provider is initialized using thecreateProviderfunction, which accepts the provider class and an optional configuration object for access keys and settings.Overview of BuilderBot Database Adapters
BuilderBot uses database adapters to maintain a record of events that occur between different conversations. While often used for chat history, the database stores all bot events, not just messages. Database providers can be easily exchanged by swapping the implemented class and updating the corresponding configuration keys.Deployment requirements for BuilderBot
BuilderBot requires a persistent execution environment to function correctly. Because the application code must be kept alive continuously, the use of serverless services is not recommended.Manage message templates with Twilio Content Template Builder
The Content Template Builder is a Twilio tool with a graphical interface used to create, approve, and manage content-rich message templates. This allows both developers and non-technical users to submit templates for approval via the Twilio Console without writing code, which is a requirement for using advanced features like buttons and lists in WhatsApp integrations.Configure Bot Providers and Databases
BuilderBot uses a provider-based architecture to allow switching between communication channels (e.g., Meta, Twilio, Baileys for WhatsApp, or Telegram) and database adapters (e.g., Mongo, MySQL, Postgres, or MemoryDB) without rewriting the core workflow logic. ThecreateBotfunction initializes the bot with these configurations.import { createBot, MemoryDB, createProvider, createFlow } from '@builderbot/bot' import { BaileysProvider } from '@builderbot/provider-baileys' const main = async () => { await createBot({ database: new MemoryDB(), provider: createProvider(BaileysProvider), flow: createFlow([flowDemo]) }) } main()Use the context object to access user interaction data
The
context(ctx) object is a core component of the framework that provides real-time information about the interaction between a user and the bot. It is passed as the first argument to callback functions when using methods likeaddAnswerandaddAction.Standard properties available across all providers include:
from: The unique identifier of the sender.body: The actual message or input text sent by the user.name: The name of the sender.
Note: Additional properties may be available depending on the specific provider being used.
import { addKeyword } from '@builderbot/bot'; const flowA = addKeyword('register') .addAnswer('What is your name?', { capture: true }, async (ctx, { state }) => { // Accessing standard context properties const responseName = ctx.body const nameFrom = ctx.name const numberFrom = ctx.from console.log(`Other properties:`, ctx) }) export default flowAImplement scheduled reminders using node-cron in BuilderBot
To send individual reminders to users at specific intervals (e.g., every 12 hours), use thenode-cronlibrary. This allows you to fetch a list of users from an API or database and send them messages via the bot's provider. To avoid being flagged for robotic behavior or banned, it is recommended to use a varied list of messages and implement a delay between messages usingutils.delay().pnpm i node-cron pnpm i @types/node-cron -DImplement a debounced message queue for fast user entries
To prevent a chatbot from responding to every single short message sent by an impatient user, you can implement a message queue with a debounce timer. This system accumulates all messages sent by a specific user within a defined time window (e.g., 3000ms) and processes them as a single combined conversation string once the timer expires.
Key features of this implementation include:
- User-specific Queues: Separate conversation handling for each user based on their identifier (
from). - Configurable Gap: The time window for accumulating messages is adjustable via
QueueConfig. - Callback Processing: Once the gap expires, the accumulated text is passed to a callback function for bot processing.
/** * @file multiUserMessageQueue.ts * @description An improved functional implementation of a multi-user message queueing system with debounce functionality, * ensuring separate conversation handling for each user. */ import { BotContext } from "@builderbot/bot/dist/types"; interface Message { text: string; timestamp: number; } interface QueueConfig { gapMilliseconds: number; } interface UserQueue { messages: Message[]; timer: NodeJS.Timeout | null; callback: ((body: string, from: string) => void) | null; } interface QueueState { queues: Map<string, UserQueue>; } function createInitialState(): QueueState { return { queues: new Map() }; } function resetTimer(userQueue: UserQueue): UserQueue { if (userQueue.timer) { clearTimeout(userQueue.timer); } return { ...userQueue, timer: null }; } function processQueue(messages: Message[]): string { const result = messages.map(message => message.text).join(" "); console.log('Accumulated messages:', result); return result; } function createMessageQueue(config: QueueConfig) { let state: QueueState = createInitialState(); return function enqueueMessage(ctx: BotContext, callback: (body: string, from: string) => void): void { const from = ctx.from; const messageBody = ctx.body; if (!from || !messageBody) { console.error('Invalid message context:', ctx); return; } console.log('Enqueueing:', messageBody, 'from:', from); let userQueue = state.queues.get(from); if (!userQueue) { userQueue = { messages: [], timer: null, callback: null }; state.queues.set(from, userQueue); } userQueue = resetTimer(userQueue); userQueue.messages.push({ text: messageBody, timestamp: Date.now() }); userQueue.callback = callback; console.log('Messages for', from, ':', userQueue.messages); if (!userQueue.timer) { userQueue.timer = setTimeout(() => { const currentQueue = state.queues.get(from); if (currentQueue) { const result = processQueue(currentQueue.messages); if (currentQueue.callback) { currentQueue.callback(result, from); } state.queues.set(from, { ...currentQueue, messages: [], timer: null }); } }, config.gapMilliseconds); } state.queues.set(from, userQueue); }; } export { createMessageQueue, QueueConfig };- User-specific Queues: Separate conversation handling for each user based on their identifier (
Send dynamic messages with flowDynamic
UseflowDynamicto send messages based on API calls, database results, or other dynamic processes. It can accept a simple string or an array of objects for advanced control over delays and media.import { addKeyword } from '@builderbot/bot'; const flow = addKeyword('register') .addAction(async (_, { flowDynamic }) => { // Simple string message await flowDynamic(`Thanks for registering`); // Advanced options using an array of objects await flowDynamic([ { body: `Message with 2 seconds delay`, delay: 2000 }, { body: `Look at this image`, media: `https://i.imgur.com/0HpzsEm.png` }, { body: `Look at this file`, media: join('assets', 'file.pdf') } ]); });Disable the bot for a specific user
You can turn off the bot for a specific user by storing a flag in the user'sstateand callingendFlow()when that flag is active.const flow = addKeyword<BaileysProvider>('magic keyword') .addAction(async (_, { state, endFlow }) => { const botOffForThisUser = state.get<boolean>('botOffForThisUser') await state.update({botOffForThisUser:!botOffForThisUser}) if(botOffForThisUser) return endFlow() }) .addAnswer('Hello!')