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 Amazon DynamoDB usage is limited to the free tier: 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 tables

To see the Amazon DynamoDB tables 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 Database to open the AWS DynamoDB console.
    Your Amazon DynamoDB tables appear.

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
        )