Build a Facebook Messenger Bot App

build a facebook messenger bot from scratch in minutes. Configure answers, questions and other types of replies. This is built using TypeScript, NodeJs, Express

fb_bot

Here is the source code {Github Link}

The goal of this post is to showcase how easy it is to create a Facebbok Messenger Bot which is capable of handling almost all of your customer's queries or questions etc. Lets dive into the code.

Installation

git clone https://github.com/prashantban/Facebook-Bot-App
cd Facebook-Bot-App
npm install
npm build (To build app)
npm run (To run app)

Before we begin running this app, we need coupld of things from Facebook Developer . Here is the list of things needed -

Facebook Page 
Facebook Developer App
Access Token
App Secret
Verify Token

Here is the link for Facebook Developer Panel. Now follow the instruction to create a new Facebook Messenger App.

Add a product Messenger
Select your FB Page and generate the token. This will be your access token.
Then you need to setup webhook endpoint. For this, we will have to write some code and expose a Webhook endpoint on our app.

Screen-Shot-2019-01-09-at-12.30.04-AM

Webhook Endpoint

Facebook expects an endpoint in your system where messages will be posted. But prior to posting messages, facebook makes a GET call to the same api to verify the access token. Remember, above we Verify Token, put some random string in your .env file for now.

# Any secret to be kept

APP_SECRET='<Your App Secret>'
ACCESS_TOKEN='Access Token Copied from Your FB Page'
VERIFY_TOKEN='my random string'

We will leave this for now, and get started with our code. This project will be built in TypeScript. To those who have little to no idea about TypeScript, can read here. Here are the following things need to be present -

nodejs
npm
typescript
express

Obviously we have done npm install, so I assume all these things are available. Here is how our folder structure will be -

Screen-Shot-2019-01-09-at-12.26.48-AM-1

As simple as it can get, here is the code for our bot.

"use strict";
import express from "express";
const router = express.Router()
import logger from "../util/logger";
import BootBot from 'bootbot';
import {Payload} from "../types/payloadTypes";
import {Chat} from "../types/chatTypes";
import {helpFunc} from "../modules/help";
import {genreFunc} from "../modules/genre";
import {greetFunc} from "../modules/greet";

const bot = new BootBot({
    accessToken: process.env.ACCESS_TOKEN,
    verifyToken: process.env.VERIFY_TOKEN,
    appSecret: process.env.APP_SECRET
});

/**
 * Define Home page route
 * Not using this here though
 */
router.get('/', function (_req, res) {
    res.send('Thanks for Checking Us Out');
});

/**
 * This will get triggered as and when any one
 * opens the chat window for the first time
 */
bot.setGreetingText("Hello, Welcome to XYZ Page. Lets start by knowing your favorite genre.");

/**
 * Log the message we receive.
 * All the message with type `message`
 * will appear in this function
 */
bot.on('message', (payload : Payload, _chat : Chat) => {
    logger.info({"module": "Api Controller", "message": payload.message.text, "details": payload});
});

/**
 * Log the Attachment message we receive.
 * All the message with type `Attachment message`
 * will appear in this function
 */
bot.on('attachment', (payload : Payload, chat : Chat) => {
    logger.info({"module": "Api Controller", "message": "Recieved Attachment", "details": payload});
    chat.say('We do not support this message type');
});

/**
 * Assign Bot Modules
 */
bot.module(greetFunc);
bot.module(helpFunc);
bot.module(genreFunc);

/**
 * Start the Bot
 */
bot.start(process.env.BOTPORT);

export default router;

To explain, FB supports several different types of messages, for example - Normal Message, Greeting Text, Quick Reply, Options etc , so instead of creating the structure of each of those, we are using a library named bootbot. This library has a pretty neat interface to define what type of message to be sent. Note, for instantiating an instance of bootbot, we are passing all the necessary client details to it at the top.

Let me put up the greetFunc module as well, to give more context on how a message is programmed.

import {Payload} from "../types/payloadTypes";
import {Chat} from "../types/chatTypes";
import logger from "../util/logger";

export const greetFunc = (bot : any) => {

    bot.hear(['hello', 'sup', /hey( there)?/i], (payload : Payload, chat : Chat) => {
        logger.info({"module": "Api Controller", "message": payload.message.text, "details": chat});
        chat.say('Hello, human friend!').then(() => {
            chat.say('Please say genre to get the list of genres to search from', { typing: true });
        });
    });

    bot.hear([/(good)?bye/i, /see (ya|you)/i, 'adios', 'get lost', 'thankyou'], (_payload : Payload, chat : Chat) => {
        chat.say('Bye, human!');
    });

};

All we are doing is defining a set of array with possible values and as soon as a visitor sends any of these values, we respond back with the defined message.

Assuming, that now its pretty staright forward code, lets come back to the webhook verification part. First, lets follow the following steps -

npm build
npm run
./ngrok http 3000

Note, we are starting our app in port 8080, but are forwarding port 3000 as bootbot creates a subserver which by default utilizes port 3000.
Now, go back to Facebook Developer Webhook page, select Create Subscription, enter the ngrok or localtunnel or forward url, paste the secret string defined above and hit verify. Once facebook is able to hit the endpoint, it will send a challenge which will be verified against your app secret.

Thats it, we are pretty much done. You can start the conversation with the bot.

As part of extension, you can use some sort of Database to store the User and probably the received messages, run some analytics to improve the bot responses. This has a very different challenge, but I leave that to you to determine.

Here is the source code again {Github Link}

Feel free to contact for any suggestion - dev[at]prashantb[dot]me