Tutorial: Using the Messenger Webview to create richer bot-to-user interactions


  • Whitelist the domains that serve your webview.
  • Handle incoming messages.
  • Create a URL button that calls a webview.
  • Create a webview.
  • Use the Messenger Extensions SDK to access platform features in your webview.
  • Create an alternative webview that doesn’t use the Messenger Extensions SDK.
  • Process data from the webview.

What you need

Messenger Features

  • Webhook: The Messenger Platform sends events to your webhook to notify your bot when interactions or events happen.
  • Webview: Allows you to open a standard webview, where you can load web pages inside Messenger and offer an experience that is harder with standard Messenger features.
  • A URL Button: Allows you to open a web page in Messenger.
  • The Messenger Extensions SDK: Brings Messenger-specific features to any website or web app opened in the Messenger webview.


  • Complete the general set up:
  • Facebook Page created: Used as the identity of your bot.
  • Facebook for Developers account: Required to create new apps, which are the core of any Facebook integration.
  • Webhook setup: The Messenger Platform sends events to your webhook to notify your bot when a variety of interactions or events happen, including when a person sends a message.
  • Facebook app setup: contains the settings for your Messenger bot, including access tokens.
  • Build a bot for Messenger. You can do so quickly using the Quick Start guide.
  • Have a server with Node.js installed.

Repository with working code

What does it look like?

The bot overview

How does it work? Step-by-step

STEP 1: Download the starter project

STEP 2: Install dependencies

  • Express to set up a web server for the webhook.
  • body-parser to parse the JSON body of the incoming POST requests.
  • request to send HTTP requests to the Messenger Platform.
  • dotenv to make setting environment variables easier.
npm install

STEP 3: Whitelist domains

curl -X POST -H "Content-Type: application/json" -d '{
}' "https://graph.facebook.com/v2.6/me/messenger_profile?access_token=<PAGE_ACCESS_TOKEN>"

STEP 4: Handle incoming messages

let response;if (received_message.text) {
// Code to follow
} else {
response = {
"text": `Sorry, I don't understand what you mean.`
callSendAPI(sender_psid, response);
if (received_message.text) {
switch (received_message.text.replace(/[^\w\s]/gi, '').trim().toLowerCase()) {
case "room preferences":
response = setRoomPreferences(sender_psid);
response = {
"text": `You sent the message: "${received_message.text}".`
} else {
response = {
"text": `Sorry, I don't understand what you mean.`

STEP 5: Display the URL button

let response = {
attachment: {
type: "template",
payload: {
template_type: "button",
text: "OK, let's set your room preferences so I won't need to ask for them in the future.",
buttons: [{
type: "web_url",
url: SERVER_URL + "/options",
title: "Set preferences",
webview_height_ratio: "compact",
messenger_extensions: false
return response;
Webview size presets

STEP 6: Create the webview page

<form action="/optionspostback" method="get">
<input type="hidden" name="psid" id="psid">
<input type="radio" name="pillows" value="soft" checked>Soft<br>
<input type="radio" name="pillows" value="hard">Hard<br>
<input type="radio" name="bed" value="single" checked>Single<br>
<input type="radio" name="bed" value="double">Double<br>
<input type="radio" name="bed" value="twin">Twin<br>
<input type="radio" name="view" value="sea" checked>Sea<br>
<input type="radio" name="view" value="street">Street<br>
<input type="submit" value="Submit" id="submitButton">

STEP 7: Initialize the SDK

(function (d, s, id) {
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) {
js = d.createElement(s);
js.id = id;
js.src = "//connect.facebook.com/en_US/messenger.Extensions.js";
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'Messenger'));
window.extAsyncInit = function () {
// SDK loaded, code to follow

STEP 8: Access SDK features

MessengerExtensions.getSupportedFeatures(function success(result) {
let features = result.supported_features;
if (features.indexOf("context") != -1) {
function success(thread_context) {
// success
document.getElementById("psid").value = thread_context.psid;
// More code to follow
function error(err) {
}, function error(err) {
document.getElementById('submitButton').addEventListener('click', function () {
MessengerExtensions.requestCloseBrowser(function success() {
console.log("Webview closing");
}, function error(err) {

STEP 9: Allow Messenger to serve the webview

app.get('/options', (req, res) => {});
let referer = req.get('Referer');
if (referer) {
if (referer.indexOf('www.messenger.com') >= 0) {
res.setHeader('X-Frame-Options', 'ALLOW-FROM https://www.messenger.com/');
} else if (referer.indexOf('www.facebook.com') >= 0) {
res.setHeader('X-Frame-Options', 'ALLOW-FROM https://www.facebook.com/');
res.sendFile('public/options.html', {root: __dirname});

STEP 10: Process the webview data

app.get('/optionspostback', (req, res) => {});
let body = req.query;
let response = {
"text": `Great, I will book you a ${body.bed} bed, with ${body.pillows} pillows and a ${body.view} view.`
res.status(200).send('Please close this window to return to the conversation thread.');
callSendAPI(body.psid, response);





I explain cool tech to the World. I am a Technical Writer and blogger. I have crazy projects in progress and will speak to anyone who listens.

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

COVID-19 India: Geo Plotting using Python

SAP HANA Cloud Data Security | Masking and Anonymization

Does code style matter?

Notes and a Summary on D. Stein’s “Implementing Lightweight Threads” paper.

Create Your First AWS Lambda Function with Java using Eclipse IDE

Try Hack Me-GameZone

Connect your Raspberry Pi with AWS IoT

KDE PLOT: Kernal Density Function

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Chris Chinchilla

Chris Chinchilla

I explain cool tech to the World. I am a Technical Writer and blogger. I have crazy projects in progress and will speak to anyone who listens.

More from Medium

Hoppscotch is celebrating 35,000 GitHub Stars

extending hyper — ->

Implementing Apple subscriptions on backend

Using Feedly, Pocket and IFTTT to Capture News Items