Skip to contentSkip to navigationSkip to topbar
Rate this page:
On this page

Manage application state with cookies


Due to the ephemeral nature of Functions, application state for purely serverless apps has previously been difficult to manage, or required storing such information in a remote database. Luckily, with access to cookies with Runtime Handler version 1.2.1 and later, you can now maintain limited state in your apps through cookies!

Let's create a Function named state that leverages per-phone number cookies to store some application state, just like you would with a more traditional, server-based solution! Use the following directions to create a Service and your state Function:


Create and host a Function

create-and-host-a-function page anchor

In order to run any of the following examples, you will first need to create a Function into which you can paste the example code. You can create a Function using the Twilio Console or the Serverless Toolkit as explained below:

ConsoleServerless Toolkit

If you prefer a UI-driven approach, creating and deploying a Function can be done entirely using the Twilio Console and the following steps:

  1. Log in to the Twilio Console and navigate to the Functions tab(link takes you to an external page) . If you need an account, you can sign up for a free Twilio account here(link takes you to an external page) !
  2. Functions are contained within Services . Create a Service by clicking the Create Service(link takes you to an external page) button and providing a name such as test-function .
  3. Once you've been redirected to the new Service, click the Add + button and select Add Function from the dropdown.
  4. This will create a new Protected Function for you with the option to rename it. The name of the file will be path it is accessed from.
  5. Copy any one of the example code snippets from this page that you want to experiment with, and paste the code into your newly created Function. You can quickly switch examples by using the dropdown menu of the code rail.
  6. Click Save to save your Function's contents.
  7. Click Deploy All to build and deploy the Function. After a short delay, your Function will be accessible from: https://<service-name>-<random-characters>-<optional-domain-suffix>.twil.io/<function-path>
    For example: test-function-3548.twil.io/hello-world .

Your Function is now ready to be invoked by HTTP requests, set as the webhook of a Twilio phone number, invoked by a Twilio Studio Run Function Widget, and more!

Add counter state to an SMS response

add-counter-state-to-an-sms-response page anchor

_30
exports.handler = (context, event, callback) => {
_30
// Initialize a new Response and some TwiML
_30
const response = new Twilio.Response();
_30
const twiml = new Twilio.twiml.MessagingResponse();
_30
_30
// Cookies are accessed by name from the event.request.cookies object
_30
// If the user doesn't have a count yet, initialize it to zero. Cookies are
_30
// always strings, so you'll need to convert the count to a number
_30
const count = Number(event.request.cookies.count) || 0;
_30
_30
// Return a dynamic message based on if this is the first message or not
_30
const message =
_30
count > 0
_30
? `Your current count is ${count}`
_30
: 'Hello, thanks for the new message!';
_30
_30
twiml.message(message);
_30
_30
response
_30
// Add the stringified TwiML to the response body
_30
.setBody(twiml.toString())
_30
// Since we're returning TwiML, the content type must be XML
_30
.appendHeader('Content-Type', 'text/xml')
_30
// You can increment the count state for the next message, or any other
_30
// operation that makes sense for your application's needs. Remember
_30
// that cookies are always stored as strings
_30
.setCookie('count', (count + 1).toString());
_30
_30
return callback(null, response);
_30
};

For Twilio SMS, cookies are scoped to the "conversation" between two parties — you can have a unique cookie for each To/From phone number pair. For example, you can store a unique cookie for any messages sent between 415-555-2222 (your number, for example) and 415-555-1111 (the phone number your Function is a webhook for), which will be different from the cookie used between 415-555-3333 and 415-555-1111.

The code here is accepting an incoming Message webhook request, and checking for an incoming cookie named count. If that cookie is not present, count is initialized to 0, the user message is formatted to indicate the start of a conversation, and the count is incremented then set as a cookie along with the response to the sender. If count is already present, its value is included in the message, incremented, and set so that subsequent messages can continue to store the ever-increasing value of count.

To test this and observe your stateless Function managing to track state with cookies, you'll need to set your deployed state Function as the webhook for your Twilio phone number, as shown next.

(warning)

Warning

Cookies created in this specific scenario(link takes you to an external page) (Twilio forwarding SMS messages to your Function or server) are limited to a maximum lifetime of four hours, so if a conversation remains idle for more than four hours, it will be automatically cleared. If you require longer-lasting state, you will need to store it in an external source such as a database.

In any other scenario, cookies set by your Function are only subject to the usual limitations.


Set a Function as a webhook

