Functions
Within cards you will make use of functions and expressions to describe the logic of your impact service.
Cards allow for various functions: replying with multi-media or interactive buttons, updating contact fields, integrating with 3rd party services or doing various calculations.
Text messages
Send a text message
This function sends a text message to the user.
Syntax
text("lorem ipsum")
Example
The following example creates a stack that sends a single text message to a user. The content of the message says "Hello this is my first text.".
card TextCard do
text("Hello this is my first text.")
end
Common errors
- Not wrapping the message in double quotes.
- text() is misspelt as test().
Ask a question
This function sends a text message and waits for the user’s response.
Syntax
ask("lorem ipsum?")
Example
The following example creates a stack that asks the user "What is your name?" and then waits for the user’s response. Once the user replies a thank you message is sent.
card QuestionCard do
ask("What is your name?")
text("Thanks for answering")
end
Key things to note
- The chat service will only execute further steps when a response is received or, else, when the stack times out.
Common errors
- Not wrapping the question in double quotes.
Interactive messages
WhatsApp supports two types of quick replies: button replies and list replies.
Buttons replies are limited to 3 buttons. Each button has a limit of 20 characters.
List replies are limited to 10 options. Each option has a limit of 24 characters.
The body text, the header, and the footer of an interactive message can be placed into the buttons
or list
blocks so it can be composed as a single message.
Send a button message
This function sends a text message with buttons to the user. Buttons make it easy for the user to reply. You can add up to 3 buttons per message.
Syntax
buttons([Button1, Button2, Button3]) do
text("Select an option!")
end
You can also use labels for the buttons like so:
buttons([Button1: "1️⃣", Button2: "2️⃣", Button3: "3️⃣"]) do
text("Select an option!")
end
Example
The following example creates a stack that ask the user "What would you like to drink?" and provide two options to select from: Tea or Coffee.
If the user selects Tea
they receive a message saying "Thanks for choosing tea". If the user selects Coffee
they receive a response saying "Thanks for choosing coffee".
card ButtonsCard do
buttons([Tea, Coffee]) do
text("What would you like to drink?")
header("This is the header!")
footer("This is the footer!")
end
end
card Tea do
text("Thanks for choosing tea")
end
card Coffee do
text("Thanks for choosing coffee")
end
You can provide labels for the buttons (e.g. Tea 🫖
), while keeping a simple card name (e.g. Tea
).
card ButtonsCard do
buttons([Tea: "Tea 🫖", Coffee: "Coffee ☕️"]) do
text("What would you like to drink?")
header("This is the header!")
footer("This is the footer!")
end
end
Sometimes, one wants to provide multiple buttons with different labels and but have them go to the same destination card. It's possible to do so by using the same destination card name, with different labels.
card Card do
var =
buttons(Destination: "🧁", Destination: "🎂", Destination: "🍰") do
text("Choose your favourite cake!")
end
end
card Destination do
text("You chose @var using @var.label ")
end
This will present 3 buttons, each with a different label but the response
is all handled by the same card with the name Destination
. Keep in mind that
even if the Destination
card may have a display label assigned, any label set
in the button will take priority over display labels on the card.
Key things to note
- You need to use both the
buttons()
and thetext()
functions. - The
buttons()
function describes the available options. Buttons can have up to 3 options. Button options have a limit of 20 characters. - The
text()
function describes the instruction to the user. - The header and footer are optional.
- If you want to act on the user selection you need to add new cards to the stack to define the logic of each selected option.
Common errors
- Forgetting to add the
text()
function into thebuttons()
function. - Forgetting to add cards for each button option.
Send a list message
This function sends a list of items to the user to select from. You can add up to 10 options in a list.
Syntax
list("lorem ipsum", [Option1, Option2, …, Option10]) do
text("lorem ipsum")
end
Example
The following example creates a stack that sends the user a list message and allows them to choose between four options.
The user is instructed to "Pick an option!". Once they click the "Call to action" text the list expands and they see 4 options: Option1, Option2, Option3, Option4. After the user makes a selection, they get a message confirming their choice.
card List do
list("Call to action", [Option1, Option2, Option3, Option4]) do
text("Pick an option!")
header("This is the header!")
footer("This is the footer!")
end
end
card Option1 do
text("You selected option 1")
end
card Option2 do
text("You selected option 2")
end
card Option3 do
text("You selected option 3")
end
card Option4 do
text("You selected option 4")
end
Key things to note
- You need to use both the
list()
and thetext()
functions. - The
list()
function describes the copy for the selection button, as well as all the available options. Lists can have up to 10 options. List options have a limit of 24 characters. - The
text()
function describes the instruction to the user. - The header and the footer are optional.
- If you want to act on the user selection you need to add new cards to the stack to define the logic of each selected option.
Common errors
- Forgetting to add text for the selection button.
- Forgetting to add the text() function after the list() function.
- Forgetting a comma between the selection text button and the options.
- Forgetting to add cards for each list option.
Labels for buttons and list items
Often times on an impact service you will re-use things, e.g. your menu. When you need to make updates to your copy, ideally you want to update it once and have that change apply everywhere that is applicable. This is possible for button and list options.
Syntax
When defining cards you can add an optional label for the card. The label will be used for buttons and list items the card is part of.
card ButtonCard, "lorem ipsum" do
buttons([Button1, Button3, Button3]) do
text("lorem ipsum")
end
end
Example
Let's create a basic menu selection with 3 options: About
, Contact
and Terms of service (ToS)
. Once the user clicks any of the buttons, they get a short message with a single button that takes them back to the Start
.
card Start do
buttons([About, Contact, ToS]) do
text("This our menu. Select an option.")
end
end
card About do
buttons([Start]) do
text("This is about us, we are truly wonderful!")
end
end
card Contact do
buttons([Start]) do
text("You can contact us via pigeon post, glhf")
end
end
card ToS do
buttons([Start]) do
text("We provide zero guarantees")
end
end
Now, let's say we want to change the copy of the Start
button. We use it three times but only want to update it once. You can do that by specifying the copy you want as a string in that button option card.
By adding the "Menu" label to the definition of the Start
card, that label will now be used in any button or list item where the Start
card is referenced.
card Start, "Menu" do
buttons([About, Contact, ToS])
text("This our menu. Select an option.")
end
card About do
buttons([Start]) do
text("This is about us, we are truly wonderful!")
end
end
card Contact do
buttons([Start]) do
text("You can contact us via pigeon post, glhf")
end
end
card ToS do
buttons([Start]) do
text("We provide zero guarantees")
end
end
The best part about the string is that you can also use dynamic fields, which is great for personalisation. Let's update the Start
button to include the user's profile name on WhatsApp.
card Start, "Head home @contact.whatsapp_profile_name" do
buttons([About, Contact, ToS])
text("This our menu. Select an option.")
end
card About do
buttons([Start]) do
text("This is about us, we are truly wonderful!")
end
end
card Contact do
buttons([Start]) do
text("You can contact us via pigeon post, glhf")
end
end
card ToS do
buttons([Start]) do
text("We provide zero guarantees")
end
end
Media messages
Making use of media improves the user experience and can overcome literacy gaps. WhatsApp allows five types of media: image, video, audio, document and sticker.
The media you intend to send must be hosted on a publicly-accessible URL.
A simple way to host media on a publicly-accessible URL is to upload your file to Google Drive and then obtain a download link using this site. Make sure the sharing permissions is set to Any one with the link can view.
Send an image
This function sends an image to the user.
Syntax
image("<URL of your image>")
Example
The following example creates a stack that sends the user an image with a caption saying "hello there!".
card MyCard do
image("https://upload.wikimedia.org/wikipedia/commons/thumb/d/db/Golden-crowned_kinglet_at_JBWR_%2811835%29.jpg/1000px-Golden-crowned_kinglet_at_JBWR_%2811835%29.jpg")
text("hello there!")
end
Key things to note
- You need to use both the
image()
and thetext()
functions. - The
image()
function only holds the URL. Images can be up to 5MB. - The
text()
function sends a text caption. - WhatsApp only supports specific file types.
Common errors
- Forgetting to add the text() function after the image() function.
Send a video
This function sends an image to the user.
Syntax
video("<URL of your video>")
Example
The following example creates a stack that sends the user a (cat) video with a caption saying "hello there!".
card MyCard do
video("https://drive.google.com/uc?export=download&id=1LCTe5S6DT1mNnYQhaoeYsk3jqSAEglVE")
text("hello there!")
end
Key things to note
- You need to use both the
video()
and thetext()
functions. - The
video()
function only holds the URL. Videos can be up to 16MB. - The
text()
function sends a text caption. - WhatsApp only supports specific file types.
Send an audio
This function sends an audio to the user.
Syntax
audio("<URL of your audio>")
Example
The following example creates a stack that sends the user an audio file and a text message saying "hello there!".
card MyCard do
audio("https://drive.google.com/uc?export=download&id=1hpkdDN9noqIqvwDX0EhS2z7K2W_-khXS")
text("hello there!")
end
Key things to note
- You need to use both the
audio()
and thetext()
functions. - The
audio()
function only holds the URL. Audio files can be up to 16MB. - The
text()
function sends a separate text message. - WhatsApp only supports specific file types.
Send a document
This function sends an document to the user.
Syntax
document("<URL of your document>")
Example
The following example creates a stack that sends the user a document named "hello there!".
card MyCard do
document("https://drive.google.com/uc?export=download&id=17-O2zjqaI-eQdqVJ-febYBxr0E9YT_HU")
text("hello there!")
end
Key things to note
- You need to use both the
document()
and thetext()
functions. - The
document()
function only holds the URL. Document files can be up to 100MB. - The
text()
function describes the document name. - WhatsApp only supports specific file types.
Template messages
You can send message templates from stacks provided that the template you want to send already exists and has been approved.
A WhatsApp message template is identified by its name and language, so you'll need both of those to send a template from stacks.
Syntax
send_message_template(
"template-name",
"template-language",
["body-placeholder1", "body-placeholder2", ...],
header: ["header-placeholder"],
video: "https://link.to/video.mp4",
image: "https://link.to/image.mp4",
document: "https://link.to/document.mp4",
buttons: [Card1, Card2, ...]
)
The header
, video
, image
, document
and buttons
parameters are optional.
Template with placeholders in the body
If the template contains placeholders in its body, you can provide values for those placeholders in a list after the template name and language.
In case the template doesn't have body placeholders, you can pass an empty list []
.
Example
Let's assume you have created the following template:
- name:
simple-reminder
- language:
en
- body:
Hi {{1}}, this a reminder to {{2}}
Here is how you could send that template:
card SendTemplate do
send_message_template(
"simple-reminder",
"en",
["Mark", "exercise"]
)
end
Template with placeholders in the header
If the template contains placeholders in its header, you can provide parameters for them passing a list of values to the optional header
argument.
Example
Let's assume you have created the following template:
- name:
simple-reminder
- language:
en
- header:
{{1}} reminder
- body:
Hi {{1}}, this a reminder to {{2}}
Here is how you could send that template:
card SendTemplate do
send_message_template(
"simple-reminder",
"en",
["Mark", "exercise"],
header: ["Training"]
)
end
Template with a media header
If the template has a media header, you can use the optional video
, image
, document
arguments to provide a link to the desired media.
Example
Let's assume you have created the following template:
- name:
simple-reminder
- language:
en
- header media type:
VIDEO
- body:
Hi {{1}}, this a reminder to {{2}}
Here is how you could send that template:
card SendTemplate do
send_message_template(
"simple-reminder",
"en",
["Mark", "exercise"],
video: "https://link.to/the/video.mp4"
)
end
Let's assume you have created the following template:
- name:
simple-reminder
- language:
en
- header media type:
IMAGE
- body:
Hi {{1}}, this a reminder to {{2}}
Here is how you could send that template:
card SendTemplate do
send_message_template(
"simple-reminder",
"en",
["Mark", "exercise"],
image: "https://link.to/the/image.jpg"
)
end
Let's assume you have created the following template:
- name:
simple-reminder
- language:
en
- header
media type: DOCUMENT
- body:
Hi {{1}}, this a reminder to {{2}}
Here is how you could send that template:
card SendTemplate do
send_message_template(
"simple-reminder",
"en",
["Mark", "exercise"],
document: "https://link.to/the/document.pdf"
)
end
Template with buttons
If the template contains buttons, you can use the optional buttons
argument to direct the flow of the stack to different cards depending on the button the user clicks.
Example
Let's assume you have created the following template:
- name:
updates
- language:
en
- body:
Hi {{1}}, would you like to receive updates?
- buttons:
Yes, I would love to!
,No, I would not.
Here is how you could send that template and direct the flow of the stack depending on the button the user clicks:
card SendTemplate do
send_message_template(
"updates",
"en",
["Mark"],
buttons: [Yes, No]
)
end
card Yes do
text("Great! You will receive updates from now on.")
end
card No do
text("Ok, you will not receive updates.")
end
It's important to note that the text of the buttons displayed in the simulator will likely be different from the ones displayed in WhatsApp. This is because the simulator uses the names of the cards you defined as options to simulate the display text for the buttons, while the real message uses the text you provided in the template.
Key things to note
- The template you want to send should already exists and be approved.
Personalisation
Stacks allows you to build highly personalised impact services. You can store responses from users momentarily in variables while the conversation happens, or more permanently against the user's contact profile.
Save a response and use it in conversation
Any response from a user can be stored momentarily in variables and used in future interactions. This provides a more personalised user experience.
Syntax
# Save a result into a variable
variable_name = some_function_call()
# Use an expression to put the variable's value in a string
text("The value is: @variable_name")
Example
Let's revisit the button example. This time will will store the selected options and reference it in future responses. You will notice we refer to the stored value in strings by using the @
symbol. This makes use of expressions to include the button picked in the response.
card Card do
button_picked = buttons([Tea, Coffee]) do
text("What do you like to have?")
end
end
card Tea, "Tea 🫖" do
text("You selected @button_picked")
end
card Coffee, "Coffee ☕️" do
text("You selected @button_picked")
end
Update a contact profile field
This function updates a contact profile field with a defined value. Storing a value against the user's contact profile means it is available when the stack interaction ends and can be retrieved in future interactions.
The value can be any data captured while the user interacts with the Stack. All standard and custom fields can be updated with this function.
Syntax
update_contact(profileFieldName: "value")
Example
The following example creates a stack that asks the user what their name is, saves the response to a variable called name
, and updates the contact profile name field with that value.
card One, then: Two do
name = ask("What is your name?")
end
card Two do
update_contact(name: "@name")
text("Your name has been updated to @contact.name")
end
Key things to note
- The contact profile field needs to exist already.
Running another stack
A stack can start the execution of another stack. This can be useful to break large services into multiple stacks or to extract common logic into a separate stack.
Syntax
run_stack("<uuid-of-the-stack-to-run>")
Retrieving the UUID of a stack
To run a stack you need its UUID. You can retrieve the UUID of the stack to run by clicking the "Copy ID" button next to it in the list of stacks:
Example
This example shows you how to call a stack B from withing stack A. The run_stack()
function requires the UUID of the stack you want to run.
This would be the code for Stack A:
card MyCardA do
text("Hello from Stack A")
run_stack("d58b0319-eb3f-4884-b43b-4ef0b7c37e1d")
text("Hello again from Stack A")
end
This the code for Stack B. Let's assume its UUID is d58b0319-eb3f-4884-b43b-4ef0b7c37e1d
:
card MyCardB do
text("Hello from Stack B")
end
Key things to note
- The flow goes back to the parent stack once the child stack ends.
- There is currently no way to pass parameters or expect a return value from a child stack, however you can update fields on the contact profile, which is available both to the parent and child stack.
Scheduling
A stack can schedule the execution of another stack (or itself) at some time in the future. This can be useful to program messages that will be sent to the user in some time from now (e.g. 2 days from now).
Syntax
The stack can be scheduled using either the in
argument or the at
argument.
The in
argument requires a relative time expressed in seconds. The scheduled stack will execute after the number of seconds specified.
schedule_stack("<uuid-of-the-stack-to-schedule>", in: seconds)
The at
argument requires an exact date, in a datetime format. This date can be expressed using one of our expressions. The scheduled stack will execute at the date and time that has been defined.
If you wanted to schedule a stack exactly two days from now you could do:
schedule_stack("<uuid-of-the-stack-to-schedule>", at: datetime_add(now(), 2, "D"))
Or if you wanted to schedule a stack to run at 9am, the next monday after a certain date you could do:
base_date = date(2023, 2, 08))
schedule_stack("<uuid-of-the-stack-to-schedule>", at: datetime_next("monday", "09:00", base_date))
A stack that was previously scheduled can also be canceled, using our cancel_scheduled_stacks
function:
card TextCard, then: MaybeCancel do
schedule_stack("<uuid-of-the-stack-to-schedule>", at: datetime_next("monday", "09:00", base_date))
schedule_stack("<uuid-of-the-stack-to-schedule>", at: datetime_next("tuesday", "09:00", base_date))
keep_going = ask("Do you want to keep receiving these messages? Type STOP to cancel them")
end
card MaybeCancel when keep_going == "STOP" do
cancel_scheduled_stacks("<uuid-of-the-stack-to-cancel>")
end
card MaybeCancel do
schedule_stack("40ac549a-a883-4c26-b3a2-6eaf8f799edb", at: datetime_next("friday", "10:00"))
end
Please note that this function cancels all scheduled stacks with the given UUID for that recipient, so in the example above, both scheduled stacks would be canceled.
Retrieving the UUID of a stack
To schedule a stack you need its UUID. You can retrieve the UUID of the stack to schedule by clicking the "Copy ID" button next to it in the list of stacks:
A basic reminder message
This example shows you how to schedule an individual reminder that will be sent to the user in 2 hours. You need to create two stacks. The schedule_stack()
function requires the UUID of the stack you want to schedule.
This stack schedules a second stack to run in 2 hours from now. It refers to the other stack using its UUID:
card ScheduleReminder do
text("We'll send you a reminder message in 2 hours")
schedule_stack("d58b0319-eb3f-4884-b43b-4ef0b7c37e1d", in: 2 * 60 * 60)
end
This is the stack that will send the reminder message. Let's assume its UUID is d58b0319-eb3f-4884-b43b-4ef0b7c37e1d
:
card SendReminder do
text("Here is your reminder")
end
A more complete use case
In this example we allow the user to decide when they want to receive a reminder message. Once again two stacks are required.
This is the first stack the user interacts with. It schedules the execution of the second stack referencing it by UUID:
card FirstCard, then: NoChoice do
buttons([OneHour, TwoDays, NextSaturday])
text("When would you like to be reminded?")
end
card NoChoice do
text("Please click on one of the buttons.")
end
card OneHour, "In 1 hour" do
text("Ok, we'll remind you in 1 hour.")
schedule_stack("5ac7f564-a158-4519-9e41-faac610d59ec", in: 60 * 60)
end
card TwoDays, "In 2 days" do
text("Ok, we'll remind you in 2 days.")
schedule_stack("5ac7f564-a158-4519-9e41-faac610d59ec", in: 2 * 24 * 60 * 60)
end
card NextSaturday, "Next Saturday at noon" do
text("Ok, we'll remind you next Saturday at noon.")
schedule_stack("5ac7f564-a158-4519-9e41-faac610d59ec", at: datetime_next("saturday", "12:00"))
end
This is the stack that will send the reminder message, Let's assume its UUID is 5ac7f564-a158-4519-9e41-faac610d59ec
:
card SendReminder do
# Send a template in order to support reminders longer than 24 hours
send_message_template("reminder_template", "en", ["Time is up!"])
end
Key things to note
- The first argument needs to be a valid UUID of an existing stack on the same number.
- If a stack is scheduled to run after more than 24 hours, it should start by sending a message template. WhatsApp requires you to start a conversation with a template if the last message from the user is older than 24 hours.
When a schedule stack executes, it interrupts any other stack that is running at that time for the user.
Integrating with ML models hosted on Huggingface.co
Often a user experience can be improved by using a machine learning model to infer the meaning of the submitted request. A convenient way to do this is to use models hosted on Huggingface.co.
Here is an example using the hf_connect
and the hf_infer
functions to interact with Huggingface APIs.
Setting up a connection to a model
In the following card we setup a connection to a model hosted on Huggingface and store the reference to it in a variable called connection
.
card Start, then: HFCard do
connection =
hf_connect(
"michellejieli/NSFW_text_classifier",
"<- insert your Hugggingface API token here ->"
)
query = ask("What is your question?")
end
In the example above we are using an freely available NSFW classification model called michellejieli/NSFW_text_classifier
. This can be replaced with a model of your liking. If you have a model running on a custom Huggingface domain you can refer to it by URL:
hf_connect(
"https://my-custom.endpoints.huggingface.cloud/the-model",
"<- insert your Hugggingface API token here ->"
)
Calling the Inference API with the model
In the following card we use the hf_infer()
function to submit the query to the model being referred to in the connection
variable.
As per the model's documentation at Huggingface the response from the model has the following shape:
[
[
{
"label": "SFW",
"score": 0.9408659934997559
},
{
"label": "NSFW",
"score": 0.05913396179676056
}
]
]
Processing the model's results
The model in this example returns a list of results and we need to pick the result with the higest score. The model may already always return the highest scoring label as the first value in the list but given we're not sure about that we apply sorting in the stack anyway.
card HFCard, then: HFResult do
# This model returns a list with lists, we're wanting to read the first list item
# as that has the list of scorings for the given query
all_responses = hf_infer(connection, query)[0]
# Sort with descending score
sorted_responses = sort_by(all_responses, &(&1.score * -1))
# Get the first item from the sorted responses, this is the one with the highest score
top_response = sorted_responses[0]
end
Turn calls the Huggingface API with the wait_for_model
parameter set to true
. If the model in question takes some time to startup then the first interactions may hit a timeout. Note that the default timeout for Huggingface models is 5 seconds. This is currently not configurable.
Using the results to make an informed decision
Next we use the result stored in the top_response
variable to determine what
to do with the original query. In this case, because this is a demo, we're just
returning the label and the score. In your applications you'll likely want to modify this to do something that suits your usecase and requirements.
card HFResult when top_response.label == "NSFW" do
text("This was classified as NSFW with a score of @top_response.score")
end
card HFResult when top_response.label == "SFW" do
text("This was classified as SFW with a score of @top_response.score")
end
card HFResult do
text("Huggingface returned something unexpected: @all_responses ")
end
Assigning labels to messages
When handling a pivotal moment in a stack, say a question received a specific response, it can be useful to add a label to a message. This allows it to be included in collections set up specifically to track messages with one or more labels applied.
Adding a label can be achieved with the add_label()
function.
card AddLabel do
add_label("a plain label")
add_label("a label with metadata", extra: "label assigned at @now()")
end
If the label doesn't exist yet, it will be created. In some use cases it can useful to allocate extra metadata about the label. These can be added as key-value pairs as the second argument to the add_label()
function. This metadata is stored on the assignment between the message and the label. If one retrieves the labels assigned to a message via the API, the metadata will be available there.
The label is always applied to the last message received from the user.
Assigning chats to an operator
Even in the most automated services, some questions simply need the attention of a human being. Stacks allow a chat to be assigned to an account within the Turn organisation the number is part of. Like labels, this assignment can be used to create collections that require the attention of a specific operator.
Assigning a chat to an operator can be achieved with the assign_chat_to()
function.
card AssignChat do
assign_chat_to("user@example.org")
end
This will only work if the email address is of a known account within the number's organisation. If the email address is not recognised, it will clear any chat assignment.
To explicitly remove an operator assignment from a chat use the unassign_chat()
function:
unassign_chat()
Logging in the Stacks Simulator
Sometimes we want to be able to understand and debug the behavior of our stacks without adding messages to the chat. The Stacks Simulator allows us to do this by logging messages to the simulator with the log
function.
A simple example where we just want to add text.
card TextAndLogMessage do
text("Hello this is my first text.")
log("a simple message")
text("Hello this is my second text.")
end
However, you can also use it to log more complicated data structures, such as the dictionary below.
You could also log structures such as @contact
, made available within the chat.
card LogData do
text("@params.items.greeting!")
log("@params")
log("@contact")
end
Will result in the following:
You need to pass in a string. If you want to evaluate a more complicated structure like
contacts
, you need to use an expression - so uselog("@contact")
, notlog(contact)
. The Stack will highlight this issue as an error if you attempt to do this.log
currently only works within the Stacks simulator. They will not affect interactions when using a Stack directly via WhatsApp.Logs are temporary. They will disappear each time you start a new session with the Stacks simulator
Advanced functions
Interaction timeout
Stacks have a timeout value. The default is 300 seconds (equating to 5 minutes). If a user takes longer that 5 minutes to respond to a request for input (for example a question from ask()
) the stack will expire. This means that it won't respond as expected if the user comes back after more than 5 minutes.
You can change the timeout to any value that makes sense to you. Timeout values need to be specified in seconds.
Syntax
The timeout is defined with the interaction_timeout
optional stack
parameter.
stack MyStack, interaction_timeout: 20 do
...
end
Example
The following example gives a user 10 seconds to reply in order to win. If the user takes longer than 10 seconds the stack has expired and the user did not win.
The user replied within 10 seconds.
The user took longer than 10 seconds to reply and stack expired.
interaction_timeout(10)
card Card, then: Win do
ask("You have 10 seconds to reply to win!")
end
card Win do
text("congrats! you replied on time")
end
Key things to note
- Timeout values need to be specified in seconds.
- The default timeout is 300 seconds (equating to 5 minutes).