WEB WIDGET CHAT BOT¶
The Web Widget Chat Bot allows integrating Teamwire as a chat widget into any web site. It is composed of the following main components:
- a chat bot (
web_widget_bot.py
), which provides the integration with the Teamwire platform - a web server component, integrated within the bot for serving the web widget files and providing an interface for commands received from the widget
- a main web component (in the
widget/src
directory), which provides the main chat UI - a JS script (in the
widget/widget-script
directory) capable of injecting into the target page a chat button and an iframe container for the chat ui
The source code of this bot is not part of the Teamwire SDK Bot Examples package, but it can be downloaded here:
Widget UI¶
The widget is implemented as an HTML page template (index.html
) plus some vanilla JS code
based on jQuery for DOM manipulation, and some basic CSS for styles.
The source code for the chat widget is contained in the widget/src
directory.
The page, JS and CSS are bundled together through Webpack and made available in
the widget/dist/bundles
directory.
In order to simplify the integration of the widget into any web site, a reference to the
widget/dist/widget-script.js
script should be used. Its source files are contained in the
widget/widget-script
directory.
Supposing the bot is running on a publicly accessible server, for
example at the url http://example.com/
, in order to integrate the widget in
your web page you simply have to add the following reference in your HTML:
<script src="http://example.com/widget-script.js?key=<site-key>"></script>
for example:
<script src="http://example.com/widget-script.js?key=b28b3065-6f95-2db6-9372-6482b1999c6f"></script>
The key
argument in the query string is used for authentication and for
selecting the correct configuration to be applied to the widget for the specific
site it's embedded into.
The widget-script.js
file is served by the bot's internal web server and, once
loaded in the host web page, it will place a button with the Teamwire logo at
a fixed (sticky) position in the page. When the user clicks the button,
the chat widget is presented, and a conversation can be started.
Once the user enters their name and sends a first message, the message is relayed to the bot, which creates a new chat with the recipients specified in the bot configuration. Any recipient can then reply, so the bot will relay the response message to the chat widget, thus permitting the conversation between the user of the hosting web page and the Teamwire users invoved in the chat.
Bot configuration¶
The bot can be configured to serve the chat widget to multiple sites. The default
configuration file name is config.json
.
The following example shows a configuration for serving the widget to two
different sites:
{
"configs": [{
"key": "b28b5065-6f95-4db6-9272-6482b1899c6f",
"allowed-origins": ["https://bots.teamwire.eu/widget-test/"],
"title-primary": "How can we help you?",
"title-secondary": "Hello,",
"site_name": "TW Support",
"chat_recipients": [{"first_name": "first_name", "last_name": "last_name"}],
"permanent_session": true
},
{
"key": "2f627450-821e-4a61-8931-63f2cf90427e",
"allowed-origins": ["https://bots.teamwire.eu/testsite/"],
"title-primary": "Chat with us",
"title-secondary": "Hey!,",
"site_name": "TW Website",
"chat_recipients": [{"first_name": "first_name", "last_name": "last_name"}]
}]
}
Each site configuration must provide the following properties
key
: this should be a GUID, used to univokely identify the siteallowed-origins
: in order to allow a site to use the widget, theReferer
header is used for authentication, and it should prefix-match one of the values contained in this string array. In particular theReferer
header received by the bot should contain any of the specifiedallowed-origins
title-primary
: the primary title to be shown in the widget headertitle-secondary
: the secondary title to be shown in the widget headersite_name
: a short handle for the site integrating the widget. This name will be used in chat titleschat_recipients
: a list of recipient names, to be matched with the names of existing Teamwire userspermanent_session
: boolean (default: false). If true, the chat session created through the widget will be permanent, otherwise it will be based on the life-span of the browser tab that loaded the page.
Running the bot¶
In order to start the bot you simply have to run:
$ python web-widget-bot.py
Please ensure that the following environment variables are correctly set:
TW_API_APPID
TW_API_SECRET
TW_API_HOST
Integrating the widget in a web site¶
Supposing the web widget bot is running and accessible at a url like
https://example.com/
the widget can be integrated in an html web page by simply adding the following script declaration:
<script src="https://example.com/widget-script.js?key=b28b5065-6f95-4db6-9372-6482b1999c6f"></script>
Running the bot behind a transparent proxy (e.g. nginx)¶
It is advised that the bot web service is placed behind a transparent proxy, in
order to ensure proper SSL termination.
Supposing the bot's web service is bound to port 8080 (the default port) the nginx
configuration for the https://example.com
site could be like the following:
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_pass http://localhost:8080;
}
location /ws {
proxy_pass http://localhost:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
As you can notice, we have to explicitly expose both the root /
and the /ws
locations with a proxy_pass
directive.
In most cases, however it is necessary to expose the service at a public location
different form the root /
. For example we could expose the chat widget at the
following public location:
https://example.com/web-widget/widget-script.js
The nginx configuration for the above location /web-widget
could be like the
following:
location /web-widget {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_pass http://localhost:8080;
}
location /web-widget/ws {
proxy_pass http://localhost:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
IMPORTANT NOTE: using this last configuration will not work unless the
bot is instructed about its public location. This is done by setting the
WEB_WIDGET_BOT_WEB_PREFIX
environment variable before running the bot.
For example, if the widget is made accessible through:
https://example.com/web-widget/widget-script.js
the WEB_WIDGET_BOT_WEB_PREFIX
variable should be set as:
export WEB_WIDGET_BOT_WEB_PREFIX=/web-widget
The leading /
is required
Running the bot with Docker¶
If you are Teamwire Partner, you can request access to the Teamwire's Harbor Registry where you can find a standard image of the Web Chat Widget bot to be directly deployed in your own staging or production environment. Please contact support@teamwire.eu for additional information about how to get access to Teamwire's Harbor Registry.
Provided that the above requirement is met, you can get the Web Chat Widget bot image with:
$ docker pull harbor.teamwire.eu/bots/web-widget-bot:1.6.0
then you can launch it with:
docker run -d --restart always --network host --name web-widget-bot \
-e TW_API_APPID="<YOUR APP ID>" \
-e TW_API_SECRET="<YOUR API SECRET" \
-e TW_API_HOST="https://backend.teamwire.eu" \
-e WEB_WIDGET_BOT_PORT="8081" \
-e WEB_WIDGET_BOT_CONFIG="/config/config.json" \
-e WEB_WIDGET_BOT_WEB_PREFIX="/chat-widget" \
-v /path/to/config/dir:/config \
harbor.teamwire.eu/web-widget-bot:1.6.0
The above docker run
command creates a new container named
web-widget-bot
and passes all the required environment variables to it.
In particular, the bot's web backend will listen on TCP port 8081, exposed at the
URL path /chat-widget/
. In other words, the chat widget script will be
served at http://localhost:8081/chat-widget/widget-script.js
.
In order to make a custom configuration file available to the bot, a container
volume is set, mounting the /path/to/config/dir
external directory to the
internal /config
directory. The WEB_WIDGET_BOT_CONFIG
environment variable
ensures that the configuration file is loaded from the volume.
Creating a Docker image for the bot¶
NOTE: this is needed only in case you want to build your own Docker image for the bot, e.g. because you want to run your own customised version of it. In case you simply want to run the standard Docker image provided by Teamwire, please refer to the previous section.
To build a Docker image for the bot you need access to the Teamwire SDK docker
image named bots/sdk-base
which is available for Teamwire Partners on
the Teamwire's Harbor Registry.
Provided that the above requisite is met, the Docker image for the bot can be created with:
$ docker build --rm --no-cache -t teamwire/web-widget-bot -f Dockerfile .
This will create the teamwire/web-widget-bot
Docker image, which can then be
deployed in a Docker environment, like detailed in the previous section.
For example:
docker run -d --restart always --network host --name web-widget-bot \
-e TW_API_APPID="<YOUR APP ID>" \
-e TW_API_SECRET="<YOUR API SECRET" \
-e TW_API_HOST="https://backend.teamwire.eu" \
-e WEB_WIDGET_BOT_PORT="8081" \
-e WEB_WIDGET_BOT_CONFIG="/config/config.json" \
-e WEB_WIDGET_BOT_WEB_PREFIX="/chat-widget" \
-v /path/to/config/dir:/config \
teamwire/web-widget-bot
Customising the Chat Widget¶
Widget build system¶
The chat widget sources are all contained under the widget
directory, which
in particular contains the following subdirectories:
widget-script
: sources forwidget-script.js
, which is ultimately integrated into the target web page and which is responsible of injecting the chat button and chat widget iframe into itsrc
: sources for the chat widget proper, which is loaded into the iframe
The build system for these components, which generates the scripts and bundles in
the dist
directory is based on Webpack and one custom Node.js script.
Requisites¶
- Node.js
- npm or yarn
Install dependencies¶
cd widget
npm install
Rebuilding the widget components¶
For development builds, use:
npm run build-dev
For production builds, use:
npm run build-prod
The build artifacts will be generated in the dist
directory.
Technical notes¶
Widget to bot protocol¶
The web-widget-bot
acts as a gateway between the chat widget and the Teamwire
backend, implementing chat creation, messages loading and message reception
through the Teamwire SDK. Moreover it provides all functionality for properly
serving the widget assets to the web pages the widget is integrated into.
The communication between the widget and the bot, and vice-versa, is completely handled through a websocket channel, over which a basic JSON-RPC protocol is implemented. This ensures both real time communication and the ability to quickly identify situations involving a loss of connectivity.
The JSON command format is the following:
id
: progressive numeric command identifier. Subsequent commands will have increasing command idsmethod
: string, name of the command to be performedparams
: dict, any JSON-serializable data
example:
{
"id": 1,
"method": "send_message",
"params": {
"sessionId": "aabbccddeeff",
"text": "hello"
}
}
Responses to commands must repeat back the command id received, additionally they will contain response or error data. Example:
{
"id": 1,
"result": {
"success": true
}
}
or for example in case of error:
{
"id": 1,
"error": "backend disconnected"
}
Please see /widget/src/js/ws.js
, /widget/src/js/api.js
for additional details
on the client component implementation.
Messages reception¶
The chat widget, besides the ability to send commands to the bot, is subscribed to "response_message" events, which are dispatched by the bot to the widget through the websocket channel any time it receives a new text message.
See /widget/src/js/api.js
.
Note: the websocket connection is initiated every time the widget is open, and it is terminated within an interval of 5s after the widget is closed (i.e. if the widget is closed and reopened within 5s the websocket is not affected).
Button and widget injection script¶
Once loaded in the target web page, the integration script will inject the chat
button and the iframe holding the widget into it.
In particular, as visible in widget/dist/widget-script.js
, the button, iframe,
and css style elements are created in the page by injecting html and css code
at the appropriate places inside of the page's DOM. The html and
css code used to construct the DOM elements are contained as simple strings in
widget-script.js
.
In order to ease the development of such injected components, the final
widget-script.js
script is built in a custom way by the widget build system.
In particular, its source code can be found in the widget/widget-script
directory,
which contains the following:
widget-script-template.js
: template ofwidget-script.js
widget-button-iframe.html
: html code for the chat button and iframewidget-style.css
: button and iframe styling
The same directory also contains the build-widget.js
node.js script, which is
used ot build the widget script from the three files above by minimising both
the html and the css sources and embedding them as strings in the template.
The build-widget.js
script is automatically invoked any time the widget is
rebuilt