If you're adding in-skill purchasing (ISP) to your skill, one of the features that is tested during certification is the ability to keep track of your customers' inventory of consumable in-skill products. Similar to the other in-skill products, one-time purchases (also known as entitlements) and subscriptions, consumables are a type of product that any developer can offer within their skills. However, with consumable in-skill products, maintaining an accurate inventory is important to provide a good experience for your customers and help your skill pass certification. Below is a quick overview of each type of in-skill product, followed by examples.
When implementing ISP in your skill, Alexa handles the purchase flow, which is triggered when a customer says “buy more hints,” for example, or when they say “yes” to an offer (Skill: “Would you like to buy it?”, Customer: “Yes”), and returns the result of that purchase to your code. In the case of consumables, it is your responsibility to manage their inventory, which means tracking how many hints, for example, the customer has used. Alexa will keep track of how many times a consumable has been bought (as activeEntitlementCount in the returned object from the getInSkillProducts function), so you can use that information in conjunction with the number of hints used to let the customer know how many they still have available.
This information has to persist between sessions and even in case a customer disables and then re-enables the skill. The good news is that by using persistent attributes together with Amazon DynamoDB, it is fairly easy to do so. In this blog post, I will guide you through how to set up your code to handle persistent attributes with DynamoDB and share a few functions to keep track of your customers' usage of consumables. This guided blog post is relevant for experienced skill builders who are familiar with writing code.
As you will need to use extra dependencies to work with DynamoDB, the deployment package of your code will be too large to enable editing in the AWS Lambda webpage. Make sure that you have the Alexa Skills Kit Command Line Interface (CLI) installed and configured properly, as the code will be edited locally and then uploaded to Lambda.
Also, you will need to ensure that the execution role selected for your Lambda code has the appropriate set of permissions to use DynamoDB. You can verify that by checking if the following resources are listed in your Lambda page:
If that is not the case, then visit the IAM Management Console in your AWS account and add the necessary permissions to the role you choose.
First, add the DynamoDB persistence adapter dependencies. In order to do so, you will need to go to the lambda/custom folder in your skill directory and execute the following command:
npm -i ask-sdk-dynamodb-persistence-adapter —save
To see if this has worked, check if there are new folders under lambda/custom/node_modules (originally there should be only three) and if new dependencies have been listed in the package.json file.
Now, in your index.js file, add the following lines:
const { DynamoDbPersistenceAdapter } = require('ask-sdk-dynamodb-persistence-adapter');
const persistenceAdapter = new DynamoDbPersistenceAdapter({
tableName: 'SkillTable', // <-- change this
createTable: true
});
This will make the skill create the SkillTable in DynamoDB, if it has not been created yet. Feel free to change this name to something more appropriate for your skill.
For the next step, you will need to add the persistence adapter that you just created to the skill builder. This is accomplished by adding just one line to the builder, so it looks something like this:
exports.handler = Alexa.SkillBuilders.custom()
.addRequestHandlers(
LaunchRequestHandler,
HelpIntentHandler,
CancelIntentHandler,
// ... other handlers
SessionEndedRequestHandler)
.withPersistenceAdapter(persistenceAdapter) // <- this is the line to be added
.addErrorHandlers(ErrorHandler)
// ...
Your code is now ready to start working with persistent attributes!
In order to implement persistent attributes, you will need to use async/await operators. You can find more about these operators on this blog post.
First, you will need a function that checks the DynamoDB table for used consumables and return its value:
async function getUsedConsumables(handlerInput) {
const { attributesManager } = handlerInput;
let persistentAttributes;
try {
persistentAttributes = await attributesManager.getPersistentAttributes();
} catch (e) {
// if there was an error, log it and return false
console.log(`[ERROR] Could not retrieve persistent attributes: ${e}`);
return false;
}
let usedConsumables = persistentAttributes.usedConsumables;
if (typeof usedConsumables === 'undefined') {
// if we are here, it means that availableConsumables has not
// been stored in the persistent attributes, so let us set it to
// zero,
usedConsumables = 0;
// store it in the persistent attributes,
persistentAttributes.usedConsumables = usedConsumables;
// set it in the attributes manager,
attributesManager.setPersistentAttributes(persistentAttributes);
// save it to the table,
try {
await attributesManager.savePersistentAttributes();
} catch(e) {
// if there was an error, log it and return false
console.log(`[ERROR] Could not save persistent attributes: ${e}`);
return false;
}
// return the value of usedConsumables
return usedConsumables;
} else {
// this means that the usedConsumables has already been
// stored, so its value can be returned
return usedConsumables;
}
}
Now, when the customer uses a consumable, you need to change the value in your inventory, which is exactly what this next function does:
async function updateUsedConsumables(handlerInput, newValue) {
const { attributesManager } = handlerInput;
let persistentAttributes;
try {
persistentAttributes = await attributesManager.getPersistentAttributes();
} catch (e) {
// if there was an error, log it and return
console.log(`[ERROR] Could not retrieve persistent attributes: ${e}`);
return;
}
// set the usedConsumables in the table to newValue
persistentAttributes.usedConsumables = newValue;
// set it in the attributes manager and
attributesManager.setPersistentAttributes(persistentAttributes);
// save it to the table
try {
await attributesManager.savePersistentAttributes();
} catch(e) {
// if there was an error, log it and return
console.log(`[ERROR] Could not save persistent attributes: ${e}`);
return;
}
}
When asked how many consumables a customer still has available, your code can use the function below to calculate the number:
async function getAvailableConsumables(handlerInput, consumableProduct) {
// consumable product is the JSON object representing the consumable product,
// i.e. one of the items returned by the getInSkillProduct function
const { attributesManager } = handlerInput;
let persistentAttributes;
// get the numbers of time consumableProduct has been bought
const boughtConsumables = consumableProduct.activeEntitlementCount;
if (boughtConsumables === 0) {
// this means that consumableProduct has not been bought yet, so there is
// no need to continue and we can return 0
return 0;
}
// get the number of times the user has used consumables
const usedConsumables = await getUsedConsumables(handlerInput);
if (usedConsumables) {
// calculate the difference between the times the consumable has been bought
// and the times it has been used
let availableConsumables = boughtConsumables - usedConsumables;
// return the number of available consumables
return availableConsumables;
} else {
}
}
Using these functions, you will be able to control your skill's consumables inventory using DynamoDB. By using DynamoDB, you don't need to worry about looking for an individual key for your customers, as Alexa will automatically use the userId value for the table's keys. For skills that implement consumables, the userId value remains unchanged even after the customer disables and re-enables the skill
For additional support on this topic, or support in general, feel free to post on the Alexa Developer Forums, or get in touch with us. You can also reach out to me directly at @bbezerra82.
When you create delightful skills with compelling content, customers win. You can make money through Alexa skills using in-skill purchasing or Amazon Pay for Alexa Skills. You can also make money for eligible skills that drive some of the highest customer engagement with Alexa Developer Rewards. Learn more about how you can make money with Alexa skills.