Facebook now has the Messenger Platform which allows us to build bots which can accept messages from users and respond to them. In this tutorial, we shall see how we can build a bot and add it to one of our pages so that the users can interact with the bot by sending messages to the page.
To get started, we have three requirements to fulfill:
- We need a Facebook Page
- We need a Facebook App
- We need a webhook / callback URL to accept incoming messages
I am assuming you already have a Facebook Page. If you don’t, go ahead and create one. It’s very simple.
Creating and Configuring The Facebook App
(1) First, we create a generic facebook app. We need to provide the name, namespace, category, contact email. Simple and straightforward. This is how it looks for me:
.
(2) Now we have to browse the “Add Product” section and add “Messenger”.
(3) Generate access token for a Page you manage. A popup will open asking you for permissions. Grant the permission and you will soon see the access token for that page. Please take a note of this token. We shall use it later send messages to the users on behalf of the page.
Next, click the “Webhooks” section.
(4) Before we can setup a webhook, we need to setup an URL which is publicly accessible on the internet. The URL must have SSL (that is it needs to be https). To meet this requirement and set up a local dev environment, we setup a quick flask app on our local machine.
Install Flask from PyPi using pip
:
1 |
pip install Flask |
Facebook will send a GET
request to the callback URL we provide. The request will contain a custom secret we can add (while setting up the webhook) and a challenge code from Facebook. They expect us to output the challenge code to verify ourselves. To do so, we write a quick GET
handler using Flask.
1 2 3 4 5 6 7 8 9 10 11 12 |
## Filename: server.py from flask import Flask, request app = Flask(__name__) @app.route('/', methods=['GET']) def handle_verification(): return request.args['hub.challenge'] if __name__ == '__main__': app.run(debug=True) |
We run the local server using python server.py
. The app will launch at port 5000 by default. Next we use ngrok
to expose the server to the internet. ngrok is a fantastic tool and you should seriously give it a try for running and debugging webhooks/callback urls on your local machine.
1 |
ngrok http 5000 |
With that command, we will get an address like https://ac433506.ngrok.io
. Copy that url and paste it in the Webhook setup popup. Checkmark the events we’re interested in. I check them all. Then we input a secret, which our code doesn’t care about much. So just add anything you like. The popup now looks like this:
Click “Verify and Save”. If the verification succeeds, the popup will close and you will be back to the previous screen.
Select a Page again and click “Subscribe”. Now our app should be added to the page we selected. Please note, if we haven’t generated an access token for that page in the earlier step, the subscription will fail. So make sure we have an access token generated for that page.
Handling Messages
Now every time someone sends a message to the “Masnun” page, Facebook will make a POST
request to our callback url. So we need to write a POST
handler for that url. We also need respond back to the user using the Graph API. For that we would need to use the awesome requests
module.
1 |
pip install requests |
Here’s the code for accepting incoming messages and sending them a reply:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
from flask import Flask, request import requests app = Flask(__name__) ACCESS_TOKEN = "EAAP9MMaGh1cBAHS7jZCnuQgm2GWx5grLraIElFlWlIw2r3Afb34m2c2rP0xdkkkKEeiBOykGINAP0tScwmL5NNBJQN9ayPCuq13syvWocmbYZA7BXL86FsZCyZBxTmkgYYp8MDulLc1Tx70FGdU5ebQZAJV28nMkZD" def reply(user_id, msg): data = { "recipient": {"id": user_id}, "message": {"text": msg} } resp = requests.post("https://graph.facebook.com/v2.6/me/messages?access_token=" + ACCESS_TOKEN, json=data) print(resp.content) @app.route('/', methods=['POST']) def handle_incoming_messages(): data = request.json sender = data['entry'][0]['messaging'][0]['sender']['id'] message = data['entry'][0]['messaging'][0]['message']['text'] reply(sender, message[::-1]) return "ok" if __name__ == '__main__': app.run(debug=True) |
The code here accepts a message, retrieves the user id and the message content. It reverses the message and sends back to the user. For this we use the ACCESS_TOKEN
we generated before hand. The incoming request must be responded with a status code 200 to acknowledge the message. Otherwise Facebook will try the message a few more times and then disable the webhook. So sending a http status code 200 is important. We just output “ok” to do so.
You can now send a message to your page and see if it responds correctly. Check out Flask’s and ngrok’s logs to debug any issues you might face.
You can download the sample code from here: https://github.com/masnun/fb-bot
33 replies on “Building a Facebook Messenger Bot with Python”
Is there a way to just do it with a straight python module? I did one to telegram and only needed the telegram module, no need to generate a webserver or a routing mechanism. Only add the token and the channel for it.
Wonder why I would need django, web.py or flask to do a response callback.
It’s how they designed it to be. Whether you use a web server or not, you need to keep a program running anyway. So I see not much difference anyway.
[…] tried to perform other steps from instruction (and also looked here: https://masnun.com/2016/05/22/building-a-facebook-messenger-bot-with-python.html, where is nothing said about the review too), filling Facebook Page Id, App Id, Secret, Access […]
Hello, I tried this out. Everything went well until I test messaging. FB doesn’t call my POST url back. Any ideas?
Sorry no idea. There could be a lot of reasons. If you entered the url correctly, I am pretty sure Facebook sends a POST request.
Masnun,
thank you for this useful tutorial!
But I have a question about ngrok and webhooks. After reloading the computer I launched ngrok again (./ngrok http 5000) and it generated a different address. Now I don’t know how to launch the previous address I used the first time while creating an app. And there is no way to change the webhook address in Facebook messenger settings…
Nadya
ngrok creates a new url everytime. It’s good for testing.
The webhook url needs to be updated in the app settings.
I have the same problem, can you please tell how to update the webhook url in the app settings?
Did you add the “Messenger” product? Go to it’s settings. You should find the webhook section there.
Yes, I did but it didn’t add the webhook section automatically on the left. Now I fixed the problem but only thanks to a mail that I received because of inactivity of the server. In the mail I found the link to add the webhook section. Thank you anyway!
I have the same problem,doesn’t accept me the webhook address?
This works perfectly !
Thank you very much! 🙂
I have the same problem,doesn’t accept me the webhook address? Plz after I have to browse the “Add Product” section and add “Messenger”,what I must do exactly after ?
Not sure why, but the bot works only on the first message. I get the echoed message reverse but after that it seems to crash. Ngrok just shows “500 internal server error”. Any ideas on how to fix this? Great Tutorial by the way.
Please check the error logs in the Flask app.
I have a similar problem.
POST / 500 INTERNAL SERVER ERROR
Perhaps the error is somewhere here:
in handle_incoming_messages
message = data[‘entry’][0][‘messaging’][0][‘message’][‘text’]
KeyError: ‘message’
May be Facebook changed the parameters they used to POST to the endpoint. You can try to
pprint
thedata
variable and explore what params they send.I also got the same error, when I print the data object ,it doesn’t have the message in the object.
{u’entry’: [{u’messaging’: [{u’delivery’: {u’mids’: [u’mid.1470729876873:428e78899337c4cd56′], u’seq’: 79, u’watermark’: 1470729876884}, u’timestamp’: 0, u’recipient’: {u’id’: u’595256117288792′}, u’sender’: {u’id’: u’1130129647025300′}}], u’id’: u’595256117288792′, u’time’: 1470730542889}], u’object’: u’page’}
I’ve run into this issue, too. The problem is that Facebook is sending a response to the successful POST request to send a message, and that message doesn’t have the same the same JSON body as the initial message we’re replying to. Namely, the [‘message’] object is absent.
I’m new to programming, but I’m working on how to handle this. When I figure it out, I’ll post an update here.
This solution might be kind of hacky, but I found something that works.
If you compare the JSON body of the Facebook’s initial message post to their send request confirmation post, you’ll see that one reliable difference between them is that the “Timestamp” object has a 0 value in the confirmation.
So I added an IF statement to check if the “Timestamp” value is more than 0 to tell the two incoming posts apart:
inbound_check = data[‘entry’][0][‘messaging’][0][‘timestamp’]
if inbound_check > 0:
Then proceed with normal message parsing and sending.
Else:
return “200”
I’m guessing there are more elegant ways of doing this, but as I said, I’m new to programming.
Cheers
How can i send messages with that?
I havent run the program yet, but I guess you’d just have to call the reply function(given you have the recipients ID).
Hi,
Superb Tutorial – Everything worked fine and I was able to send messages correctly until a few weeks ago.
It still the same code, I’m still correctly the GET to verify the Webhook but then I’m not receiving any incoming messages from FB anymore 🙁
Is anybody having the same issue. I’m not sure what to check more…
Thanks.
Florian
Dear
Based on your expertise in coding BOT on Facebook Messenger,
I wondered if you could be so kind as to give me a few minutes to help me with a problem.
I am trying to set-up the START button to launch the conversation,
I tried all the given methods on the documentation, but it fails.
Have you ever encountered this problem?
Best regards,
Where it could be wrong?
POST / 405 METHOD NOT ALLOWED
Error in code?
POST / 405 METHOD NOT ALLOWED
Appears in ngrok cmd.
What could I do?
Hello. I am not clear where are we supposed to execute the python code? Is it in the python idle itself?
Hey.. I m a student and have to made fb messenger bot using python and flask but with api.ai in my fyp..Can you gave me a sample code which include api.ai along with python..M grateful to you..Thnx
[…] blog entry obtained a lot of help from Masnun’s blog post, which uses Python and ngrok for setting up an echo […]
Thankyou bhai jee
As I understand, ngrok needs only during adding the webhook or it must be enabled every time when I start the bot from my local PC?
Every time you want to use it from your local PC.