Use DynamoDB for Data Persistence with Your Alexa-hosted Skill


When you create an Alexa-hosted skill, you get access to an Amazon DynamoDB table for persisting data. Your DynamoDB table is part of the Amazon Web Services (AWS) free tier that provides storage free of charge within the usage limits. All user data stored in your DynamoDB table is fully encrypted at rest with encryption keys managed by AWS Key Management Service (KMS). For details, see DynamoDB Encryption at Rest.

The ASK SDK for Node.js and the ASK SDK for Python each include an adapter to persist data to DynamoDB.

For an overview of hosted skills, see About Alexa-hosted Skills. To provision DynamoDB resources close to your skill users to reduce the perceived latency of your skill, see Hosting your skill resources in different AWS Regions.

Use DynamoDB to persistent session data

When you create an Alexa-hosted skill, Alexa creates a DynamoDB table, named with a UUID-formatted string. Use the table, as needed, to store skill attributes so that you can continue the skill on the next invocation.

Each item in the table has a unique identifier, called a primary key, that distinguishes the item from others items in the table. For the Alexa-hosted DynamoDB table, the primary key is the user ID from the context.System.user.userId property in standard requests from Alexa. You define the attributes for each user entry in the database. Each attribute is a data element that your skill wants to persist across sessions, such as the last question answered in a trivia game.

DynamoDB uses the user ID value as the partition key to determine the partition in which to store the item. As a result, the DynamoDB service stores each user's data in a separate partition to allow for scalability and efficient retrieval. For more details about the structure of DynamoDB, see Core components of Amazon DynamoDB.

In your skill code, you can configure the Alexa Skills Kit (ASK) SDK PersistenceAdapter to use the DynamoDB table to persist attributes for each user. Then, use the persistentAttributes object to store and retrieve any attributes that you want to persist across sessions.

Alexa stores the DynamoDB table name and region in the following environment variables that you can access from your skill:

  • DYNAMODB_PERSISTENCE_TABLE_NAME
  • DYNAMODB_PERSISTENCE_REGION

View your Amazon DynamoDB table

Each Alexa-hosted skill gets one DynamoDB table to use to persist data.

To see the Amazon DynamoDB table for your Alexa-hosted skill

  1. Open the Alexa developer console and log in.
  2. In the list of your skills, click the name of the skill that you want to view.
  3. Click the Code tab.
  4. In the toolbar, click the Database icon to open the AWS DynamoDB console.
    Your Amazon DynamoDB table appears.

Persist data with Node.js

Use the ASK SDK for Node.js to persist attributes in the DynamoDB table.

To persist data with Node.js

  1. First add the following dependency in the dependencies section of your package.json file:

    "ask-sdk": "^2.6.0"
    "aws-sdk": "2.637.0"
    "ask-sdk-dynamodb-persistence-adapter": "^2.9.0"
    
  2. Then, in your index.js file, add the code to import the ASK persistence adapter.

    const AWS = require("aws-sdk");
    const ddbAdapter = require('ask-sdk-dynamodb-persistence-adapter');
    
  3. Add the SessionEndedRequestHandler request handler to your skill builder request handlers.

    exports.handler = Alexa.SkillBuilders.custom()
        .addRequestHandlers(
            LaunchRequestHandler,
            // Other request handlers
            SessionEndedRequestHandler
        )
        .addErrorHandlers(ErrorHandler)
        .withPersistenceAdapter(
            new ddbAdapter.DynamoDbPersistenceAdapter({
                tableName: process.env.DYNAMODB_PERSISTENCE_TABLE_NAME,
                createTable: false,
                dynamoDBClient: new AWS.DynamoDB({apiVersion: 'latest', region: process.env.DYNAMODB_PERSISTENCE_REGION})
            })
        )
        .lambda();
    
  4. Add a handler to save attributes. By default, the attributesManager uses the userId as the primary key.

    async handle(handlerInput)
    {
        const attributesManager = handlerInput.attributesManager;
        let attributes = {"counter":10};
    
        attributesManager.setPersistentAttributes(attributes);
        await attributesManager.savePersistentAttributes();
    
        let speechOutput = `Hi there, Hello World! Your saved counter is ${attributes.counter}`;
    
        return handlerInput.responseBuilder
            .speak(speechOutput)
            .getResponse();
    }
    
  5. Add a handler to read attributes.

    async handle(handlerInput){
    
        const attributesManager = handlerInput.attributesManager;
        const attributes = await attributesManager.getPersistentAttributes() || {};
        console.log('attributes is: ', attributes);
    
        const counter = attributes.hasOwnProperty('counter')? attributes.counter : 0;
    
        let speechOutput = `Hi there, Hello World! Your counter is ${counter}`;
    
        return handlerInput.responseBuilder
            .speak(speechOutput)
            .getResponse();
    }
    

