Have you ever wanted to make a text-based messaging game, like “Bury me my Love?” Text-based messaging games are games that occur through the medium of text. They can be played with other players or they can be played against an automated system. In this case I built a game where players communicate with an automated system built using Twilio Autopilot and Facebook Messenger.
The title of my game is called Camaraderie Park. Players complete a short questionnaire filled with a few outlandish questions meant to help them find which part of Camaraderie Park is most suited to them.
Play Camaraderie Park by messaging the Camaraderie Park Facebook Page.
Follow this tutorial to learn how to make your own text-based adventure on Facebook Messenger using Twilio Autopilot.
You Will Need
- A Twilio account (If you sign up for a new account through this link, you’ll get an extra $10 in credit when you upgrade.)
- A Facebook account. You’ll need this to set up your Facebook Messenger integration.
- An Airtable account. We’ll use airtable to store the results of the game, in case you wanted to see what kind of game choices your users were making.
Create your game bot using Twilio Autopilot
In order to make the automatic text messaging system for your game, you will need to write a task using Twilio Autopilot. In order to do this, navigate to the Twilio Autopilot Console, then create a new task.
Access the Twilio Autopilot section of the Console on the navigation panel to the left.
In the Autopilot dashboard, click on the Start from Scratch button in the “Create a bot” panel. Type in a unique name for your bot. I chose to name my bot “camaraderie_park” in order to match the name of my project. You may also enter a human friendly name for your bot as well, in case you want to describe your bot a bit further.
Your bot will contain a few tasks already. A task represents the primary meaning behind a user’s text or speech when they interact with the chatbot, or Assistant. You will add a new task and edit some existing ones. These tasks contain the content of your messages and will be deployed at various points of the message exchange with your bot.
Click on the blue Add a task button. I chose to name this task “camaraderie_park” in order to match the name of my game. This task will contain the core content of the game.
Click on Program for the “camaraderie_park” task to the right. Delete the code that is already in place and replace it with the following code:
{
"actions": [
{
"collect": {
"name": "camaraderie_park",
"questions": [
{
"question": "You just won a sea-faring vacation from the Vodovod industrial maritime trade company. They will give you free use of one of their cargo ships for any deep sea aquatic adventure of your choice. What sort of adventure do you pursue? \n \n A. I take my cargo ship far out into the sea and dive into an oceanic abyss. No one knows what lives down there, but I plan on taking at least one beach bottom dwelling creature and keeping it as a pet. \n \n B. I'm going to stock up on fancy glassware, Hors d'oeuvres, and sparkly beverages and ascertain whether mermaids do truly exist! I just hope I don't run into any wandering submerged AI crabs and fall for their siren call! \n \n C. I scour the seas for a yet undiscovered, uninhabited island. I lounge on the sand all day and look at the undulating waves while humming glow clouds float in the sky.",
"name": "question1",
"validate": {
"allowed_values": {
"list": [
"a",
"b",
"c"
]
},
"on_failure": {
"messages": [
{
"say": "Please send a, b, or c!"
}
],
"repeat_question": true
},
"max_attempts": {
"redirect": "task://greeting",
"num_attempts": 3
}
}
},
{
"question": "Scientists from the VeleSystem Interstellar Research Laboratory have discovered a new dimension. What do you think is most likely going to be lurking in it? \n \n A. Some new extra-dimensional friends and good vibes all around! \n \n B. Some life forms that exist and light waves and sound waves that we can't perceive. If we open it, we won't really notice any changes. But something will be different. \n \n C. Definitely something malicious. Close that other worldly portal and never touch it again, not even with a ten foot pole!",
"name": "question2",
"validate": {
"allowed_values": {
"list": [
"a",
"b",
"c"
]
},
"on_failure": {
"messages": [
{
"say": "Please send a, b, or c!"
}
],
"repeat_question": true
},
"max_attempts": {
"redirect": "task://greeting",
"num_attempts": 3
}
}
},
{
"question": "While The historians at the KosmoHall University uncovered a buried library full of ancient tomes. What do you try to uncover in this library? \n \n A. Research spells to communicate with the dark, clouded mountains that rest on the horizon. \n \n B. Memorize incantations to grow beautiful flowering forests and fields that welcome fairies and woodland spirits your home. Make your own magical dream wonderland happen. \n \n C. Transcribe and mass publish the entire library. Now the ability to summon ancient deities, access the power of the weather and change land formations is accessible to the entire world. This is the best option come what may.",
"name": "question3",
"validate": {
"allowed_values": {
"list": [
"a",
"b",
"c"
]
},
"on_failure": {
"messages": [
{
"say": "Please send a, b or c!"
}
],
"repeat_question": true
},
"max_attempts": {
"redirect": "task://greeting",
"num_attempts": 3
}
}
},
{
"question": "The VeleSystem researchers discovered that the structural stability of the worlds ecosystems is controlled by a nebulous eldritch entity that needs to be constantly placated in order to hold the world in a state of equilibrium. How do you placate it? \n \n A. Give it candy. Lots of candy. Doesn't matter if it's a glimmering, tentacled being that oscillates between solid and liquid states. It will still appreciate candy. \n \n B. Point this entity towards the home of your favorite enemy. And say nothing else. This situation is out of your hands now. \n \n C. Give it a hug, or a hug approximation that complements its gaseous form. Kindness wins every time. ",
"name": "question4",
"validate": {
"allowed_values": {
"list": [
"a",
"b",
"c"
]
},
"on_failure": {
"messages": [
{
"say": "Please send a, b, or c!"
}
],
"repeat_question": true
},
"max_attempts": {
"redirect": "task://greeting",
"num_attempts": 3
}
}
}
],
"on_complete": {
"redirect": "task://goodbye"
}
}
}
]
}
This dialogue is stored as a JSON object. The JSON contains some structural elements that are key to understanding how this conversation will play out when the player starts messaging your bot.
The collect
object stores how the player responds to each question. You will use this object later when sending data over to Airtable.
You can learn more about the collect
action here. The questions
array stores multiple question
objects. The allowed_values
object contains the only acceptable answers that the player can respond with. If the player responds with something that is not in the allowed_values
object, then they receive a message telling them to enter one of the allowed answers.
The messaging exchange loops through all of the questions in the questions
object. Once the player has answered all of the questions, they are redirected to the “goodbye” task which sends the player a final message.
The on_complete
object dictates what will happen when the player finishes messaging your bot. Eventually, you will want it to redirect to a function that will evaluate the results and send them over to Airtable. You have not programmed this function yet, so you’re using the default “goodbye” task for now.
Eventually, after you create the Airtable, your on_complete
object will look like this:
"on_complete": {
"redirect": "https://testservice-4904.twil.io/camaraderie_park"
}
After you have copied and pasted the game dialogue, click on Save and then Build Model.
Navigate back to the “Tasks” section of the bot dashboard. Click on Program for the “greeting” task. This task sends the first message when a player messages your bot. (This task is called “greeting” by default. It is possible to change the name for this task, but this tutorial will stick to the default name.) Your next step is to alter the default greeting message and then redirect this task to send the dialogue for the game.
To do this, replace the code for the “greeting” task with an opening statement that you would like the player to receive when they first message your bot. Then, redirect the “greeting” task to the “camaraderie_park” task. Here’s an example:
{
"actions": [
{
"say": "Greetings traveller! Welcome to Camaraderie Park. Before you begin your ascent up the fortress, please complete this survey to find out which path is right for you!"
},
{
"redirect": "task://camaraderie_park"
}
]
}
Connect your Autopilot Bot to Facebook Messenger
Players will be using Facebook Messenger to message a bot tied to a Facebook page. If you’re looking to launch a game on Facebook Messenger, it can help to have a Facebook page that represents your game’s aesthetic. It should have a matching title and a matching visual style if applicable. Check out the Facebook page for Camaraderie Park for an example.
After you have set up your Facebook page, configure the Facebook Messenger bot to work with Twilio Autopilot. This will ensure that when players message, the bot will send the dialogue you’ve included in the Tasks section.
To begin, install the Facebook Messenger channel on your Twilio account. Visit the installation page and then click “Install”. Once installed, you will see a page to configure your new Facebook Messenger connection.
In the “Properties” section of the configuration page, check “Programmable SMS Inbound” next to “USE IN”. Next, in the “Credentials” section, click the “Facebook Login” button, follow the instructions, and then select the Facebook Page you would like to use for messaging. This will link your Facebook page to your Twilio account.
In order to connect the Autopilot Task to Facebook Messenger, you need to set the Callback URL to the Autopilot URL for Facebook Messenger. Open Twilio Autopilot in a new tab. Make sure you are in the “Your bots” section. You can find it in the left-hand menu. Click on the bot that you would like to use for the game.
Select “Channels” in the left hand menu.
On the resulting page, you will see a Facebook Messenger tile in the Channels Catalog area. Click this Facebook Messenger tile and make sure you are under the “Configure” tab. Scroll down to the “Configuration” section, which is beneath the “Credentials” section, and copy the Callback URL.
Then, go back to Autopilot, and select the bot that you have made for the messaging game. Go to the Channels section, and select the Facebook Messenger tile.
Once you click the tile, you will see a URL section. Copy and paste the Callback URL from the “Configuration” section into the Callback URL area on your Channels page. Click Save. You have now connected your Autopilot Task to Facebook Messenger.
Try messaging your Facebook page and see if you get a response containing the dialogue you pasted into the tasks from earlier in the tutorial.
Set up an Airtable Base to save info about player responses
In games like “Life is Strange”, players get to see how their choices in the game stack up against the percentages of players worldwide who made similar choices.
If you’d like to do something similar, you’ll need to set up an Airtable Base in order to save the player’s data from the message exchange. If you would like to learn more about using Airtable with Twilio, take a look at this tutorial.
First make a free Airtable account by visiting the Airtable site. Once you have logged in, create a new Workspace. I named mine “CamaraderiePark” to match my game.
Then, add a new base to your Workspace. In Airtable, a base contains tables with data.
Create a new table in your base (I named my table CamParkData for consistency). This table will store your user’s data. My table has four fields, one for each question. In this case, each field will hold a single line of text data. When you click the plus button to the right to add a field, you can choose what sort of data you would like the new field to store.
This screenshot contains data from previous message exchanges, but when you create the table, it will be blank.
Once you have set up your table, you will need to connect it to your Twilio app. In order to do this, you will need your Airtable API Key and your Airtable Base ID.
Follow these instructions to generate an Airtable API Key. Make sure to keep this key private so that no one can tamper with your Airtable data. Save this value in a safe place. We will be returning to it later.
To find your Airtable Base ID, click on the new base you created for this game from your list of bases in Airtable. This will take you to the API documentation for that base. In the “Introduction” section, you will see a line that says the ID of this base is xxxxxxxxxxxxxx
. This is your Airtable Base ID. Save this value in a safe place. You will be returning to it later.
Connect your Autopilot Bot to your Airtable Base
Now it is time to write the code that will process your users’ responses. This code will access the data saved from the messaging exchange in Autopilot, send it to the Airtable base, evaluate the results, and send the results of the game back to the player.
In this tutorial, you’ll use Twilio Functions to host this code. Twilio Functions is a serverless environment that allows you to run backend code without the hassle of setting up and configuring your own server.
You can create functions directly from the Functions section of the Twilio Console. Once there, click on the Create Service button and enter a name for your service.
This will direct you to a dashboard where you can add functions, dependencies, and environment variables to your new service.
In order for your function to work, you will need to add some supporting libraries and environment variables. In the “Settings” section, found toward the bottom of the Service dashboard, click on the “Dependencies” tab.
Add the Airtable module, by entering airtable
in the Module field and the version number, ^0.8.1
, in the corresponding Version field. Make sure the twilio
module is also included. The version is not important. If you leave it blank it will assume the latest version.
After you have added the airtable
dependency, click on the “Environment Variables” tab. This is where you will add the Airtable API Key and the Airtable Base ID. You will access these values in the code you’ll be writing shortly.
In the Key field, enter BASE_ID
, and in the corresponding Value field, copy and paste the value of your Airtable Base ID. Do the same for the Airtable API Key, using the variable name AIRTABLE_API_KEY
.
Now that you have the needed dependencies and environment variables, you can begin writing your function. Click on the Add + button, then click Add function. Give your function a concise name in the space available.
The purpose of this function is to tell players how they did at the end of the game and to store the data from their playthrough in Airtable. In Camaraderie Park, I send the player an image after they have completed the quiz. If you would like to include an image in your game, click on the Add + button and then select Upload File.
My finished code, along with images and gameplay text, looks like this:
// This is your new function. To start, set the name and path on the left.
const airtable = require("airtable");
const twilio = require("twilio");
exports.handler = function(context, event, callback) {
let memory = JSON.parse(event.Memory);
let question1 = memory.twilio.collected_data.camaraderie_park.answers.question1.answer.toLowerCase();
let question2 = memory.twilio.collected_data.camaraderie_park.answers.question2.answer.toLowerCase();
let question3 = memory.twilio.collected_data.camaraderie_park.answers.question3.answer.toLowerCase();
let question4 = memory.twilio.collected_data.camaraderie_park.answers.question4.answer.toLowerCase();
//finding the lowest
const result = Object.entries(
[question1, question2, question3, question4].reduce((previous, current) => {
if (previous[current] === undefined) previous[current] = 1;
else previous[current]++;
return previous;
}, {})).reduce((previous, current) => (current[1] >= previous[1] ? current : previous))[0];
//determine what to say to the player based off of the result
var msg = '';
var destination_image = '';
if(result == 'a') {
msg = `Based off of your answers, we believe that the Old Fortress would be the best destination for you. Be sure to watch out for the holographic knight!`;
destination_image = 'https://testservice-4904.twil.io/holo_garden_small.gif';
}
else if(result == 'b') {
msg = `Based off of your answers, we believe that the Holographic Spirit Garden would be the ideal destination for you. Remember, you are free to observe the holographic spirits, but you are not free to feed nor touch them!`;
destination_image = 'https://testservice-4904.twil.io/holo_garden_small.gif';
}
else if(result == 'c') {
msg=`Based off of your answers, we believe that the Amorphous Shrine will be a great destination for you. Pay special attention to any reverberating objects. They might contain special wisdoms for you to contemplate.`;
destination_image = 'https://testservice-4904.twil.io/holo_garden_small.gif';
}
//the response is based off of the players answer
const response = { actions: [{
show: {
body: msg,
images: [{
label: "The Holographic Garden",
url: destination_image
}
]
}
}]
}
const base = new airtable({
apiKey: context.AIRTABLE_API_KEY,
}).base(context.CAMPARK_BASE_ID);
base("CamParkData").create(
[
{
fields: {
Question1: question1,
Question2: question2,
Question3: question3,
Question4: question4
},
},
],
function (error, records) {
if (error) {
console.error(error);
callback(error);
return;
} else {
callback(null, response);
}
}
);
};
In the code above, the event.Memory.collected_data
object stores the player’s answers from the game. The value memory.twilio.collected_data.camaraderie_park.answers.question1.answer.toLowerCase()
stores the player’s answer for the first question.
If you’ve named your game something else, be sure to replace camaraderie_park
with the name of your Twilio bot. Also, replace question1
with the name you chose for the first question in the Task.
The next section in the code calculates the most common answer and returns it as the final decision. You may recognize this method from Lizzie Siegel’s tutorial on building a QuizBot in 8 minutes.
const result = Object.entries(
[question1, question2, question3, question4].reduce((previous, current) => {
if (previous[current] === undefined) previous[current] = 1;
else previous[current]++;
return previous;
}, {})).reduce((previous, current) => (current[1] >= previous[1] ? current : previous))[0];
Next, the code sends the information to the Airtable base, using the environment variables you added in the previous step.
const base = new airtable({
apiKey: context.AIRTABLE_API_KEY,
}).base(context.CAMPARK_BASE_ID);
console.log("Sending keys");
base("CamParkData").create(
[
{
fields: {
Question1: question1,
Question2: question2,
Question3: question3,
Question4: question4
},
},
],
function (error, records) {
if (error) {
console.error(error);
callback(error);
return;
} else {
callback(null, response);
}
}
);
Make sure you include the name of the table that will be receiving the data (I send the data to my “CamParkData” table, but you may have named your table something else). Similarly, keep an eye on your field names and make sure they match the names in your table.
Save your function, and then deploy your service by selecting Deploy All. Next to your function’s name, click on the three dots to open the options menu and copy the URL of the function:
Navigate back to your Autopilot bot. Remember the original function you defined that contained your game content? You’ll need to open that up and edit the last line to remove the “Goodbye” task and instead re-route to the Twilio function. Click Program next to your game data task.
Scroll to the bottom to find where you previously defined the on_complete
object.
Currently, it’s redirecting to the “Goodbye” task. You’ll need to change this so that it redirects to your newly created Twilio Function. So if your function URL is https://nameofyourfunction-1234.twil.io/test, your redirect should look like:
"on_complete": {
"redirect": "https://nameofyourfunction-1234.twil.io/test"
}
Now, if you play your game, it should conclude with the function you defined above...
...and you’ll receive the responses in your Airtable!
Conclusion
Thank you for following along with this tutorial! I hope you have a lot of fun making your own text-based messaging game. If you’d like to build more Twilio chatbots, check out this Netflix recommendation chatbot or this GPT-3-powered bot that gives cooking advice.
Julia Makivic is an artist who combines art and technology to create amazing experiences. Follow her on Twitter and Instagram for more fun projects, and check out the Camaraderie Park Facebook page for more updates on the game.

Aprenda a crear un chatbot de WhatsApp que reserve citas en Google Calendar usando Twilio Autopilot y PHP

Aprenda como criar um chatbot no WhatsApp que agenda compromissos no Calendário do Google utilizando Twilio Autopilot e PHP


In part 2 of this series, learn how to use Twilio Autopilot, Airtable, and an Adafruit Feather Huzzah to create an interactive sculpture.

Sempre foi complicado desenvolver sistemas de atendimento via URA que permitissem uma experiência interessante para seus usuários e para negócios, veja como a Twilio permitiu conquistar esse tipo de solução através dos seus produtos.

Você quer desenvolver um chatbot, mas não sabe qual a ferramenta ideal para começar?