One of our recent skill recipes explains how you can use session attributes to enable repeat responses in your Alexa skill. We used session attributes to remember our skill's last response to the customer; when the customer asked Alexa to repeat a response, we could fetch it from the session attributes and respond back with it. While we walked through the Node.js code you can use to do that, we didn’t get the chance to explore how session attributes work.
Here we dive deeper into session attributes so you can use them more effectively to improve the voice experience for your customers.
An Alexa session for your skill starts when the customer begins interacting with your skill by using its invocation name, and ends when the customer asks Alexa to stop (AMAZON.StopIntent), cancel (AMAZON.CancelIntent), or fails to respond to a re-prompt from the skill.
Let’s look at this in action to understand how this works:
Customer: Alexa, ask space facts to tell me a fact <Session Starts>
Alexa: The Sun contains 99.86% of the mass in the Solar System. Would you like another fact?
Customer: Yes
Alexa: Jupiter has the shortest day of all the planets. Would you like another fact?
Customer: No (AMAZON.StopIntent)
Alexa: Goodbye <Session Ends>
If the customer launches the skill again, a new session will start. Now, that we understand when a session starts and ends, let’s move on to understanding session attributes.
As you can see in the multi-turn conversation above, Alexa goes back and forth engaging in a conversation with the customer. It’s important to remember that at each turn of this conversation your skill sends or receives a JSON object, making this a back-and-forth request/response loop between the Alexa service and your web service. Since each turn kicks off a new request/response loop, this means that if we want to temporarily save the "last speech" of our skill, we can't rely on variables set in one Lambda invocation being still set in subsequent executions.
This is where session attributes come to our rescue. You can manage state within the context of your Alexa session using the session object in the request JSON that’s sent to your skill. All requests (LaunchRequest, IntentRequest, and SessionEndedRequest) that are sent to your skill include a session object in the JSON definition.
We are essentially sending the attributes we may need in the next turn back to Alexa as part of the JSON response. Alexa will then include these as part of the next JSON request, ready for us to use again.
Let’s revisit our skill recipe to see how this works. Here’s the kind of conversation we want to enable by using AMAZON.RepeatIntent and session attributes:
Customer: Alexa, ask space facts to tell me a fact <Session Starts, Intent: GetNewFactIntent>
Alexa: Jupiter has the shortest day of all the planets. Would you like another fact? <Save this fact as a Session Attribute>
Customer: Repeat that <Intent: AMAZON.RepeatIntent>
Alexa: Jupiter has the shortest day of all the planets. Would you like another fact? <Retrieve the last fact from Session Attribute>
Customer: No <Intent: AMAZON.NoIntent>
Alexa: Goodbye <Session Ends>
The customer launches your skill by saying, “Alexa, ask space facts to give me a fact.” Alexa sends the following JSON request to our skill. As you can see, there’s a session object in the JSON request our skill received, but there are no attributes yet.
Here's the JSON request received by our skill:
{
"version": "1.0",
"session": {
"new": true,
"sessionId": "amzn1.echo-api.session.<value>",
"application": {
"applicationId": "amzn1.ask.skill.<value>"
},
"user": {
"userId": "amzn1.ask.account.<value>"
}
},
. . .
. . .
. . .
"request": {
"type": "IntentRequest",
"requestId": "amzn1.echo-api.request.<value>",
"timestamp": "2018-03-22T15:25:51Z",
"locale": "en-US",
"intent": {
"name": "GetNewFactIntent",
"confirmationStatus": "NONE"
}
}
}
Our skill sends the following JSON response back to Alexa, which includes the speech that Alexa should respond back (outputSpeech) with. It also includes a new key/value pair of lastSpeech inside the sessionAttributes property in our response. This session attribute will then be passed back to us in the next JSON request. Any session-level data that you need to track (in our case, "lastSpeech”) can be sent with your response JSON object inside the sessionAttributes property as key/value pairs, and it will be available to our skill in the next JSON request.
Here's the JSON response sent back by our skill:
{
"body": {
"version": "1.0",
"response": {
"outputSpeech": {
"type": "SSML",
"ssml": "<speak> Here's your fact: Jupiter has the shortest day of all the planets. Would you like another fact? </speak>"
},
"card": {
"type": "Simple",
"title": "Space Facts",
"content": "Jupiter has the shortest day of all the planets"
},
"reprompt": {
"outputSpeech": {
"type": "SSML",
"ssml": "<speak> Would you like another fact? </speak>"
}
},
"shouldEndSession": false
},
"sessionAttributes": {
"lastSpeech": "Jupiter has the shortest day of all the planets"
},
"userAgent": "ask-nodejs/1.0.25 Node/v6.10.3"
}
}
In the last response, our skill responded back with something like "Jupiter has the shortest day of all the planets. Would you like another fact?” This prompted the customer to either say yes or no. The customer, of course, didn’t hear that, and wants Alexa to repeat it by saying “repeat that please.” Alexa matches this to our AMAZON.RepeatIntent, and sends the following JSON to our skill, this time including the attributes object, which contains “lastSpeech” property.
As you can see, the JSON request sent to our skill this time includes the lastSpeech session attribute we set in the last turn inside the attributes property. All we need to do now is parse this JSON, and use the lastSpeech key/value pair to respond back with the last fact.
Here's the JSON request received by our skill:
{
"version": "1.0",
"session": {
"new": false,
"sessionId": "amzn1.echo-api.session.<value>",
"application": {
"applicationId": "amzn1.ask.skill.<value>"
},
"attributes": {
"lastSpeech": "Jupiter has the shortest day of all the planets"
},
"user": {
"userId": "amzn1.ask.account.<value>"
}
},
. . .
. . .
. . .
"request": {
"type": "IntentRequest",
"requestId": "amzn1.echo-api.request.<value>",
"timestamp": "2018-03-22T13:37:36Z",
"locale": "en-US",
"intent": {
"name": "AMAZON.RepeatIntent",
"confirmationStatus": "NONE"
}
}
}
Now that we have access to the last response through the session attributes sent back to us, we can access that to create our speech response back.
Here's the JSON response sent back by our skill:
{
"body": {
"version": "1.0",
"response": {
"outputSpeech": {
"type": "SSML",
"ssml": "<speak> Jupiter has the shortest day of all the planets. Would you like another fact?</speak>"
},
"reprompt": {
"outputSpeech": {
"type": "SSML",
"ssml": "<speak> Would you like another fact? </speak>"
}
},
"shouldEndSession": false
},
"sessionAttributes": {
"lastSpeech": "Jupiter has the shortest day of all the planets"
},
"userAgent": "ask-nodejs/1.0.25 Node/v6.10.3"
}
}
Using session attributes to repeat the last response is one of the many ways you can use them to improve the voice experience. You could also use session attributes to create a context sensitive “Help” for your customers. Rather than delivering the same help message, you could create an intent history by assigning the last intent to an attribute called “lastIntent" and then using that to deliver context sensitive help messages. You could even use this “lastIntent” attribute to suggest a valid slot in case the slot is missing or not a match.
Bring your big idea to life with Alexa and earn perks through our tiered rewards system. US developers, publish a skill in May and earn an Alexa developer backpack. If 1,000 customers use your skill in its first 30 days in the Alexa Skills Store, you will also earn a free Echo Plus to help you make Alexa even smarter. If you're not in the US, check out our promotions in the UK, Germany, and India. Learn more about our promotion and start building today.