Run Node.js Facebook Messenger Chat Bot on AWS Lambda

Igor Khomenko
Dev Tutorials
Published in
7 min readMay 6, 2016

--

AWS Lambda

UPD: This guide has been updated on April 23, 2017, after the latest AWS/Facebook updates.

Facebook announced its Messenger Platform for Chat Bots — new tools to help you build your bot and reach 900 million(UPD: now it’s 1.2B) people around the world. That guide shows how to build a chat bot and integrate it with Facebook Messenger platform.

One thing the Facebook team omits is hosting for your bots. It’s up to you where to host your chat bots.

There is a cool page from Slack — https://api.slack.com/docs/hosting. They have a hub page with hosting details, what platforms can be used as home for chat bots. I hope each Chat Bots platform will have similar page because it’s super cool and easy to start.

Because I like AWS for their simplicity and powerful set of features we will show how to deploy Facebook Messenger Chat Bot on AWS Lambda. So let’s start!

First of all we need to create an AWS Lambda function. Go to AWS console -> Lambda service -> New function.

Here you need to select a blueprint. Blueprints are sample configurations of event sources and Lambda functions. Choose a blueprint that best aligns with your desired scenario and customize as needed. We will use the hello-world blueprint — it’s a starter node.js function:

Select a blueprint for your AWS Lambda function

Next — we will skip ‘Configure triggers’ section for now and return to it later, so just press on ‘Next’ button.

Next — configure your function:

AWS Lambda — Configure function

set the following fields:

  • Name: a name of your function, for example processMessages
  • Description: leave as is, not important at this stage
  • Runtime: leave as is (nodejs)
  • Lambda function code: leave as is (index.handler)
  • Handler: leave as is, not important at this stage
  • Role: create a basic execution role and set it

Other settings (Tags, Advanced settings) — leave as is, not important at this stage.

Then click on Next button, review your settings on next screen and click on Create function to finalise it. You should see something like this:

Your 1st Lambda function

To test your first function you can press on blue Test button, set your test input (you can leave it as is) and run your 1st test. You should get the following result:

Test your function

Alright, next you need to add a trigger that will invoke your function. Your function will receive messages from Facebook Messenger via this trigger.

Go to Triggers tab and click on Add trigger link:

Add trigger

and then choose API Gateway as trigger type:

Choose API Gateway as trigger type

On next screen you need to set the following fields:

  • API name: name of your API endpoint, e.g. ‘LambdaMicroservice’
  • Deployment stage: the name of your deployment stage, e.g. ‘prod’
  • Security: Open
Add API endpoint

then click on Submit and get your API endpoint ready to use:

API Gateway URL

Congratulations! We have finished with Lambda setup!

You need to save somewhere API Gateway URL. We will need to enter it when setup Facebook Messenger app later.

Next step — Facebook Messenger settings.

Next step is to Create a Facebook App and Facebook Page. Follow the Getting Started guide to do that.

The most interesting part in that guide is a step N2: Setup Webhook. Here we need to connect Facebook App with our Lambda function. You should set the following fields:

  • Callback URL: you need to copy you API Gateway endpoint URL from Lambda (from ‘Triggers’ tab)
  • Verify token: set some value, will explain why you need it later.
  • Subscription fields: select all
copy API Gateway URL

Now lets explain what is Verify token and how to verify and save these settings.

As Facebook explains, at your webhook URL, add code for verification. Your code should look for the Verify Token and respond with the challenge sent in the verification request.

So we need to write some code in our Lambda function to verify our webhook. Facebook provides some examples in its guide (using Express), but we don’t want to bother with all these 3rd party things and will use vanilla AWS Lambda Node.js environment.

Go to our Lambda function and write the following code and save it:

'use strict';var VERIFY_TOKEN = "my_awesome_token";exports.handler = (event, context, callback) => {

// process GET request
if(event.queryStringParameters){
var queryParams = event.queryStringParameters;

var rVerifyToken = queryParams['hub.verify_token']

if (rVerifyToken === VERIFY_TOKEN) {
var challenge = queryParams['hub.challenge']

var response = {
'body': parseInt(challenge),
'statusCode': 200
};

callback(null, response);
}else{
var response = {
'body': 'Error, wrong validation token',
'statusCode': 422
};

callback(null, response);
}
}
}

Here you need to put your Verify token that you set on Facebook page above.

Now click on Verify and Save button on Facebook page and you should see a green ‘Complete’ mark:

Verify and save your webhook

Superb!

Next steps (3. Get a Page Access Token, 4. Subscribe the App to the Page) are easy to do so please follow Facebook guide to do it.

Now let’s allow our chat bot to receive messages from users and reply.

Now it’s time to allow our chat bot receive messages from users and reply.

Back to our Lambda function and write the following code and save it:

'use strict';var VERIFY_TOKEN = "my_awesome_token";var https = require('https');var PAGE_ACCESS_TOKEN = "EAF...DZD";exports.handler = (event, context, callback) => {

// process GET request
if(event.queryStringParameters){
var queryParams = event.queryStringParameters;

var rVerifyToken = queryParams['hub.verify_token']

if (rVerifyToken === VERIFY_TOKEN) {
var challenge = queryParams['hub.challenge']

var response = {
'body': parseInt(challenge),
'statusCode': 200
};

callback(null, response);
}else{
var response = {
'body': 'Error, wrong validation token',
'statusCode': 422
};

callback(null, response);
}

// process POST request
}else{
var data = JSON.parse(event.body);

// Make sure this is a page subscription
if (data.object === 'page') {
// Iterate over each entry - there may be multiple if batched
data.entry.forEach(function(entry) {
var pageID = entry.id;
var timeOfEvent = entry.time;
// Iterate over each messaging event
entry.messaging.forEach(function(msg) {
if (msg.message) {
receivedMessage(msg);
} else {
console.log("Webhook received unknown event: ", event);
}
});
});

}
// Assume all went well.
//
// You must send back a 200, within 20 seconds, to let us know
// you've successfully received the callback. Otherwise, the request
// will time out and we will keep trying to resend.
var response = {
'body': "ok",
'statusCode': 200
};

callback(null, response);
}
}
function receivedMessage(event) {
console.log("Message data: ", event.message);

var senderID = event.sender.id;
var recipientID = event.recipient.id;
var timeOfMessage = event.timestamp;
var message = event.message;
console.log("Received message for user %d and page %d at %d with message:", senderID, recipientID, timeOfMessage);
console.log(JSON.stringify(message));
var messageId = message.mid; var messageText = message.text;
var messageAttachments = message.attachments;
if (messageText) { // If we receive a text message, check to see if it matches a keyword
// and send back the example. Otherwise, just echo the text we received.
switch (messageText) {
case 'generic':
//sendGenericMessage(senderID);
break;
default:
sendTextMessage(senderID, messageText);
}
} else if (messageAttachments) {
sendTextMessage(senderID, "Message with attachment received");
}
}
function sendTextMessage(recipientId, messageText) {
var messageData = {
recipient: {
id: recipientId
},
message: {
text: messageText
}
};
callSendAPI(messageData);
}
function callSendAPI(messageData) {
var body = JSON.stringify(messageData);
var path = '/v2.6/me/messages?access_token=' + PAGE_ACCESS_TOKEN;
var options = {
host: "graph.facebook.com",
path: path,
method: 'POST',
headers: {'Content-Type': 'application/json'}
};
var callback = function(response) {
var str = ''
response.on('data', function (chunk) {
str += chunk;
});
response.on('end', function () {

});
}
var req = https.request(options, callback);
req.on('error', function(e) {
console.log('problem with request: '+ e);
});

req.write(body);
req.end();
}

This is the completed code of our chat bot. It just echoes a message it receives and nothing more. So you can start here and implement any logic you want — use this code as a carcass.

One thing you need to do to make it work is to set a PAGE_ACCESS_TOKEN value. Go to Facebook app console and copy it:

Page access token

Alright! Let’s test it!

Open our bot page, click on Send Message and send something:

Test our bot

Works like a charm!

There is also a possibility to track logs of your Lambda function.
Each console.log(“some text”) instruction will print a log into CloudWatch stream and you can easily check it to simplify your bot debugging:

CloudWatch logs
CloudWatch logs
CloudWatch logs

That’s all about AWS Lambda deployment. As you can see — it’s not super hard to host your chat bots on AWS Lambda.

Feel free to provide your feedback,

Cheers!

P.S. Need chat bots development? You can ping me at khomenkoigor@gmail.com

--

--

Software craftsman, RTC pro, love programming and clouds, XMPP, WebRTC, secure messaging, chat bots