Building Your First BotMate Plugin: A Step-by-Step Guide

Learn how to create and customize your first plugin for BotMate with this easy-to-follow tutorial.

The project is under heavy development, if you want to contribute, or you have any queries, please join our Telegram group and checkout Github repository.

If you're not familiar with BotMate, it’s a powerful open-source web-based platform designed to help you manage multiple bots across different platforms—all from a single, unified dashboard. BotMate features an intuitive plugin system that enhances your bots with extended functionality. By simply installing a plugin, you can unlock new capabilities for your bots in just a few clicks.

Each plugin comes with its own set of customizable configurations, which you can easily manage through the platform’s user-friendly interface. The best part? Once you’ve adjusted your settings, your bots are automatically updated—no need to restart or modify any code. With BotMate, bot management becomes effortless, giving you more time to focus on what really matters.


🌐 Website: botmate.dev 📦 Repository: GitHub - botmate 📚 Docs: Documentation 🔍 Sample Repository: botmate-openai-example


Overview

Before diving into the details, let me give you a quick rundown of what we’re going to build and the technologies we’ll be using.

We’ll be creating a plugin for BotMate that allows users to input their OpenAI API keys directly from the dashboard. This plugin will enable a Telegram bot to respond to every message it receives. Additionally, we’ll add a configuration option to specify whether the bot should respond in Telegram groups or only in personal messages.

With this plugin, users will have full control over their bot’s behavior through simple settings—no code modifications needed.

Get started

Before we dive into the development process, let’s ensure you have the necessary prerequisites in place.

Prerequisites

  1. Node.js – Version 20 or higher

  2. Operating System – Linux, macOS, or Android (Windows is currently untested)

  3. pnpm – For managing the workspace and faster installations

  4. TailwindCSS – Used for styling, as BotMate relies on it

To begin, we’ll create a new BotMate project. Run the following command in your terminal:

pnpm create botmate

This will go through a series of questions in the terminal. Please answer the questions, and then a project directory will be created.

pnpm create botmate

