Use DynamoDB for Data Persistence with Your Alexa-hosted Skill

When you create an Alexa-hosted skill, Alexa stores your code and resources on AWS for you. For details about hosted skills, see Build a Skill End-to-end Using an 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 AWS free tier that provides up to 25 GB of Amazon DynamoDB storage, and 1 GB of data transfer out per month. Alexa-hosted skills use the encryption methods supported by AWS for tabular data.

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

View your Amazon DynamoDB table

Each Alexa-hosted skill gets one DynamoDB table for persisting 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

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. 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. Don't overwrite other 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.

    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

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. Don't overwrite other 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.

    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
        )