🚀 ¡Nuevo! builderbot cloud para No-code ¡Pruébalo gratis!

Examples

Below you will find different examples showing the implementation in different use cases. These examples have been compiled based on the community, feel free to post an example that you like or that you think would be useful for new people.


How to Update to the Latest Version

To ensure you're using the most up-to-date features and bug fixes, it's important to keep your BuilderBot installation current. Follow the steps below to update to the latest version. To keep your project up to date, make sure to run the command to update the core and the corresponding provider

pnpm install @builderbot/bot@latest 
pnpm install @builderbot/provider-baileys@latest
pnpm install @builderbot/provider-wppconnect@latest
pnpm install @builderbot/provider-venom@latest
pnpm install @builderbot/provider-meta@latest
pnpm install @builderbot/provider-twilio@latest

My first bot

The following code represents the quick use of a bot that when you type the word hi, greets you with a welcome message and asks you for your name and then returns a funny image

app.ts

import { createBot, createProvider, createFlow, addKeyword, MemoryDB } from '@builderbot/bot'
import { BaileysProvider } from '@builderbot/provider-baileys'

const welcomeFlow = addKeyword<BaileysProvider, MemoryDB>(['hi'])
    .addAnswer('Ey! welcome')
    .addAnswer('Your name is?', { capture: true }, async (ctx, { flowDynamic }) => {
        await flowDynamic([`nice! ${ctx.body}`,'I will send you a funny image'])
    })
    .addAction(async(_ , {flowDynamic}) => {
        const dataApi = await fetch(`https://shibe.online/api/shibes?count=1&urls=true&httpsUrls=true`)
        const [imageUrl] = await dataApi.json()
        await flowDynamic([{body:'😜', media: imageUrl}])
    })


const main = async () => {
    const adapterDB = new MemoryDB()
    const adapterFlow = createFlow([welcomeFlow])
    const adapterProvider = createProvider(BaileysProvider)

    adapterProvider.initHttpServer(3000)

    await createBot({
        flow: adapterFlow,
        provider: adapterProvider,
        database: adapterDB,
    })
}

main()

state

Conversational history

Often, we will need to manage conversations and keep the context in a memory called state which is volatile and accessible from any function executed in a stream.

  const welcomeFlow = addKeyword(['hello'])
      .addAnswer(
          "¿What's your name?",
          {capture: true},
          async (ctx, { flowDynamic, state }) => {
              await state.update({ name: ctx.body })
              await flowDynamic('Thanks for giving me your name!')
          }
      )
      .addAnswer(
          '¿How old are you?',
           {capture: true},
          async (ctx, { flowDynamic, state }) => {
              const name = state.get('name')
              await state.update({ age: ctx.body })
              await flowDynamic(`Thanks for sharing your age! ${name}`)
          }
      )
      .addAnswer('Here is your data:', null, async (_, { flowDynamic, state }) => {
          const myState = state.getMyState()
          await flowDynamic(`Name: ${myState.name} Age: ${myState.age}`)
      })

flowDynamic

Dynamic Messages

In other occasions we need to send messages in a dynamic way of data that can be variable, below you can see an example of how you should do it and how you should NOT do it.

let name = ''

const flow = addKeyword('hello')
    .addAnswer(`What is your name?`, { capture: true }, async (ctx) => {
        name = ctx.body
    })
    .addAnswer(`Your name is: ${name}`)
const flow = addKeyword('hello')
    .addAnswer(`What is your name?`, { capture: true }, async (ctx, { state }) => {
        await state.update({ name: ctx.body })
    })
    .addAction(async (ctx, { state, flowDynamic }) => {
        const name = state.get('name')
        await flowDynamic(`Your name is: ${name}`)
    })

Send File

When you want to send an image, audio, file or any other file you can do it this way. It is important to note that the URL must be publicly accessible.

const flow = addKeyword('hello')
    .addAnswer(`Send image from URL`, 
        { media: 'https://i.imgur.com/0HpzsEm.png' }
    )
    .addAnswer(`Send video from Local`, 
        { media: join(process.cwd(), 'assets', 'sample.png') }
    )
    .addAnswer(`Send video from URL`, 
        { media: 'https://media.giphy.com/media/KWZKwdBC2ODWlQ8kgt/giphy.mp4' }
    )
    .addAnswer(`Send file from URL`, 
        { media: 'https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf' }
    )

Other ways to use when the route is coming from a dynamic data source