set-a-function-as-a-webhook page anchor

In order for your Function to react to incoming SMS and/or voice calls, it must be set as a webhook for your Twilio number. There are a variety of methods to set a Function as a webhook, as detailed below:

Twilio ConsoleTwilio CLITwilio SDKs

You can use the Twilio Console(link takes you to an external page) UI as a straightforward way of connecting your Function as a webhook:

  1. Log in to the Twilio Console's Phone Numbers page(link takes you to an external page) .
  2. Click on the phone number you'd like to have connected to your Function.
  3. If you want the Function to respond to incoming SMS, find the A Message Comes In option under Messaging . If you want the Function to respond to Voice, find the A Call Comes In option under Voice & Fax .
  4. Select Function from the A Message Comes In or A Call Comes In dropdown.
  5. Select the Service that you are using, then the Environment (this will default to ui unless you have created custom domains ), and finally Function Path of your Function from the respective dropdown menus.
    Connect a Function as a Messaging webhook using the Function dropdowns.
  • Alternatively, you could select Webhook instead of Function, and directly paste in the full URL of the Function.
    Setting a Function as a Messaging webhook using the webhook dropdown option.
  1. Click the Save button.

Now that your Twilio phone number is directing incoming SMS messages to your Function, try sending a short message to your Twilio phone number.

You will receive an initial response of Hello, thanks for the new message!, and any subsequent messages you send will then receive a response of Your current count is 1, Your current count is 2, and so on.


Cookies support several attributes(link takes you to an external page), which allow you to define aspects such as duration, security, and more. You can set these using the third parameter to setCookie. For example, given the existing call:


_10
response.setCookie('count', (count + 1).toString());

You could modify the count cookie to last for a maximum of 30 minutes (1800 seconds) by setting the Max-Age attribute like so:


_10
response.setCookie('count', (count + 1).toString(), ['Max-Age=1800']);


By default, session cookies persisted by Twilio SMS only last for four hours at most, and you cannot exceed this limit. However, it's perfectly valid to remove a cookie at any time to fit your application's needs.

For example, you could clear the count from the previous example once a condition is met, as shown in this sample:

Clear counter state from an SMS conversation

clear-counter-state-from-an-sms-conversation page anchor

_34
exports.handler = (context, event, callback) => {
_34
// Initialize a new Response and some TwiML
_34
const response = new Twilio.Response();
_34
const twiml = new Twilio.twiml.MessagingResponse();
_34
_34
// Since we're returning TwiML, the content type must be XML
_34
response.appendHeader('Content-Type', 'text/xml');
_34
_34
// Cookies are accessed by name from the event.request.cookies object
_34
// If the user doesn't have a count yet, initialize it to zero. Cookies are
_34
// always strings, so you'll need to convert the count to a number
_34
const count = Number(event.request.cookies.count) || 0;
_34
_34
if (count > 5) {
_34
twiml.message("You've reached the end of the count!");
_34
// In this case we want to remove the count and let the user begin
_34
// a new conversation
_34
response.setBody(twiml.toString()).removeCookie('count');
_34
// Use an early return to respond to the user and avoid other logic paths
_34
return callback(null, response);
_34
}
_34
_34
// Return a dynamic message based on if this is the first message or not
_34
const message =
_34
count > 0
_34
? `Your current count is ${count}`
_34
: 'Hello, thanks for the new message! Message again to see your count update.';
_34
_34
twiml.message(message);
_34
_34
response.setBody(twiml.toString()).setCookie('count', (count + 1).toString());
_34
_34
return callback(null, response);
_34
};


If you save and deploy this new code instead, you should have a very similar interaction with your Twilio phone number. After sending a message, you will receive an initial response, and any subsequent messages you send will then receive a response of Your current count is 1, Your current count is 2, and so on.

The difference is that after reaching a count of five and sending another message, you'll receive You've reached the end of the count!. If you try to message again, you'll find yourself in a completely new conversation. This is a handy way to end interactions, such as if your application has successfully helped a customer, or if your application is a game that the user has won or lost.

(warning)

Warning

These examples demonstrate adding a single state value as a cookie, but you are free to add more to support your application needs!

Keep in mind, there are limitations on how many cookies can be set, how large they can be, and how long they can persist until expiring.

(information)

Info

Curious about what else you can build by using cookies to add statefulness to your Functions? Check out this blog article to see how you can build your own Wordle clone purely with Functions and Assets!


Rate this page: