
This tutorial is part of the Quick & Dirty series for developing a custom Alexa skill called My Zoo.
Estimated time: 10 – 15 minutes
No programming experience necessary
Overview
With this tutorial, you’ll learn to use AWS DynamoDB to store and retrieve persistent data.
What is persistent data?
It’s nice when Alexa remembers stuff about a user’s previous interaction with the skill. Persistent data helps Alexa remember that stuff. So, let’s update My Zoo to remind a returning user what animal they heard last time they visited the zoo!
A couple notes …
This tutorial assumes you have not yet added persistent data to your My Zoo skill. The previous post of this series (Add Persistent Data on Amazon S3 to a Custom Alexa Skill) added persistent data using S3. If you followed the S3 tutorial and now wish to use DynamoDB instead, you’ll need to make small adjustments to instructions here.
Alexa Development Console (ADC)-hosted skills, like My Zoo, along with its DynamoDB data storage, is limited in its free-ness. If you publish a skill and it becomes popular, you may need to move the skill to your own AWS account. But we’re not launching My Zoo for public use, so don’t worry about that right now!
Prerequisites
- an Amazon Developer account, click here to create one (it’s free)
The instructions in this post are applicable to any custom Alexa skill coded with Python. If you wish to join-in on the My Zoo fun, complete these 3 mini-tutorials first (total estimated time: 25 – 40 minutes):
Ready? Let’s do it!
Use Persistent Data with DynamoDB
Step 1: Add Code Requirements
First, we need to do programmer-techie stuff with code requirements. If you’re not a coder, no worries, just follow these steps:
- Log into the Alexa developer console and open My Zoo.
- Click Code on the top menu bar.
- Double-click the requirements.txt in the left column. The file will open in the editor window to the right.

- Add this line:
ask-sdk-dynamodb-persistence-adapter==1.15.0
The requirements.txt file should now look like this:

