With this example channel connector for Facebook Messenger you can make your Teneo bot available on Facebook Messenger. This guide will take you through the steps of installing the connector and connecting it to a business page on Facebook.
You can find the source code of this connector here: TeneoFBconnector.zip.
These instructions assume your Teneo solution is published and that you know the Engine URL. Further you need a web container running on a JVM version 11 or higher and compatible with Jakarta EE 9.1 Web Profile (e.g. Tomcat v.10, WildFly v.23, GlassFish v.6) such that web applications installed therein are able to send HTTPS POST requests to the published Teneo engine and receive HTTPS POST requests from the Facebook Messenger Platform via its webhooks. Besides that, you need one or several Facebook business pages with a Facebook Messenger available there.
The description of the software
The goal of this Teneo Facebook Messenger Connector is to connect Facebook Messenger to a Teneo-built Virtual Assistant (VA) so that Facebook Messenger acts as a frontend to the Teneo engine (the VA backend). In this way, visitors to a Facebook page (users) can chat via Facebook Messenger with a Teneo engine instead of with a real person. The connector was developed and tested with the version 13.0 of the Facebook Graph API and makes use of Webhooks and Send API of the Facebook Messenger Platform. It should also work with newer versions of Facebook Graph API as long as they are backwards compatible with the target version.
Teneo Facebook Messenger Connector is a Java web application. It can be deployed in any Java web container running on a JVM version 11 or higher and compatible with Jakarta EE 9.1 Web Profile (e.g. Tomcat v.10, WildFly v.23, GlassFish v.6). It should be deployed so it is able to send HTTPS POST requests to the published Teneo engine and receive HTTPS POST requests from the Facebook Messenger Platform via its webhooks.
One instance of this connector can serve multiple Facebook business pages and multiple users on each page talking to one Teneo engine instance simultaneously.
When a user opens Facebook Messenger on a given Facebook page, the user is assigned a page-scoped ID (PSID) which is unique for the given user on the given page. The user is then identified by this PSID during his/her interactions with the messenger so this PSID is present in the webhook requests triggered by the user's actions (submitting an input, clicking a button etc) and can be used to display messages to the user via Send API. The connector itself uses this PSID as a session identifier. The connector has its own internal session management mechanism instead of the one provided by the Java web container. This is motivated by the specifics of the Facebook Messenger webhook implementation which is not directly compatible with any of the typical Java web app session identification mechanisms such as e.g. session cookies and URL rewriting.
When the user submits a message via Facebook Messenger connected to a Teneo engine, Facebook Messenger's webhook sends a POST request to the connector. This request contains the user's PSID and the submitted message itself, among other information. The connector receives this request via its webhook servlet,
com.artificialsolutions.asolfbconnector.webapp.servlets.Webhook, and parses it to "understand" what kind fo webhook sent the data. In this version of the connector,
messaging_postbacks are the only ones implemented. If you want to process more webhooks, you should add the corresponding logic in
com.artificialsolutions.asolfbconnector.webapp.servlets.Webhook.doPost(). If the webhook has been parsed successfully, the connector invokes the singleton instance of the Facebook-Teneo bridge,
com.artificialsolutions.asolfbconnector.bridge.FacebookTeneoBridge, which handles the custom sessions including their timeout. The connector creates a new (or grabs an existing) session identified via the user's PSID.
The functioning of the connector is illustrated in the following functional diagram:
The sequence of the steps depicted in the diagram is as follows:
The user submits his/her message into Facebook Messenger on a customer's page.
A POST request with the user's message and PSID is sent to the connector via Facebook Messenger webhook. The connector receives the request with its Webhook servlet (an instance of
com.artificialsolutions.asolfbconnector.webapp.servlets.Webhook) and checks via its singleton Facebook-Teneo bridge object (an instance of
com.artificialsolutions.asolfbconnector.bridge.FacebookTeneoBridge) if there already exists a session (an instance of
com.artificialsolutions.asolfbconnector.bridge.FacebookTeneoBridge.Session) identified via this PSID. If no such session exists, it is created and its timeout countdown is started. If it already exists, it is returned and its timeout countdown is restarted. Each session object has its own instance of Teneo engine client (
com.artificialsolutions.asolfbconnector.teneoengine.TeneoEngineClient) to talk to the Teneo engine and its own instance of Facebook Send API client (
com.artificialsolutions.asolfbconnector.facebook.FacebookMessagingClient) to send messages from the connector to the user's Facebook Messenger.
The Teneo engine client forwards the user's message to the Teneo engine with a POST request.
The Teneo engine client receives Virtual Assistant's answer in the response.
Virtual Assistant's answer is passed over to the Facebook Send API client.
The Facebook Send API client sends Virtual Assistant's answer with the user's PSID to the user's Facebook Messenger.
The answer is displayed to the user.
The application data, including its sessions, is fully serializable. Serialization and deserialization within the application is compatible with session timeouts so the pause between serialization and subsequent deserialization is taken into account to adjust the session timeout.
Configuring the connector
It is possible to have several different webapp configurations for different packaging/compilation profiles. By default, this project is supplied with the predefined packaging profiles
production specified in the
pom.xml file. Feel free to add new profiles or edit existing ones. Each profile contains the
META-INF folder, the log configuration file
log4j2.properties and the configuration reference file
META-INF folder and the log configuration file are common ones for this kind of applications. The configuration reference file is specific to this particular webapp. It contains one single property,
configFile, which points to the properties file containing the actual webapp configuration. In production this webapp configuration file should ideally be stored separately from the webapp itself, i.e. outside of its
.war file, although it is also possible to have it inside of it. The following configuration properties are implemented.
teneo.engine.endpointUrl- the Teneo engine endpoint (the URL of the virtual assistant backend)
facebook.webhook.verificationToken- any string you will use for the token verification in Facebook
facebook.application.appSecret- the app secret to perform the security verification. Leave the value of this property empty if you want to switch this verification off.
facebook.pageIdToAccessToken- a JSON-formatted mapping where the keys are the IDs of the Facebook business pages where Facebook Messenger is supposed to be connected to Virtual Assistant and the values are the page access tokens of the corresponding pages. It's up to you to find the IDs of your pages and to generate the corresponding page access tokens. Please refer to the Facebook documentation for more information.
teneo.engine.connectTimeoutMillis- the timeout to connect with Teneo engine, in milliseconds
teneo.engine.responseTimeoutMillis- the timeout to wait for Teneo engine responses, in milliseconds
facebook.messaging.connectTimeoutMilli- the timeout to connect with Facebook Send API, in milliseconds
facebook.messaging.responseTimeoutMillis- the timeout to wait for responses from Facebook Send API, in milliseconds
bridge.sessionTimeoutMillis- the timeout for the sessions created by Teneo Facebook bridge, in milliseconds; it is recommendable to have it slightly longer then the session timeout of Teneo engine, which is normally 10 minutes (600 seconds, 600000 milliseconds), in millisecond
bridge.maxParallelSessions- the maximum number of simultaneous sessions for the Teneo Facebook bridge; this number can be kept high (tens of thousands), although not too high since its purpose is to reduce the risk or the application running out of memory if the number of session increases too much
application.explicitData- the Boolean value indicating if some error and debug information should be added to requests sent both to Teneo engine and to Facebook Messenger. This property is not obligatory and defaults to
false. It should only be set to
truefor testing and troubleshooting
An example configuration file
asolfbconnector.properties is supplied with this webapp.
Compiling the connector
The compilation and packaging goals for development :
clean compile package -Pdevxxx javadoc:javadoc cargo:run
In this case, the compiled webapp is deployed on a special embedded Tomcat via the Cargo Maven plugin. It allows you to run and test the application straight away. In the folder
target/site/apidocs it will generate the javadoc of the application.
The compilation and packaging goals for production :
clean compile package -Pproduction
Regarding the logger configuration, in order to test the application it is highly recommended to have it on the
trace level. If you have it on those sensitivity levels, it might log some PII, like user PSIDs, user inputs etc. Thus it should be set to have less sensitivity in production (
warn for example).
In Facebook developers create an application as "Messenger", configure its endpoint as
[yourAsolfbconnectorURL]/webhook (i.e., the endpoint of your hosted
asolfbconnector connector webapp plus the
/webhook path) and subscribe it for
messaging_postbacks webhooks. When you configure the "Messenger" part, you will have a chance to get the application's app secret to be used in the
facebook.application.appSecret property and generate the page access token, which you will need to configure the
facebook.pageIdToAccessToken property of your connector webapp.
Teneo Solution configuration
Data received by Teneo engine from Connector
The current version of the Teneo Facebook Connector processes requests from the "messages" and "messaging_postbacks" webhooks of the Facebook Messaging platform and passes them over to Teneo engine as HTTPS POST requests. These requests contain the following parameters:
businessPageId, value: the ID of the Facebook business page (basing on this ID you will know which page the Teneo Engine is accessed from)
userPsid, value: the current user's PSID (this parameter is only added if the
application.explicitDataproperty in the configuration files is set to
Additionally they can also contain the following request parameter:
referral, value as a stringified JSON object: referral of the message from shops product details page for
messagesrequests and referral information for how the user got into the thread for
messages request received by Teneo engine may also contain the following request parameters:
userinput, value: the actual user input
attachments, value as a stringified JSON object: an array containing attachment data (if the user tried to upload an image to the Teneo engine, for example)
quick_reply.payload: the payload (a string) of the quick reply the user clicked
asStandby: this parameter will be received with the value
trueif the message has been submitted as a standby.
messaging_postbacks request received by Teneo Engine contains the following request parameter:
It may also contain the following parameters:
payload, value: the postback payload (a string)
title, value: the postback title (a string)
Data returned by Teneo engine (Teneo solution) to Connector
Teneo engine normally returns a text as its answer. This text is then displayed in Facebook Messenger to the user. If content other than simple text should be returned, e.g. buttons, templates etc, this content should be placed in the output parameter
facebookMessage. It should be a well formed stringified JSON representing a value of Facebook's
message property as per Send API Message.