Training material of Facebook Messenger Bot and Facebook Analytics for Facebook Masterclass Training. Facebook Masterclass Training is official workshop training provided by Facebook.
This repo is a revision of prayudiutomo/Messenger-Bot-Ngrok-Tutorial
- NodeJS
- Facebook Page
- Facebook App
- Webhook Service
- Ngrok
a. Download and install NodeJS from official website: https://nodejs.org/.
b. Check version.
node -v
c. Install latest npm
npm install npm -g
d. Create directory anywhere
mkdir myBot
cd myBot
npm init
e. Install Express is for the server, request is for sending out messages and body-parser is to process messages
npm install express request body-parser --save
a. Download and install Ngrok from official website: https://ngrok.com/
b. Unzip from a terminal to any directory. On Windows, just double click ngrok.zip.
unzip /path/to/ngrok.zip
c. Start the ngrok
ngrok http 5000
'use strict'
const express = require('express')
const bodyParser = require('body-parser')
const request = require('request')
const app = express()
app.set('port', (process.env.PORT || 5000))
// Process application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({extended: false}))
// Process application/json
app.use(bodyParser.json())
// Index route
app.get('/', function (req, res) {
res.send('Hello world, I am a chat bot')
})
// for Facebook verification
app.get('/webhook/', function (req, res) {
if (req.query['hub.verify_token'] === 'make_indonesian_great_again') {
res.send(req.query['hub.challenge'])
}
res.send('Error, wrong token')
})
// Spin up the server
app.listen(app.get('port'), function() {
console.log('running on port', app.get('port'))
})
node index.js
a. Click https://www.facebook.com/pages/create
a. Click https://developers.facebook.com/apps/
b. Add Product Facebook Messenger
c. Test connection
curl -X POST "https://graph.facebook.com/v2.6/me/subscribed_apps?access_token=PAGE_ACCESS_TOKEN"
a. Click Messenger - Settings
b. Click Setup Webhooks
c. Add URL from ngrok
https://blabla.ngrok.io
https://blabla.ngrok.io/webhook
const token = "<PAGE_ACCESS_TOKEN>"
app.post('/webhook/', function (req, res) {
let messaging_events = req.body.entry[0].messaging
for (let i = 0; i < messaging_events.length; i++) {
let event = req.body.entry[0].messaging[i]
let sender = event.sender.id
if (event.message && event.message.text) {
let text = event.message.text
sendTextMessage(sender, "Text received, echo: " + text.substring(0, 200))
}
}
res.sendStatus(200)
})
function sendTextMessage(sender, text) {
let messageData = { text:text }
request({
url: 'https://graph.facebook.com/v2.6/me/messages',
qs: {access_token:token},
method: 'POST',
json: {
recipient: {id:sender},
message: messageData,
}
}, function(error, response, body) {
if (error) {
console.log('Error sending messages: ', error)
} else if (response.body.error) {
console.log('Error: ', response.body.error)
}
})
}
a. Add crypto library
const crypto = require('crypto')
b. Add APP Secret
const AppSecret = 'APP_YOUR_SECRET';
c. Check first
app.use(bodyParser.json({verify: verifyRequestSignature}))
d. Add function to verify
function verifyRequestSignature(req, res, buf){
let signature = req.headers["x-hub-signature"];
if(!signature){
console.error('You dont have signature')
} else {
let element = signature.split('=')
let method = element[0]
let signatureHash = element[1]
let expectedHash = crypto.createHmac('sha1', AppSecret).update(buf).digest('hex')
console.log('signatureHash = ', signatureHash)
console.log('expectedHash = ', expectedHash)
if(signatureHash != expectedHash){
console.error('signature invalid, send message to email or save as log')
}
}
}
app.post('/webhook/', function (req, res) {
let data = req.body
if(data.object == 'page'){
data.entry.forEach(function(pageEntry) {
pageEntry.messaging.forEach(function(messagingEvent) {
if(messagingEvent.message.text){
sendTextMessage(messagingEvent.sender.id,messagingEvent.message.text);
} else {
sendTextMessage(messagingEvent.sender.id,'Service Belum Support Untuk Mendeteksi Hal ini');
}
});
});
res.sendStatus(200)
}
})
function sendTextMessage(sender, text) {
let url = `https://graph.facebook.com/v2.6/${sender}?fields=first_name,last_name,profile_pic&access_token=${token}`;
request(url, function (error, response, body) {
if (!error && response.statusCode == 200) {
let parseData = JSON.parse(body);
let messageData = {
text: `Hi ${parseData.first_name} ${parseData.last_name}, you send message : ${text}`
}
request({
url: 'https://graph.facebook.com/v2.10/me/messages',
qs: {
access_token: token
},
method: 'POST',
json: {
recipient: {
id: sender
},
message: messageData,
}
}, function (error, response, body) {
if (error) {
console.log('Error sending messages: ', error)
} else if (response.body.error) {
console.log('Error: ', response.body.error)
}
})
}
})
}
app.post('/webhook/', function (req, res) {
let data = req.body
if(data.object == 'page'){
data.entry.forEach(function(pageEntry) {
pageEntry.messaging.forEach(function(messagingEvent) {
console.log(messagingEvent)
if(messagingEvent.message.text.indexOf('?') > 0){
var randInt = Math.floor(Math.random() * (1 - 0 + 1)) + 0;
var strPost = 'Ya';
if(randInt === 0) strPost = 'Tidak';
sendTextMessage(messagingEvent.sender.id, strPost);
} else {
sendTextMessage(messagingEvent.sender.id, 'Maaf saya hanya bisa menjawab pertanyaan yang dimulai dengan kata apakah dan diakhiri dengan tanda tanya. Contoh: Apakah saya jago ?');
}
});
});
res.sendStatus(200)
}
})
curl -X POST -H "Content-Type: application/json" -d '{
"greeting": [
{
"locale":"default",
"text":"Hello!"
}, {
"locale":"en_US",
"text":"Hello you there"
}, {
"locale":"id_ID",
"text":"Halo Apakabar ?"
}
]
}' "https://graph.facebook.com/v2.6/me/messenger_profile?access_token=<PAGE_ACCESS_TOKEN>"
- Options button
function sendOptionsButton(sender) {
let messageData = {
text: 'Kamu suka film apa',
"quick_replies": [
{
"content_type":"text",
"title":"Drama Romantis",
"payload":"DRAMA"
},
{
"content_type":"text",
"title":"Aksi",
"payload":"AKSI"
},
{
"content_type":"text",
"title":"Humor",
"payload":"HUMOR"
},
{
"content_type":"text",
"title":"Lainnya",
"payload":"LAINNYA"
},
]
}
sendMessage(sender, messageData)
}
function sendMessage(sender, message) {
let url = `https://graph.facebook.com/v2.6/${sender}?fields=first_name,last_name,profile_pic&access_token=${token}`;
request(url, function (error, response, body) {
if (!error && response.statusCode == 200) {
let parseData = JSON.parse(body);
request({
url: 'https://graph.facebook.com/v2.10/me/messages',
qs: {
access_token: token
},
method: 'POST',
json: {
recipient: {
id: sender
},
message: message,
}
}, function (error, response, body) {
if (error) {
console.log('Error sending messages: ', error)
} else if (response.body.error) {
console.log('Error: ', response.body.error)
}
})
}
})
}
function sendTextMessage(sender, text) {
let messageData = {
text: text
}
sendMessage(sender, messageData);
}
function replyAnswerMovie(text) {
if(text === 'DRAMA') {
return 'Berarti anda suka AADC dong'
} else if(text === 'AKSI') {
return 'Film-film nya Bruce Willis asik tuh buat kamu'
} else if(text === 'HUMOR') {
return 'Warkop udah nonton belum ?'
} else if(text === 'LAINNYA') {
return 'Cintailah Film Indonesia'
} else {
return null
}
}
app.post('/webhook/', function (req, res) {
let data = req.body
if(data.object == 'page'){
data.entry.forEach(function(pageEntry) {
pageEntry.messaging.forEach(function(messagingEvent) {
console.log(messagingEvent)
if(messagingEvent.message.attachments &&
messagingEvent.message.attachments[0].type == 'location') {
sendTextMessage(messagingEvent.sender.id, 'Lokasi kamu: '+messagingEvent.message.attachments[0].url);
return;
}
if(messagingEvent.message.quick_reply) {
const replyMovie = replyAnswerMovie(messagingEvent.message.quick_reply.payload)
console.log('replyMovie', replyMovie)
if(replyMovie !== null) {
sendTextMessage(messagingEvent.sender.id, replyMovie);
return;
}
}
if(messagingEvent.message.text.indexOf('?') > 0){
var randInt = Math.floor(Math.random() * (1 - 0 + 1)) + 0;
var strPost = 'Ya';
if(randInt === 0) strPost = 'Tidak';
sendTextMessage(messagingEvent.sender.id, strPost);
} else if(messagingEvent.message.text.toLowerCase().indexOf('opsi') >= 0){
sendOptionsButton(messagingEvent.sender.id)
} else {
sendTextMessage(messagingEvent.sender.id, 'Maaf saya hanya bisa menjawab pertanyaan yang dimulai dengan kata apakah dan diakhiri dengan tanda tanya. Contoh: Apakah saya jago ?');
}
});
});
res.sendStatus(200)
}
})
- location
function sendLocationOption(sender) {
let messageData = {
text: 'Please Share your location',
"quick_replies": [
{
"content_type":"location"
},
]
}
sendMessage(sender, messageData)
}
else if(messagingEvent.message.text.toLowerCase().indexOf('location') >= 0){
sendLocationOption(messagingEvent.sender.id)
}