Table of Contents

  1. Install Botkit on your computer

  2. Create a Botkit powered Node app:

    botkit new --platform facebook
  3. Follow this guide to configuring the Facebook API

Since Facebook delivers messages via web hook, your application must be available at a public internet address. Additionally, Facebook requires this address to use SSL. Luckily, you can use LocalTunnel to make a process running locally or in your dev environment available in a Facebook-friendly way.

When you are ready to go live, consider LetsEncrypt.org, a free SSL Certificate Signing Authority which can be used to secure your website very quickly. It is fabulous and we love it.

To connect Botkit to Facebook, use the constructor method, Botkit.facebookbot(). This will create a Botkit controller with all core features as well as some additional methods.

Argument Description
config an object containing configuration options

Returns a new Botkit controller.

The config argument is an object with these properties:

Name Type Description
studio_token String An API token from Botkit Studio
debug Boolean Enable debug logging
access_token string Page access token from Facebook
verify_token string Verification token from Facebook
require_appsecret_proof Boolean Enable checking for app secret
require_delivery Boolean Require delivery confirmation of messages

For example:

var Botkit = require('botkit');
var controller = Botkit.facebookbot({
        access_token: process.env.access_token,
        verify_token: process.env.verify_token,
})

In addition to the core events that Botkit fires, this connector also fires some platform specific events.

In fact, Botkit will receive, normalize and emit any event that it receives from Facebook. This includes all of the events listed here.

Normal messages will be sent to your bot using the message_received event. In addition, several other events may fire, depending on your implementation and the webhooks you subscribed to within your app's Facebook configuration.

Event Description
message_received a message was received by the bot
facebook_postback user clicked a button in an attachment and triggered a webhook postback

Event Description
message_delivered a confirmation from Facebook that a message has been received
message_echo if enabled in Facebook, an "echo" of any message sent by the bot
message_read a confirmation from Facebook that a message has been read

Event Description
facebook_account_linking a user has started the account linking
facebook_optin a user has clicked the Send-to-Messenger plugin
facebook_referral a user has clicked on a m.me URL with a referral param
facebook_app_roles This callback will occur when a page admin changes the role of your application.
standby This callback will occur when a message has been sent to your page, but your application is not the current thread owner.
facebook_receive_thread_control This callback will occur when thread ownership for a user has been passed to your application.
facebook_lose_thread_control This callback will occur when thread ownership for a user has been taken away from your application.

Botkit receives messages from Facebook using webhooks, and sends messages using Facebook's APIs. This means that your bot application must present a web server that is publicly addressable. Everything you need to get started is already included in Botkit.

To connect your bot to Facebook, follow the instructions here. You will need to collect your page token as well as a verify token that you define yourself and configure inside Facebook's app settings. A step by step guide can be found here. Since you must already be running your Botkit app to configure your Facebook app, there is a bit of back-and-forth. It's ok! You can do it.

Here is the complete code for a basic Facebook bot:

var Botkit = require('botkit');
var controller = Botkit.facebookbot({
        access_token: process.env.access_token,
        verify_token: process.env.verify_token,
})

var bot = controller.spawn({
});

// if you are already using Express, you can use your own server instance...
// see "Use BotKit with an Express web server"
controller.setupWebserver(process.env.port,function(err,webserver) {
  controller.createWebhookEndpoints(controller.webserver, bot, function() {
      console.log('This bot is online!!!');
  });
});

// this is triggered when a user clicks the send-to-messenger plugin
controller.on('facebook_optin', function(bot, message) {

    bot.reply(message, 'Welcome to my app!');

});

// user said hello
controller.hears(['hello'], 'message_received', function(bot, message) {

    bot.reply(message, 'Hey there.');

});

controller.hears(['cookies'], 'message_received', function(bot, message) {

    bot.startConversation(message, function(err, convo) {

        convo.say('Did someone say cookies!?!!');
        convo.ask('What is your favorite type of cookie?', function(response, convo) {
            convo.say('Golly, I love ' + response.text + ' too!!!');
            convo.next();
        });
    });
});