Persist data with Python

Use the ASK SDK for Python to persist attributes in the DynamoDB table.

To persist data with Python

  1. First add the following dependency in the dependencies section of your requirements.txt file:

    boto3==1.9.216
    ask-sdk-core==1.11.0
    ask-sdk-dynamodb-persistence-adapter==1.15.0
    
  2. Then, in your lambda_function.py file, add the code. Import the ASK persistence adapter.

    import os
    import boto3
    
    from ask_sdk_core.skill_builder import CustomSkillBuilder
    from ask_sdk_dynamodb.adapter import DynamoDbAdapter
    
  3. Initialize the 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)
    
  4. Add the SessionEndedRequestHandler request handler to your skill builder request handlers.

    sb = CustomSkillBuilder(persistence_adapter = dynamodb_adapter)
    
    sb.add_request_handler(LaunchRequestHandler())
    sb.add_request_handler(CancelOrStopIntentHandler())
    sb.add_request_handler(SessionEndedRequestHandler())
    #
    # Other request handlers
    #
    sb.add_exception_handler(CatchAllExceptionHandler())
    
    lambda_handler = sb.lambda_handler()
    
  5. Add a handler to save attributes. By default, the attributes_manager uses the userId as the primary key.

    def handle(self, handler_input):
        # type: (HandlerInput) -> Response
        attr = handler_input.attributes_manager.persistent_attributes
        if not attr:
            attr['counter'] = 0
            attr['state'] = 'ENDED'
    
        handler_input.attributes_manager.session_attributes = attr
    
        handler_input.attributes_manager.save_persistent_attributes()
        speak_output = ("Welcome back. Your saved counter is {}. You can say Hello or Help?".format(attr["counter"]))
        reprompt = "Say hello or help to start."
        return (
            handler_input.response_builder
                .speak(speak_output)
                .ask(reprompt)
                .response
        )
    
  6. Add a handler to read attributes.

    def handle(self, handler_input):
        # type: (HandlerInput) -> Response
        session_attr = handler_input.attributes_manager.session_attributes
        session_attr['state'] = "STARTED"
        session_attr["counter"] += 1
        handler_input.attributes_manager.persistent_attributes = session_attr
        handler_input.attributes_manager.save_persistent_attributes()
    
        speak_output = ("Hi there, Hello World! Your saved counter is {}.".format(session_attr["counter"]))
        return (
            handler_input.response_builder
                .speak(speak_output)
                # .ask("add a reprompt if you want to keep the session open for the user to respond")
                .response
        )
    
  7. (Optional) Add a handler to delete attributes.

    def handle(self, handler_input):
        # type: (HandlerInput) -> Response
        session_attr = handler_input.attributes_manager.session_attributes
        session_attr['state'] = "ENDED"
    
        speak_output = ("Goodbye. Your counter is {}".format(session_attr["counter"]))
    
        handler_input.attributes_manager.delete_persistent_attributes()
        return (
            handler_input.response_builder
                .speak(speak_output)
                .response
        )
    

Was this page helpful?

Last updated: Nov 23, 2023