Overview
The addAction method adds a callback function to a conversation flow without sending a message to the user. Itβs useful for performing background tasks, data processing, API calls, or flow control logic.
Method Signature
addAction (
actionProps : ActionPropertiesGeneric | CallbackFunction < P , B > ,
cb ?: CallbackFunction < P , B > ,
nested ?: TFlow < P , B > | TFlow < P , B > [] | null
): TFlow < P , B >
Parameters
actionProps
ActionPropertiesGeneric | CallbackFunction
Either configuration options or the callback function directly. When passing options object: When true, captures the userβs next message and passes it to the callback.
Delay in milliseconds before executing the action.
Deprecated. Idle timeout in milliseconds.
Media URL or path (typically used with capture).
Array of button objects (typically used with capture).
When passing a function directly, it becomes the callback.
The callback function to execute (when first parameter is options object). Message context containing:
body: Userβs message text
from: Userβs phone number/ID
name: Userβs name
Additional provider-specific data
Bot control methods:
flowDynamic(messages): Send dynamic messages
gotoFlow(flow, step?): Navigate to another flow
endFlow(message?): End the conversation
fallBack(message?): Return to previous step
state: User-specific state management
globalState: Global bot state management
provider: Provider instance
database: Database instance
blacklist: Blacklist management
queue: Queue management
extensions: Custom extensions
Optional child flow(s) to include in the actionβs scope.
Return Value
Returns the flow object for method chaining.
Usage Examples
Simple Action
import { addKeyword } from '@builderbot/bot'
const flow = addKeyword ( 'start' )
. addAnswer ( 'Processing your request...' )
. addAction ( async ( ctx , { flowDynamic }) => {
// Perform background task
const result = await someAsyncOperation ()
await flowDynamic ( `Operation completed: ${ result } ` )
})
const { addKeyword } = require ( '@builderbot/bot' )
const flow = addKeyword ( 'start' )
. addAnswer ( 'Processing your request...' )
. addAction ( async ( ctx , { flowDynamic }) => {
// Perform background task
const result = await someAsyncOperation ()
await flowDynamic ( `Operation completed: ${ result } ` )
})
Database Operations
const registerFlow = addKeyword ( 'register' )
. addAnswer (
'What is your email?' ,
{ capture: true }
)
. addAction ( async ( ctx , { state , database , flowDynamic }) => {
// Save to database
await database . save ({
from: ctx . from ,
email: ctx . body ,
timestamp: Date . now ()
})
await state . update ({ registered: true })
await flowDynamic ( 'Registration successful!' )
})
const registerFlow = addKeyword ( 'register' )
. addAnswer (
'What is your email?' ,
{ capture: true }
)
. addAction ( async ( ctx , { state , database , flowDynamic }) => {
// Save to database
await database . save ({
from: ctx . from ,
email: ctx . body ,
timestamp: Date . now ()
})
await state . update ({ registered: true })
await flowDynamic ( 'Registration successful!' )
})
API Integration
const lookupFlow = addKeyword ( 'lookup' )
. addAnswer ( 'Please enter the order ID:' , { capture: true })
. addAction ( async ( ctx , { flowDynamic }) => {
const orderId = ctx . body
try {
const response = await fetch ( `https://api.example.com/orders/ ${ orderId } ` )
const order = await response . json ()
await flowDynamic ([
`Order Status: ${ order . status } ` ,
`Items: ${ order . items . length } ` ,
`Total: $ ${ order . total } `
])
} catch ( error ) {
await flowDynamic ( 'Order not found. Please check the ID.' )
}
})
const lookupFlow = addKeyword ( 'lookup' )
. addAnswer ( 'Please enter the order ID:' , { capture: true })
. addAction ( async ( ctx , { flowDynamic }) => {
const orderId = ctx . body
try {
const response = await fetch ( `https://api.example.com/orders/ ${ orderId } ` )
const order = await response . json ()
await flowDynamic ([
`Order Status: ${ order . status } ` ,
`Items: ${ order . items . length } ` ,
`Total: $ ${ order . total } `
])
} catch ( error ) {
await flowDynamic ( 'Order not found. Please check the ID.' )
}
})
Flow Control
const premiumFlow = addKeyword ( 'premium' )
. addAnswer ( 'Premium features...' )
const freeFlow = addKeyword ( 'free' )
. addAnswer ( 'Free features...' )
const checkSubscription = addKeyword ( 'features' )
. addAction ( async ( ctx , { gotoFlow , database }) => {
const user = await database . findOne ({ phone: ctx . from })
if ( user ?. subscription === 'premium' ) {
return gotoFlow ( premiumFlow )
}
return gotoFlow ( freeFlow )
})
const premiumFlow = addKeyword ( 'premium' )
. addAnswer ( 'Premium features...' )
const freeFlow = addKeyword ( 'free' )
. addAnswer ( 'Free features...' )
const checkSubscription = addKeyword ( 'features' )
. addAction ( async ( ctx , { gotoFlow , database }) => {
const user = await database . findOne ({ phone: ctx . from })
if ( user ?. subscription === 'premium' ) {
return gotoFlow ( premiumFlow )
}
return gotoFlow ( freeFlow )
})
With Capture Option
const validateFlow = addKeyword ( 'validate' )
. addAnswer ( 'Please enter your code:' )
. addAction (
{ capture: true },
async ( ctx , { flowDynamic , endFlow }) => {
const code = ctx . body
const isValid = await validateCode ( code )
if ( isValid ) {
await flowDynamic ( 'Code verified successfully!' )
} else {
await flowDynamic ( 'Invalid code. Please try again.' )
return endFlow ()
}
}
)
const validateFlow = addKeyword ( 'validate' )
. addAnswer ( 'Please enter your code:' )
. addAction (
{ capture: true },
async ( ctx , { flowDynamic , endFlow }) => {
const code = ctx . body
const isValid = await validateCode ( code )
if ( isValid ) {
await flowDynamic ( 'Code verified successfully!' )
} else {
await flowDynamic ( 'Invalid code. Please try again.' )
return endFlow ()
}
}
)
State Management
const cartFlow = addKeyword ( 'cart' )
. addAnswer ( 'What would you like to add?' , { capture: true })
. addAction ( async ( ctx , { state , flowDynamic }) => {
// Get current cart
const cart = state . get < string []>( 'cart' ) || []
// Add item
cart . push ( ctx . body )
await state . update ({ cart })
await flowDynamic ( `Added " ${ ctx . body } " to cart. Total items: ${ cart . length } ` )
})
. addAnswer ( 'Add another item?' , { capture: true })
. addAction ( async ( ctx , { state , flowDynamic , endFlow }) => {
if ( ctx . body . toLowerCase () === 'no' ) {
const cart = state . get < string []>( 'cart' )
await flowDynamic ( `Final cart: ${ cart . join ( ', ' ) } ` )
return endFlow ()
}
})
const cartFlow = addKeyword ( 'cart' )
. addAnswer ( 'What would you like to add?' , { capture: true })
. addAction ( async ( ctx , { state , flowDynamic }) => {
// Get current cart
const cart = state . get ( 'cart' ) || []
// Add item
cart . push ( ctx . body )
await state . update ({ cart })
await flowDynamic ( `Added " ${ ctx . body } " to cart. Total items: ${ cart . length } ` )
})
. addAnswer ( 'Add another item?' , { capture: true })
. addAction ( async ( ctx , { state , flowDynamic , endFlow }) => {
if ( ctx . body . toLowerCase () === 'no' ) {
const cart = state . get ( 'cart' )
await flowDynamic ( `Final cart: ${ cart . join ( ', ' ) } ` )
return endFlow ()
}
})
Delayed Action
const reminderFlow = addKeyword ( 'remind' )
. addAnswer ( 'Setting up your reminder...' )
. addAction (
{ delay: 5000 }, // Wait 5 seconds
async ( ctx , { flowDynamic }) => {
await flowDynamic ( 'This is your reminder!' )
}
)
const reminderFlow = addKeyword ( 'remind' )
. addAnswer ( 'Setting up your reminder...' )
. addAction (
{ delay: 5000 }, // Wait 5 seconds
async ( ctx , { flowDynamic }) => {
await flowDynamic ( 'This is your reminder!' )
}
)
Blacklist Management
const blockFlow = addKeyword ( 'block' )
. addAnswer ( 'Enter phone number to block:' , { capture: true })
. addAction ( async ( ctx , { blacklist , flowDynamic }) => {
const phoneToBlock = ctx . body
blacklist . add ( phoneToBlock )
await flowDynamic ( `Blocked ${ phoneToBlock } ` )
})
const blockFlow = addKeyword ( 'block' )
. addAnswer ( 'Enter phone number to block:' , { capture: true })
. addAction ( async ( ctx , { blacklist , flowDynamic }) => {
const phoneToBlock = ctx . body
blacklist . add ( phoneToBlock )
await flowDynamic ( `Blocked ${ phoneToBlock } ` )
})
Key Differences from addAnswer
Feature addAnswer addAction Sends message Yes No Executes callback Optional Required Use case Respond to user Background processing Visibility User sees message Silent operation
addAction does not send any message by default - use flowDynamic() to send messages from within the callback
Perfect for data validation, API calls, database operations, and flow control
When capture: true, the action waits for user input before executing
Callbacks are async-compatible - always use async/await for asynchronous operations
Use endFlow() to stop the conversation, fallBack() to return to previous step
State changes persist across the conversation for the same user