Facebook sends an X-HUB signature header with requests to your webhook. You can verify the requests are coming from Facebook by enabling validate_requests: true when creating your bot controller. This checks the sha1 signature of the incoming payload against your Facebook App Secret (which is seperate from your webhook's verify_token), preventing unauthorized access to your webhook. You must also pass your app_secret into your environment variables when running your bot.

The Facebook App secret is available on the Overview page of your Facebook App's admin page. Click show to reveal it.

app_secret=abcdefg12345 page_token=123455abcd verify_token=VerIfY-tOkEn node examples/facebook_bot.js

Facebook Messenger supports including "postback" buttons, which, when clicked, send a specialized facebook_postback event.

Developers may find it useful if button clicks are treated as "typed" messages. In order to "hear" these events, add the facebook_postback event to the list of events specified in the second parameter to the hears() function. This enables buttons to be used as part of a conversation flow, with the button's payload field being used for the message text.

When used in conjunction with convo.ask, Botkit will treat the button's payload field as if were a message typed by the user.

// receive a message whether it is typed or part of a button click
controller.hears('hello','message_received,facebook_postback', function(bot,message) {

  bot.reply(message, 'Got it!');

});

In order to guarantee the order in which your messages arrive, Botkit supports an optional delivery confirmation requirement. This will force Botkit to wait for a message_delivered events for each outgoing message before continuing to the next message in a conversation.

Developers who send many messages in a row, particularly with payloads containing images or attachments, should consider enabling this option. Facebook's API sometimes experiences a delay delivering messages with large files attached, and this delay can cause messages to appear out of order.

To enable this option, pass in {require_delivery: true} to your Botkit Facebook controller, as below:

var controller = Botkit.facebookbot({
        access_token: process.env.access_token,
        verify_token: process.env.verify_token,
        require_delivery: true,
})

This function configures the route https://_your_server_/facebook/receive to receive webhooks from Facebook.

This url should be used when configuring Facebook.

You can attach little bubbles

And in those bubbles can be buttons and when a user clicks the button, it sends a postback with the value.

controller.hears('test', 'message_received', function(bot, message) {

    var attachment = {
        'type':'template',
        'payload':{
            'template_type':'generic',
            'elements':[
                {
                    'title':'Chocolate Cookie',
                    'image_url':'http://cookies.com/cookie.png',
                    'subtitle':'A delicious chocolate cookie',
                    'buttons':[
                        {
                        'type':'postback',
                        'title':'Eat Cookie',
                        'payload':'chocolate'
                        }
                    ]
                },
            ]
        }
    };

    bot.reply(message, {
        attachment: attachment,
    });

});

controller.on('facebook_postback', function(bot, message) {

    if (message.payload == 'chocolate') {
        bot.reply(message, 'You ate the chocolate cookie!')
    }

});

Use a message with a sender_action field with "typing_on" to create a typing indicator. The typing indicator lasts 20 seconds, unless you send another message with "typing_off"

var reply_message = {
  sender_action: "typing_on"
}

bot.reply(message, reply_message)

To make it a bit more realistic, you can trigger a "user is typing" signal (shown in Messenger as a bubble with 3 animated dots) by using the following convenience methods.

bot.startTyping(message, function () {
  // do something here, the "is typing" animation is visible
});

bot.stopTyping(message, function () {
  // do something here, the "is typing" animation is not visible
});

bot.replyWithTyping(message, 'Hello there, my friend!');

When sending a user a message you can make the message have either no notification or have a notification that doesn't play a sound. Both of these features are unique to the mobile application messenger. To do this add the notification_type field to message. Notification type must be one of the following:

notification_type is optional. By default, messages will be REGULAR push notification type

reply_message = {
    text: "Message text here",
    notification_type: NOTIFICATION_TYPE
}
bot.reply(message, reply_message)

Messenger Codes can be scanned in Messenger to instantly link the user to your bot, no typing needed. They're great for sticking on fliers, ads, or anywhere in the real world where you want people to try your bot.

controller.api.messenger_profile.get_messenger_code(2000, function (err, url) {
    if(err) {
        // Error
    } else {
        // url
    }
});
controller.api.messenger_profile.get_messenger_code(2000, function (err, url) {
    if(err) {
        // Error
    } else {
        // url
    }
}, 'billboard-ad');

Thread settings API is now messenger profile API, it's highly recommended to use profile API instead of thread settings one, however, Botkit thread settings interface still available:

controller.api.messenger_profile.YOUR_METHOD_NAME();
controller.api.thread_settings.YOUR_METHOD_NAME();

Facebook offers a Messenger Profile API to customize special bot features such as a persistent menu and a welcome screen. We highly recommend you use all of these features, which will make your bot easier for users to work with. Read Facebook's docs here.

Argument Description
message greeting message to display on welcome screen

Remove the greeting message.

Get the greeting setting.

Argument Description
payload value for the postback payload sent when the button is clicked

Set the payload value of the 'Get Started' button

Clear the payload value of the 'Get Started' button and remove it.

Get the get started setting.

Argument Description
menu_items an array of menu_item objects

Create a persistent menu for your Bot

Clear the persistent menu setting

Get the menu setting.

Argument Description
payload the account link.

Remove the account link

Get the account link

Argument Description
payload A single or a list of domains to add to the whitelist, All domains must be valid and use https. Up to 10 domains allowed.

Remove all domains

Get a list of the whitelisted domains.

Argument Description
payload A home_url object with the properties url, webview_height_ratio, in_test

View the facebook documentation for details of the home_url payload object.

NB. The value of the url property must be present in the domain_whitelist array

Remove the home_url setting

Get the home_url

Argument Description
payload A JSON object with the properties privacy_url, public_key, testers

View the facebook documentation for more details.

Remove the payment_settings setting

Get the payment_settings property of your bot's Messenger Profile

Argument Description
payload A JSON object with the properties privacy_url, public_key, testers

View the facebook documentation for more details.

Remove the payment_settings setting

Get the payment_settings property of your bot's Messenger Profile

controller.api.messenger_profile.greeting('Hello! I\'m a Botkit bot!');
controller.api.messenger_profile.get_started('sample_get_started_payload');
controller.api.messenger_profile.menu([{
        "locale":"default",
        "composer_input_disabled":true,
        "call_to_actions":[
            {
                "title":"My Skills",
                "type":"nested",
                "call_to_actions":[
                    {
                        "title":"Hello",
                        "type":"postback",
                        "payload":"Hello"
                    },
                    {
                        "title":"Hi",
                        "type":"postback",
                        "payload":"Hi"
                    }
                ]
            },
            {
                "type":"web_url",
                "title":"Botkit Docs",
                "url":"https://github.com/howdyai/botkit/blob/master/readme-facebook.md",
                "webview_height_ratio":"full"
            }
        ]
    },
    {
        "locale":"zh_CN",
        "composer_input_disabled":false
    }
]);
controller.api.messenger_profile.account_linking('https://www.yourAwesomSite.com/oauth?response_type=code&client_id=1234567890&scope=basic');
controller.api.messenger_profile.get_account_linking(function (err, accountLinkingUrl)  {
    console.log('****** Account linkink URL:', accountLinkingUrl);
});
controller.api.messenger_profile.delete_account_linking();
controller.api.messenger_profile.domain_whitelist('https://localhost');
controller.api.messenger_profile.domain_whitelist(['https://127.0.0.1', 'https://0.0.0.0']);
controller.api.messenger_profile.delete_domain_whitelist();
controller.api.messenger_profile.get_domain_whitelist(function (err, data)  {
    console.log('****** Whitelisted domains:', data);
});

controller.api.messenger_profile.home_url({
    "url": 'https://mydomain.com',
    "webview_height_ratio": 'tall',
    "in_test": false
})

controller.api.messenger_profile.get_home_url(function (err, data)  {
    console.log('****** Home url:', data);
});

controller.api.messenger_profile.delete_home_url();

// Target Audience
controller.api.messenger_profile.target_audience({
    "audience_type":"custom",
    "countries":{
        "whitelist":["US", "CA"]
    }
});
controller.api.messenger_profile.delete_target_audience();
controller.api.messenger_profile.get_target_audience(function (err, data)  {
    console.log('****** Target Audience:', data);
});

Attachment upload API allows you to upload an attachment that you may later send out to many users, without having to repeatedly upload the same data each time it is sent:

var attachment = {
        "type":"image",
        "payload":{
            "url":"https://pbs.twimg.com/profile_images/803642201653858305/IAW1DBPw_400x400.png",
            "is_reusable": true
        }
    };

    controller.api.attachment_upload.upload(attachment, function (err, attachmentId) {
        if(err) {
            // Error
        } else {
            var image = {
                "attachment":{
                    "type":"image",
                    "payload": {
                        "attachment_id": attachmentId
                    }
                }
            };
            bot.reply(message, image);
        }
    });

Facebook offers some built-in natural language processing tools. Once enabled, messages may contain a message.nlp. object with the results of the Facebook NLP. More information can be found in Facebook's official documentation of this feature.

If specified, message.nlp.entities will include a list of entities and intents extracted by Facebook.

Facebook's NLP option can be enabled by calling controller.api.nlp.enable(OPTIONAL_WIT_TOKEN) in your Botkit app.

Facebook's NLP option can be disabled by calling controller.api.nlp.disable(OPTIONAL_WIT_TOKEN) in your Botkit app.

Adding a tag to a message allows you to send it outside the 24+1 window.

View the facebook documentation for more details.

controller.api.tags.get_all(function (tags) {
   // use tags.data
});
var taggedMessage = {
        "text": "Hello Botkit !",
        "tag": "RESERVATION_UPDATE"
};
bot.reply(message, taggedMessage);

To improve security and prevent your bot against man in the middle attack, it's highly recommended to send an app secret proof:

var controller = Botkit.facebookbot({
    access_token: process.env.page_token,
    verify_token: process.env.verify_token,
    app_secret: process.env.app_secret,
    require_appsecret_proof: true // Enable send app secret proof
});

More information about how to secure Graph API Requests here

The Messenger Platform handover protocol enables two or more applications to collaborate on the Messenger Platform for a Page.

View the facebook documentation for more details.

Allows the Primary Receiver app to retrieve the list of apps that are Secondary Receivers for a page. Only the app with the Primary Receiver role for the page may use this API.

controller.api.handover.get_secondary_receivers_list('id,name', function (result) {
   // result.data = list of Secondary Receivers
});

The Primary Receiver app can take control of a specific thread from a Secondary Receiver app:

controller.api.handover.take_thread_control('<RECIPIENT_PSID>', 'String to pass to pass to the secondary receiver', function (result) {
   // result = {"success":true}
});

To pass the thread control from your app to another app:

controller.api.handover.pass_thread_control('<RECIPIENT_PSID>', '<TARGET_PSID>', 'String to pass to the secondary receiver app', function (result) {
   // result = {"success":true}
});

The Request Thread Control API allows a Secondary Receiver app to notify the Primary Receiver that it wants control of the chat :

controller.api.handover.request_thread_control('<RECIPIENT_PSID>', 'String to pass to request the thread control', function (result) {

});

Th Thread Owner API returns the app ID of the app the currently has thread control for a Page :

controller.api.handover.get_thread_owner('<RECIPIENT_PSID>', function (result) {

});

controller.api.handover.cancel_scheduled_broadcast('<BROADCAST_ID>', function (result) {

});

controller.api.handover.get_broadcast_status('<BROADCAST_ID>', ['scheduled_time', 'status'], function (result) {

});

You can identify the purpose of the message being sent to Facebook by adding messaging_type: <MESSAGING_TYPE> property when sending the message:

var messageToSend = {
        "text": "Hello Botkit !",
        "messaging_type": "RESPONSE"
};
bot.reply(message, messageToSend);

This is a more explicit way to ensure bots are complying with Facebook policies for specific messaging types and respecting people's preferences.

The following values for 'messaging_type' are supported:

Messaging Type Description
RESPONSE Message is in response to a received message. This includes promotional and non-promotional messages sent inside the 24-hour standard messaging window or under the 24+1 policy. For example, use this tag to respond if a person asks for a reservation confirmation or an status update.
UPDATE Message is being sent proactively and is not in response to a received message. This includes promotional and non-promotional messages sent inside the the 24-hour standard messaging window or under the 24+1 policy.
MESSAGE_TAG Message is non-promotional and is being sent outside the 24-hour standard messaging window with a message tag. The message must match the allowed use case for the tag.
NON_PROMOTIONAL_SUBSCRIPTION Message is non-promotional, and is being sent under the subscription messaging policy by a bot with the pages_messaging_subscriptions permission.

By default Botkit will send a RESPONSE messaging type when you send a simple message with bot.reply(message, "this is a simple message""), conversation.say("this is a simple message") or conversation.ask("this is a simple message", ...).

Broadcast Messages API allows you to send a message to many recipients, this means sending messages in batches to avoid hitting the Messenger Platform's rate limit, which can take a very long time.

More information about the Broadcast Messages API can be found here

Messages sent with the Broadcast API must be defined in advance.

To create a broadcast message:

/* Simple example */
controller.api.broadcast.create_message_creative("Hello friend !", function (err, body) {
    // Your awesome code here
    console.log(body['message_creative_id']);
    // And here
});

/* Personalizing Messages example */
controller.api.broadcast.create_message_creative({
    'dynamic_text': {
        'text': 'Hi, {{first_name}}!',
        'fallback_text': 'Hello friend !'
    }
}, function (err, body) {
    // Your awesome code here
    console.log(body['message_creative_id']);
    // And here
});

To send a broadcast message, you call controller.api.broadcast.send(...) with the broadcast message ID.

On success, Botkit will return a numeric broadcast_id that can be used to identify the broadcast for analytics purposes:

controller.api.broadcast.send('<CREATIVE_ID>', null, function (err, body) {
    // Your awesome code here
    console.log(body['broadcast_id']);
    // And here
});

If you would like to add notification type and tag you can pass an object:

var message = {
    message_creative_id: '<CREATIVE_ID>',
    notification_type: '<REGULAR | SILENT_PUSH | NO_PUSH>',
    tag: '<MESSAGE_TAG>'
}

controller.api.broadcast.send(message, null, function (err, body) {
    // Your awesome code here
    console.log(body['broadcast_id']);
    // And here
});

Once a broadcast has been delivered, you can find out the total number of people it reached by calling controller.api.broadcast.get_broadcast_metrics(...).

controller.api.broadcast.get_broadcast_metrics("<BROADCAST_ID>", function (err, body) {
    // Your awesome code here
});

By default, the Broadcast API sends your message to all open conversations with your Messenger bot. To allow you broadcast to a subset of conversations, the Broadcast API supports 'custom labels', which can be associated with individual PSIDs.

To create a label:

controller.api.broadcast.create_label("<LABEL_NAME>", function (err, body) {
    // Your awesome code here
});

To associate a label to a specific user:

controller.api.broadcast.add_user_to_label(message.user, "<LABEL_ID>", function (err, body) {
    // Your awesome code here
});

To send a broadcast message to the set of users associated with a label:

controller.api.broadcast.send('<BROADCAST_MESSAGE_ID>', '<CUSTOM_LABEL_ID>', function (err, body) {
    // Your awesome code here
    console.log(body['broadcast_id']);
    // And here
});

To remove a label currently associated with a user:

controller.api.broadcast.remove_user_from_label(message.user, '<LABEL_ID>', function (err, body) {
    // Your awesome code here
});

To retrieve the labels currently associated with a USER:

controller.api.broadcast.get_labels_by_user(message.user, function (err, body) {
    // Your awesome code here
});

To retrieve a single label:

controller.api.broadcast.get_label_details('<LABEL_ID>', ['name'], function (err, body) {
    // Your awesome code here
});

To retrieve the list of all the labels for the page:

controller.api.broadcast.get_all_labels(['name'], function (err, body) {
    // Your awesome code here
});

To delete a label:

controller.api.broadcast.remove_label('<LABEL_ID>', function (err, body) {
    // Your awesome code here
});

The Messaging Insights API, allows you to programatically retrieve the same information that appears in the Page Insights tab of your Facebook Page.

To get insights with Botkit, you shuld call controller.api.insights.get_insights(...) with parameters metrics, since and until:

Parameter Description
metrics An array or a comma-separated list of metrics to return.
since UNIX timestamp of the start time to get the metric for.
until UNIX timestamp of the end time to get the metric for.
controller.api.insights.get_insights('page_messages_active_threads_unique', null, null, function (err, body) {
    console.log(body);
    console.log(err);
});

Instead of the web server generated with setupWebserver(), it is possible to use a different web server to receive webhooks, as well as serving web pages.

Here is an example of using an Express web server alongside BotKit for Facebook Messenger.

Is something missing or out of date?

This file is managed on Github. click here to view the source, and send us a pull request with your improvements!