The material, the translation of which we present to your attention today, is devoted to the development of chat bot for Facebook Messenger. The bot, which is called Aww Bot, communicating with users, will send them pictures of cute cats and dogs.

Beginning of work
Let's start by creating a page on
Facebook by filling in the required fields. This page is for bot. In addition,
we will create a Facebook application, then, on the Add a Product page, we will connect the Messenger product to the application. Next, we will be on the settings page of the messenger. Here you need to find the section Token Generation, in it - select the bot page in the Page list. After that, we will be asked for permissions and an access token will be created. The bot will use this token to make calls to the Facebook Messenger API, which will allow it to communicate with users.
Web server setup
We will use node.js and express.js to create an HTTP server. Run the following command:
npm install express body-parser request config
Add to
index.js
following code that will allow you to create a simple HTTP server:
'use strict'; let express = require('express'), bodyParser = require('body-parser'), app = express(); app.use(bodyParser.urlencoded({ extended: false })); app.use(bodyParser.json()); app.listen(8989, () => console.log('Example app listening on port 8989!')); app.get('/', (req, res) => res.send('Hello World!'));
Now, if you start the server and go, using the browser, at
http://127.0.0.1:8989
, you can see the page with the server's response -
Hello World!
.
HTTPS and local development environment
Before moving to working with Webhook technology, we need to configure HTTPS for the development environment. The messenger will not accept the Webhook address used to send notifications to our server if you use a self-signed SSL certificate. Free certificate can be obtained from
Let's Encrypt . Here, however, you can get a certificate only for the domain, and not for the IP address. We will use the
ngrok service, which will allow access to the local server through a public URL that uses HTTPS.
Ngrok setup
ngrok
easy. You just need to download a compressed
archive from the project site, unpack it and execute the following command:
./ngrok http 80
Do not forget to redirect port 80 to 8989 in the WAN settings of your router. As a result,
ngrok
will create public HTTP and HTTPS addresses for the local server.
Work with Webhook notifications
The messenger uses Webhook technology for authentication and to send notifications about events to your application. From a programming point of view, it all comes down to the work of ordinary callback functions for processing HTTP requests that will receive data about events, such as messages received by a chat bot. To parse GET and POST requests, we will use the
body-parser
module.
Add the following route to the application. It is needed to process Webhook verification requests.
// GET- webhook app.get('/webhook', (req, res) => { // . , let VERIFY_TOKEN = "SOMETHING_RANDOM"; // let mode = req.query['hub.mode']; let token = req.query['hub.verify_token']; let challenge = req.query['hub.challenge']; // , mode token if (mode && token) { // mode token if (mode === 'subscribe' && token === VERIFY_TOKEN) { // challenge console.log('WEBHOOK_VERIFIED'); res.status(200).send(challenge); } else { // '403 Forbidden' res.sendStatus(403); } } });
Now you need to open the settings of the messenger, find the Webhooks section there and configure the integration of the application with Webhook notifications. On the settings page, in the Callback URL field, you must enter our HTTPS URL, obtained from ngrok. The verification token (the one that is present in the code and represents the random string we created) must be placed in the Verify Token field. After that, you should be able to verify and save the settings by clicking the Verify and Save button, if your URL for processing Webhook notifications is available, and the verification token corresponds to the one in the code.
Setting a token and URL for the application to receive Webhook notificationsAfter saving, select your page from the drop-down list and subscribe to the page events.
Now create a POST route for handling POST events from the messenger. Add the following code to the application.
// webhook app.post('/webhook', (req, res) => { let body = req.body; if (body.object === 'page') { // , body.entry.forEach(function(entry) { // entry.messaging , // , 0 let webhook_event = entry.messaging[0]; console.log(webhook_event); // PSID let sender_psid = webhook_event.sender.id; console.log('Sender PSID: ' + sender_psid); // , , message postback, // - if (webhook_event.message) { console.log(webhook_event.message) } else if (webhook_event.postback) { console.log(webhook_event.postback) } }); // '200 OK' res.status(200).send('EVENT_RECEIVED'); } else { // '404 Not Found', , res.sendStatus(404); } });
We set up the application so that it handles two types of events -
message
and
postback
. In order to check the operation of the Webhook-notification mechanism, open the messenger and send a bot message to the page. If everything works as it should, the PSID of the sender, the event information and the message content will be logged. Now we will write handler functions for events of interest to us.
// message const handleMessage = (sender_psid, received_message) => { let response; if (received_message.text) { } } // postback const handlePostback = (sender_psid, received_postback) => { let response; // postback let payload = received_postback.payload; if(payload === 'GET_STARTED'){ } }
The
handleMessage()
method is responsible for handling incoming messages, and the
handlePostback()
method is responsible for handling
handlePostback()
inbound events. Update the existing code by adding calls to these methods:
// // - if (webhook_event.message) { handleMessage(sender_psid, webhook_event.message); } else if (webhook_event.postback) { handlePostback(sender_psid, webhook_event.postback); }
Now, when we receive a
message
or
postback
, the data will be sent to the appropriate handler along with the sender's PSID.
Setting the welcome screen and postback events to start a dialogue with the bot
When a new user starts a conversation with a bot, the Get Started button is displayed in the chat window. You can set up your own postback event for this situation. For example, set a message for the user, which describes the bot and how to communicate with it. In order to customize your own greeting, run this
curl
command in the terminal:
curl -X POST -H "Content-Type: application/json" -d '{ "greeting": [ { "locale":"default", "text":"Hello {{user_first_name}}! Are you ready to see the cutests cats and dogs" } ] }' "https://graph.facebook.com/v2.6/me/messenger_profile?access_token=YOUR_PAGE_ACCESS_TOKEN"
We set up Aww Bot to display a message asking the user if he is ready to see the cutest cats and dogs. To set up a postback event, issue this command in a terminal:
curl -X POST -H "Content-Type: application/json" -d '{ "get_started": {"payload": "GET_STARTED"} }' "https://graph.facebook.com/v2.6/me/messenger_profile?access_token=YOUR_PAGE_ACCESS_TOKEN"
Here’s what a chat session with a bot looks like.
Start screenApplication setup
We will use the npm configuration module to store the page access token in a separate configuration file. Create the
config
directory in our project and the
default.json
file in it. In this file, you must add the access token to the page and make an entry about this file in
.gitignore
.
{ "facebook": { "page": { "access_token": "PAGE_ACCESS_TOKEN" } } }
We will get a page access token in the
callSendAPI()
method using the
config.get('facebook.page.access_token')
command
config.get('facebook.page.access_token')
.
Handle start event
Here is the code to handle the start event.
const handlePostback = (sender_psid, received_postback) => { let response;
Create a method
askTemplate()
, which will return a properly prepared response object for the messenger API. The
callSendAPI()
method will send a message to the user. Add the following methods to the application:
const askTemplate = (text) => { return { "attachment":{ "type":"template", "payload":{ "template_type":"button", "text": text, "buttons":[ { "type":"postback", "title":"Cats", "payload":"CAT_PICS" }, { "type":"postback", "title":"Dogs", "payload":"DOG_PICS" } ] } } } } // API Send const callSendAPI = (sender_psid, response, cb = null) => { // let request_body = { "recipient": { "id": sender_psid }, "message": response }; // HTTP- Messenger Platform request({ "uri": "https://graph.facebook.com/v2.6/me/messages", "qs": { "access_token": config.get('facebook.page.access_token') }, "method": "POST", "json": request_body }, (err, res, body) => { if (!err) { if(cb){ cb(); } } else { console.error("Unable to send message:" + err); } }); }
We send the user a message containing two buttons and text. When the user selects what he needs by clicking the appropriate button, a request with the data of the
postback
event will be sent to our Webhook-address and we will process it.
The user is prompted to select the type of images he is interested in.Handling your own postback events
Update the code for the postback event handler
postback
:
const handlePostback = (sender_psid, received_postback) => { let response; // postback- let payload = received_postback.payload; // , if (payload === 'CAT_PICS') { response = imageTemplate('cats', sender_psid); callSendAPI(sender_psid, response, function(){ callSendAPI(sender_psid, askTemplate('Show me more')); }); } else if (payload === 'DOG_PICS') { response = imageTemplate('dogs', sender_psid); callSendAPI(sender_psid, response, function(){ callSendAPI(sender_psid, askTemplate('Show me more')); }); } else if(payload === 'GET_STARTED'){ response = askTemplate('Are you a Cat or Dog Person?'); callSendAPI(sender_psid, response); } // }
When a user clicks on the
Cats
button, our address used to process Webhook notifications will receive a request with a
postback
event containing
CAT_PICS
data. Selecting the
Dogs
option will send a
postback
event with
DOG_PICS
data. We added another method to the system,
imageTemplate()
, which returns a message containing a link to the image of a cat or dog.
Creating a simple API that returns links to images
Let's write a simple API to return links to the images of cats or dogs that will be used in messages sent by the bot to users. Create a
pics.js
file and add the following code to it:
module.exports = { cats : [ 'https://i.imgur.com/Qbg7CeM.jpg', 'https://i.imgur.com/nUzkpJY.jpg', 'https://i.imgur.com/NpDcKph.jpg', 'https://i.imgur.com/oJtSDaO.jpg', 'https://i.redd.it/82ajpsrd17111.jpg', 'https://i.redd.it/00km1d2rt0111.jpg', 'https://i.redd.it/rdbavhp0y7111.jpg', 'https://i.redd.it/5hn3mg0n98111.jpg', 'https://i.redd.it/d23pb8mta6111.jpg', 'https://i.redd.it/d2gyrwgy7oz01.jpg', 'https://i.redd.it/z4sgl84q72z01.jpg', 'https://i.redd.it/wvykzo8n1cy01.jpg' ], dogs : [ 'https://i.redd.it/6tjihi2qe7111.jpg', 'https://i.imgur.com/etRCs56.jpg', 'https://i.redd.it/nibw50f8y4111.jpg', 'https://i.redd.it/izcvnvj1o7111.jpg', 'https://i.redd.it/eqs1g9dldz011.jpg', 'https://i.redd.it/civ9dnu9u1111.jpg', 'https://i.redd.it/kk03qwclkp011.jpg', 'https://i.redd.it/2694pupjne011.jpg', 'https://i.redd.it/qk49ls5y6oy01.jpg', 'https://i.imgur.com/oM3mKgB.jpg', 'https://i.redd.it/8kx2riaulux01.jpg' ] };
Now connect it in the application.
images = require('./pics');
Add to the code the following method used to generate a message containing a link to the image.
const = imageTemplate(type, sender_id) => { return { "attachment":{ "type":"image", "payload":{ "url": getImage(type, sender_id), "is_reusable":true } } } }
In the process of user interaction with the bot, images are alternately extracted from the array and sent as bot answers to the user. After sending the last image, we return to the top of the list.
Let's add to the project the following code intended for storing and processing data about users communicating with the bot.
let users = {}; const = getImage(type, sender_id) => { // - if(users[sender_id] === undefined){ users = Object.assign({ [sender_id] : { 'cats_count' : 0, 'dogs_count' : 0 } }, users); } let count = images[type].length, // user = users[sender_id], // , user_type_count = user[type+'_count']; // let updated_user = { [sender_id] : Object.assign(user, { [type+'_count'] : count === user_type_count + 1 ? 0 : user_type_count + 1 }) }; // users = Object.assign(users, updated_user); console.log(users); return images[type][user_type_count]; }
We store the PSID of each of the users communicating with the bot, as a key in the
users
object. If there is no user record yet, create a new record. We will update the image number information each time a user requests a picture of a cat or dog. Then we return the absolute path to the image that will be used in the message template. Next, we send a message with the image as a response to the
postback
event, generated when the user selects the type of image of interest.
// , postback- if (payload === 'CAT_PICS') { response = imageTemplate('cats', sender_psid); callSendAPI(sender_psid, response, function(){ callSendAPI(sender_psid, askTemplate('Show me more')); }); } else if (payload === 'DOG_PICS') { response = imageTemplate('dogs', sender_psid); callSendAPI(sender_psid, response, function(){ callSendAPI(sender_psid, askTemplate('Show me more')); }); } else if(payload === 'GET_STARTED'){ response = askTemplate('Are you a Cat or Dog Person?'); callSendAPI(sender_psid, response); }
In addition, after sending the image, we pass to the
callSendAPI()
method a
callSendAPI()
function to send the user a new question about which images he is interested in. If successful, we call this function. This scheme of work, taking into account the asynchronous nature of callback functions, allows the user to receive a message asking for the next image after the message with the image requested earlier was sent to him.
Communication with the botResults
Here is the repository of this project. There, in the
readme.md
file, you can find instructions for installing and configuring the bot. In order for other people to communicate with your bot, your Facebook application must be approved. Up to this point, only administrators and testers of your application can talk to the bot.
Here is a video demonstrating the process of communicating with the bot.
Dear readers! Do you plan to create bots for Facebook Messenger?