- Click Save.
Step 2: Apply Code Requirements
- Double-click the lambda_function.py in the left column. Or, if the file is already open, click the lambda_function.py tab above the editor window.
- Find this line in the editor window:
import ask_sdk_core.utils as ask_utils
- Create a new line below it, and add this code:
# import persistence adapter import os import boto3 from ask_sdk_core.skill_builder import CustomSkillBuilder from ask_sdk_dynamodb.adapter import DynamoDbAdapter # initialize persistence adapter ddb_region = os.environ.get('DYNAMODB_PERSISTENCE_REGION') ddb_table_name = os.environ.get('DYNAMODB_PERSISTENCE_TABLE_NAME') ddb_resource = boto3.resource('dynamodb', region_name=ddb_region) dynamodb_adapter = DynamoDbAdapter(table_name=ddb_table_name, create_table=False, dynamodb_resource=ddb_resource)
- If this line of code exists, delete it:
from ask_sdk_core.skill_builder import SkillBuilder
The top section of code should now look like this:
# -*- coding: utf-8 -*-
#This sample demonstrates handling intents from an Alexa skill using the Alexa Skills Kit SDK for Python.
# Please visit https://alexa.design/cookbook for additional examples on implementing slots, dialog management,
# session persistence, api calls, and more.
# This sample is built using the handler classes approach in skill builder.
import logging
import ask_sdk_core.utils as ask_utils
# import persistence adapter
import os
import boto3
from ask_sdk_core.skill_builder import CustomSkillBuilder
from ask_sdk_dynamodb.adapter import DynamoDbAdapter
# initialize persistence adapter
ddb_region = os.environ.get('DYNAMODB_PERSISTENCE_REGION')
ddb_table_name = os.environ.get('DYNAMODB_PERSISTENCE_TABLE_NAME')
ddb_resource = boto3.resource('dynamodb', region_name=ddb_region)
dynamodb_adapter = DynamoDbAdapter(table_name=ddb_table_name, create_table=False, dynamodb_resource=ddb_resource)
from ask_sdk_core.dispatch_components import AbstractRequestHandler
from ask_sdk_core.dispatch_components import AbstractExceptionHandler
from ask_sdk_core.handler_input import HandlerInput
from ask_sdk_model import Response
logger = logging.getLogger(name)
logger.setLevel(logging.INFO)
- Scroll to the bottom of the file and find either this line:
sb = SkillBuilder()
- Replace it with this line of code:
sb = CustomSkillBuilder(persistence_adapter = dynamodb_adapter)
- Click Save.
Step 3: Save Data
Note: If you followed the tutorial Add Persistent Data to a Custom Alexa Skill using Amazon S3, you can skip Steps 3 and 4 because the coding to save and retrieve data is exactly the same, whether you do it with S3 or DynamoDB.
Next, update the CaptureAnimal intent logic created in Create a Custom Alexa Skill, Part 3 (Code an Intent) to store the most recent animal/sound pair retrieved.
A reminder about Python: formatting matters. Make sure lines are indented as shown.
- Find the CaptureAnimal intent code block by searching for this line:
class CaptureAnimalIntentHandler(AbstractRequestHandler):
- Scroll down the code block and create a new line after this one:
speak_output = animal + 's say ' + sound
- Copy/paste this code:
animal_attributes = { 'animal': animal, 'sound': sound } attributes_manager = handler_input.attributes_manager attributes_manager.persistent_attributes = animal_attributes attributes_manager.save_persistent_attributes()
Make sure attributes_manager ...
lines up with animal_attributes ...
.
The entire CaptureAnimalIntentHandler should now look like this:
class CaptureAnimalIntentHandler(AbstractRequestHandler):
"""Handler for CaptureAnimal Intent."""
def can_handle(self, handler_input):
# type: (HandlerInput) -> bool
return ask_utils.is_intent_name("CaptureAnimal")(handler_input)
def handle(self, handler_input):
# type: (HandlerInput) -> Response
animal = handler_input.request_envelope.request.intent.slots["animal"].value
sounds = {
'bat': 'screech screech',
'bee': 'buzzzz buzzzz',
'cat': 'meow meow',
'chicken': 'cluck cluck',
'cow': 'mooooo',
'dog': 'bark bark',
'human': 'hello',
'lion': 'roar',
'monkey': 'chitter chatter',
'pig': 'oink oink',
'snake': 'hiss rattle hiss',
'zebra': 'whinny'
}
try:
sound = sounds[animal]
speak_output = animal + 's say ' + sound
animal_attributes = {
'animal': animal,
'sound': sound
}
attributes_manager = handler_input.attributes_manager
attributes_manager.persistent_attributes = animal_attributes
attributes_manager.save_persistent_attributes()
except:
speak_output = "I have not learned that animal's sound yet."
prompt = " Try another one!"
speak_output = speak_output + prompt
return (
handler_input.response_builder
.speak(speak_output)
.response
)
- Click Save.
Now, whenever a user asks for an animal and Alexa returns its sound, the last animal/sound pair will be saved to the DynamoDB database.
Step 4: Retrieve Data
Note: If you followed the tutorial Add Persistent Data to a Custom Alexa Skill using Amazon S3, you can skip this Step because the coding to save and retrieve data is exactly the same, whether you do it with S3 or DynamoDB.
Add a returning user’s last animal/sound pair to their welcome message. If the user is new, stick with the standard “Welcome to My Zoo…” message.
- Find the LaunchRequest intent code by searching for this:
class LaunchRequestHandler(AbstractRequestHandler):
- Find this line:
speak_output = "Welcome to My Zoo, I make animal sounds! What animal do you want to hear?"
and replace it with this block of code:
# extract persistent attributes, if they exist attr = handler_input.attributes_manager.persistent_attributes attributes_exist = ('animal' in attr and 'sound' in attr) if attributes_exist: animal = attr['animal'] sound = attr['sound'] speak_output = "Welcome back to My Zoo! \ Last time you heard the {animal} {sound}. \ What animal do you want to hear now?" \ .format(animal=animal, sound=sound) else: speak_output = "Welcome to My Zoo, I make animal sounds! What animal do you want to hear?"
The entire LaunchRequestHandler should now look like this:
class LaunchRequestHandler(AbstractRequestHandler):
"""Handler for Skill Launch."""
def can_handle(self, handler_input):
# type: (HandlerInput) -> bool
return ask_utils.is_request_type("LaunchRequest")(handler_input)
def handle(self, handler_input):
# type: (HandlerInput) -> Response
# extract persistent attributes, if they exist
attr = handler_input.attributes_manager.persistent_attributes
attributes_exist = ('animal' in attr and 'sound' in attr)
if attributes_exist:
animal = attr['animal']
sound = attr['sound']
speak_output = "Welcome back to My Zoo! \
Last time you heard the {animal} {sound}. \
What animal do you want to hear now?"\
.format(animal=animal, sound=sound)
else:
speak_output = "Welcome to My Zoo, I make animal sounds! What animal do you want to hear?"
reprompt = "I do not know that one. What other animal do you want to hear?"
return (
handler_input.response_builder
.speak(speak_output)
.ask(reprompt)
.response
)
- Click Save.
- Click Deploy, wait for it to finish.
Step 5: Test
The first time you test after adding persistent data, Alexa won’t have any data to pull from, so you’ll be welcomed as a new user instead of a returning user.
- Click Test.
- Enter
my zoo
. If you already have a separate browser open for testing, remember to refresh it first. You should see/hear the normal “Welcome to My Zoo, …” - Enter an animal that exists in our little database, for example
lion
. - Enter
bye
to close out the session. - Enter
my zoo
again. Verify you’re getting the returning-user welcome-back message “Welcome back to My Zoo! Last time you heard …”.

Pretty cool, huh?!
Step 6: (optional): Delete Persistent Data
In order to test the “welcome” message for new users, you’ll need to delete persistent data (otherwise, you’ll always hear the “welcome back” message)
Delete persistent data by using the AWS DynamoDB management screen (it’s easy to do, I promise!) Here goes:
- Click Code on the top menu bar.
- Between the top menu bar and the editor window, notice a line of icons.

- Find DynamoDB Database and click it.
- A new browser window will open to the Amazon Web Services (AWS) DynamoDB management console.
Persistent data tables (with really long names) are listed in the middle column. If you have multiple skills in your ADC account, there’ll be a different table for each. Since you came to the AWS DynamoDB management page from your ADC skill, the appropriate table will already be selected for you.
The right-hand column displays the rows in your persistent table. A row is created for each user session.
There are two columns in the table: the id (user_id assigned by Alexa), and attributes (which you created … they should look familiar!)

- Click the box next to id for the row to be deleted.
- Click Actions button.
- Click Delete to confirm.
- You can safely close the AWS DynamoDB browser window.
Now if you go back and test again, you should see the new user welcome.
Conclusion
Congratulations! You now know how to save and retrieve persistent data from an AWS DynamoDB database. Knowing how to do this will open many options for extending the features of your custom Alexa skills.
As always, thank you for visiting my blog. If you have corrections or suggestions for this tutorial series, please add a comment below.
Leave a Reply