After that, we will change our current working directory to the newly created one (i.e. project's directory) and run the following command to start the development server:

pnpm dev

Setup Page

Visit localhost:8233 to open up the BotMate dashboard. After that, click on the Telegram icon, and you will be prompted to enter a bot token. Please click here to learn how to obtain a bot token in Telegram.

setup page

After adding the bot, you will notice on the Settings page that there are no plugins available yet. We will create our plugin by running a command in the terminal.

settings page

Creating a Plugin

To create a plugin, head back to the terminal and run the following command:

pnpm botmate pm create

"pm" refers to plugin manager

This will again ask few questions related to plugin, please select "Telegram" as the platform.

botmate pm create

After you finish creating the plugin, you should see a new folder inside the packages directory. Take a moment to explore the newly created folder and familiarize yourself with the files. Click here to learn about the plugin structure.

Now, your plugin should be visible on the Settings page of your bot. If it's not already running, be sure to run the following command to start the development server:

settings page

Click on "Install" to install the plugin to your currently active bot. You can also install this plugin in multiple Telegram bots, and even publish it to npm for others to use (we'll cover this later in the post).

After installing, you should see a "Configure" button. When you click on it, the settings modal for the plugin will open.


Now, let's open the botmate folder in Visual Studio Code. Before we dive into writing the plugin, let's take a moment to understand the folder structure.

You’ll notice there are two main folders: client and server. As their names suggest:

  • The client folder contains code for the dashboard UI, which is built using React.

  • The server folder contains code for the bot, server, and database interactions, which are powered by TypeScript and Node.js.

We'll start by adding an input field in the Settings UI to accept an API key and save it in the database. To do this, we'll use an inbuilt function that stores values as key-value pairs in the database. Let's first setup our configurations types by editing src/config.types.ts file.

export type Config = {
  key: string;
};

Then in, src/client/settings.tsx file, we will write design a basic UI for taking input from the user.

import React, { useRef } from 'react';

import { toast, usePluginConfig } from '@botmate/client';
import { Button, Input, Label } from '@botmate/ui';

import { Config } from '../config.types';

function SettingsPage() {
  const config = usePluginConfig<Config>();

  const apiKeyRef = useRef<HTMLInputElement>(null);
  const defaultValue = config.get('key', '');

  return (
    <div className="space-y-4">
      <div>
        <Label htmlFor="key">OpenAI API Key</Label>
        <Input
          id="key"
          placeholder="Enter your OpenAI API key (eg. sk-....P20J)"
          ref={apiKeyRef}
          defaultValue={defaultValue}
          className="mt-1"
        />
        <p className="text-sm text-muted-foreground mt-1">
          You can find your API key in the OpenAI dashboard.
        </p>
      </div>
      <Button
        onClick={() => {
          const apiKey = apiKeyRef.current?.value;
          if (!apiKey) {
            toast.error('API key is required');
            return;
          }
          config.save('key', apiKey).then(() => {
            toast.success('API key saved');
          });
        }}
      >
        Save
      </Button>
    </div>
  );
}

export default SettingsPage;

The code above uses the usePluginConfig hook from @botmate/client to save the configuration of the current plugin for the active bot. It handles everything internally, so all you need to do is call the save and get functions.

Note: BotMate comes with hot reload, so you don't need to manually restart the server.

After saving the file, head back to the dashboard, and you should see the following UI when you click on "Configure."

settings input ui

Try entering the API key and click "Save." You should see a success toast notification, indicating that the value has been saved in the database.

To verify, reload the page and click on "Configure" again. You should see the input box already filled with the saved value.

Run the following code to install openai package.

cd packages/openai-plugin
pnpm i openai

Now, let's write the server. Open server/server.ts file and write the following code.

import { PlatformType, Plugin } from '@botmate/server';
import type { Bot } from 'grammy';
import OpenAI from 'openai';

import { Config } from '../config.types';

export class OpenAIChatbot extends Plugin {
  displayName = 'OpenAI Chatbot';
  platformType = PlatformType.Telegram;

  client?: OpenAI;

  async load() {
    const cm = this.configManager<Config>();
    const bot = this.bot.instance<Bot>();

    bot.on('message', async (ctx) => {
      if (!this.client) {
        const apiKey = await cm.get('key');
        if (!apiKey) {
          this.logger.warn(`No API key was found for OpenAI`);
          return;
        }

        this.client = new OpenAI({
          apiKey,
        });
      }

      try {
        ctx.replyWithChatAction('typing');

        const chatCompletion = await this.client.chat.completions.create({
          messages: [{ role: 'user', content: ctx.message.text! }],
          model: 'gpt-3.5-turbo',
        });

        if (chatCompletion.choices) {
          const text = chatCompletion.choices[0].message.content;
          if (text) {
            ctx.reply(text);
          }
        }
      } catch (error) {
        this.logger.error('Error:', error);
        ctx.reply('An error occurred while processing your request');
      }
    });
  }
}

The library used for Telegram bots is grammy. The code is fairly self-explanatory. We are creating a config manager with const cm = this.configManager<Config>(), and then loading the key value from the saved configuration to pass to OpenAI. Upon receiving a message, we complete the message based on the input.

Enabling the Plugin

The next step is to enable the plugin from the Settings page. Plugins installed to a bot are disabled by default, so you must enable them if you want to use the plugin in your bot. The configuration data will be preserved as long as you don’t uninstall the plugin.

enable plugin

Now, that's it. You should see your Telegram bot reply to your message.

Next steps

Try to add a checkbox to configure whether the bot should reply in the group or only in the private.

Here is a snippet for a checkbox.

<div className="flex items-center space-x-2">
  <Checkbox />
  <label className="text-sm leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70">
    Allow in group chat
  </label>
</div>

🙂 Here is the a demo -

gpt-3.5-turbo

Did you find this article valuable?

Support Monawwar Abdullah by becoming a sponsor. Any amount is appreciated!