const flow = addKeyword('hello')
    .addAction(async (_,{flowDynamic}) => {
        // ...db get source...
        await flowDynamic([
            {body:'This is an image', media:'https://i.imgur.com/0HpzsEm.png'}
        ])
        await flowDynamic([
            {body:'This is a video', media:'https://media.giphy.com/media/KWZKwdBC2ODWlQ8kgt/giphy.mp4'}
        ])
    })

If you need to send a file that is stored locally you can do that too. The use of join is recommended to ensure correct directory concatenation.

const flow = addKeyword('hello')
    .addAction(async (_,{flowDynamic}) => {
        const pathLocal = join('assets','doc.pdf')
        // pathLocal = c:/doc.pdf
        await flowDynamic([
            {body:'This is a video', media: pathLocal }
        ])
    })


gotoFlow

Switch to another flow

If you want to divert a conversational flow to another logic flow based on a response input you can do it in this way:


const flowToA = addKeyword(EVENTS.ACTION).addAnswer('Here we have Option A!')
const flowToB = addKeyword(EVENTS.ACTION).addAnswer('Here we have Option B!')
const flowToC = addKeyword(EVENTS.ACTION).addAnswer('Here we have Option C!')

const flowDefault = addKeyword(EVENTS.ACTION).addAnswer("We don't have that Option 🤔")

const flow = addKeyword('order')
    .addAnswer(
        [
            `Which one is the best option for you?`,
            `Type **A**`,
            `Type **B**`,
            `Type **C**`,
        ], 
        { capture: true }
    )
    .addAnswer(`Thanks for you answer`,async (ctx, {gotoFlow})=> {
        const userAnswer = ctx.body
        if(userAnswer === 'A'){
            return gotoFlow(flowToA)
        } 
        if(userAnswer === 'B'){
            return gotoFlow(flowToB)
        } 
        if(userAnswer === 'C'){
            return gotoFlow(flowToC)
        } 
        return gotoFlow(flowDefault)

    })
    .addAnswer(`this message will not be sent`)

//...Previous code...
    ....addAnswer(`Thanks for you answer`,async (ctx, {gotoFlow})=> {
        gotoFlow(flowToA)

    })
    .addAnswer(`this message will not be sent`)

//...Previous code...
    ....addAnswer(`Thanks for you answer`,async (ctx, {gotoFlow})=> {
        return gotoFlow(flowToA)

    })
    .addAnswer(`this message will not be sent`)

state

Turn off bot a certain user

Sometimes we will need to turn off the bot for a certain user, so that we can have a conversation with the client without the bot interfering.

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!')

state

Turn off for everyone

Sometimes we will need to disable the bot for all people, without the need to shut down the server or stop the script.

const flow = addKeyword<BaileysProvider>('botoff')
  .addAction(async (_, { globalState, endFlow }) => {
  const botOffForEveryOne = globalState.get<boolean>('botOffForEveryOne')
    await globalState.update({botOffForEveryOne:!botOffForEveryOne})
    if(botOffForEveryOne) return endFlow()
  })
  .addAnswer('Hello!')
  

state

Bot Self-Interaction

In certain scenarios, it is necessary for the bot's phone number (host) to be able to interact within logical flows. To achieve this, we have several configurable options:

  • host: This is used when you want the bot to be able to respond to messages in the same chat with itself. For example, if the bot's number is 0000, it will be able to send and receive messages to/from 0000.
  • both: This option allows both the bot and you (the developer/administrator) to intervene in the chat of a person interacting with the bot.
  • none: (default option) Only allows interaction between the user and the bot, without intervention from the host number.

app.ts

import { createBot, createProvider, createFlow, addKeyword, MemoryDB } from '@builderbot/bot'
import { BaileysProvider } from '@builderbot/provider-baileys'

const main = async () => {
    const adapterDB = new MemoryDB()
    const adapterFlow = createFlow([...])
    const adapterProvider = createProvider(BaileysProvider, {
          writeMyself: 'host' as 'none' | 'host' | 'both'
    })

    adapterProvider.initHttpServer(3000)

    await createBot({
        flow: adapterFlow,
        provider: adapterProvider,
        database: adapterDB,
    })
}

main()

Guides

My first chatbot

Learn how build your first chatbot in few minutes

Read more

Concepts

Understand the essential concepts for building bots

Read more

Add Functions

The key to learning how to write flows is add-functions.

Read more

Plugins

Unlimitate and start implementing the community plugins.

Read more

Resources

Modularize

Learn how to modularise flows so that you can have a more maintainable bot.

Send Message

How to send a message via HTTP to start conversations, you can send multimedia as well.

Dockerizer

A good practice is to dockerise your bots to make them more maintainable and effective.

Events

Learning about events will make us more fluent when creating chatbots.