Tutorial: Develop Your First Alexa Skill With the ASK SDK for Node.js
The following tutorial walks you through developing your first skill with the Alexa Skills Kit (ASK) Software Development Kit (SDK) v2 for Node.js. The example skill has the following flow:
User: Alexa, what's the weather?
Alexa: The weather is sunny.
You start with an empty skill project, add request handlers, and create a skill package. Then, you create a corresponding Amazon Web Services (AWS) Lambda function by using the AWS console, and configure the skill by using the Alexa developer console. You can test your skill by using the simulator in the developer console or by using an Alexa-enabled device.
Prerequisites
Before you follow this tutorial, you must have the following accounts and tools:
- Amazon developer account – You can use an existing Amazon account to sign in, or you can create a new Amazon developer account. The account is free.
- Amazon Web Services (AWS) account – The AWS account gives you access to resources as part of the free tier of services. You host your skill code on AWS Lambda.
- Node Package Manager (NPM) – For details about how to install NPM, see Getting started in the NPM documentation.
- ASK SDK v2 for Node.js – For details about installing the SDK, see Set up the ASK SDK v2 for Node.js. This tutorial requires one of the following installations:
- The standard SDK distribution
- The support modules for the core SDK, if you want to customize your dependencies
- Alexa-enabled device – Make sure that you sign in to the Alexa-enabled device, such as an Amazon Echo, with the same credentials as your Alexa developer account.
Steps to create a skill with the ASK SDK for Node.js
To create a skill, complete the following steps:
- Create an empty skill project.
- Import dependencies.
- Add request handlers.
- Create the skill package.
- Create an AWS Lambda function.
- Create and configure your skill.
- Test your skill.
Step 1: Create an empty skill project
To create an empty skill project by using NPM, take the following steps.
To create an empty skill project
- On your computer, create a folder for your skill.
- Open the command prompt, and then navigate to your skill folder.
- At the command prompt, enter
npm init
. - Press Enter for all the prompts.
In your skill code folder, you now have a file calledpackage.json
. - From your skill code folder, enter
npm install --save ask-sdk
.
This command creates anode_modules
folder. - In your skill folder, create an empty file named
index.js
.
Step 2: Import dependencies
To indicate that your code relies on the ASK SDK for Node.js, you must import the SDK as a dependency.
To import dependencies
- Paste the following code into your
index.js
file.
const Alexa = require('ask-sdk-core');
import {
ErrorHandler,
HandlerInput,
RequestHandler,
SkillBuilders,
} from 'ask-sdk-core';
import {
Response,
SessionEndedRequest,
} from 'ask-sdk-model';
Step 3: Add request handlers
Request handlers handle the different types of incoming requests to your skill. The following sections provide code examples for request handlers that you can paste into your skill code:
- LaunchRequest handler
- AskWeatherIntent handler
- HelpIntent handler
- CancelAndStopIntent handler
- SessionEndedRequest handler
- Error handler
- Lambda handler
LaunchRequest handler
When the user invokes your skill without a specific intent, Alexa sends your skill a LaunchRequest
. The following code configures a handler that Alexa invokes when your skill receives a LaunchRequest
.
To add a LaunchRequest handler
- Paste the following code into your
index.js
file after therequire
line that you added previously.
const LaunchRequestHandler = {
canHandle(handlerInput) {
return Alexa.getRequestType(handlerInput.requestEnvelope) === 'LaunchRequest';
},
handle(handlerInput) {
const speechText = 'Welcome to your SDK weather skill. Ask me the weather!';
return handlerInput.responseBuilder
.speak(speechText)
.reprompt(speechText)
.withSimpleCard('Welcome to your SDK weather skill. Ask me the weather!', speechText)
.getResponse();
}
};
const LaunchRequestHandler : RequestHandler = {
canHandle(handlerInput : HandlerInput) : boolean {
const request = handlerInput.requestEnvelope.request;
return request.type === 'LaunchRequest';
},
handle(handlerInput : HandlerInput) : Response {
const speechText = 'Welcome to your SDK weather skill. Ask me the weather!';
return handlerInput.responseBuilder
.speak(speechText)
.reprompt(speechText)
.withSimpleCard('Welcome to your SDK weather skill. Ask me the weather!', speechText)
.getResponse();
},
};
In the code, the canHandle()
function returns true
if the incoming request is a LaunchRequest
. The handle()
function generates and returns a response to Alexa.
AskWeatherIntent handler
The following code configures a handler that Alexa invokes when the user asks for the weather.
To add an AskWeatherIntent handler
- Paste the following code after the previous handler in your
index.js
file.
const AskWeatherIntentHandler = {
canHandle(handlerInput) {
return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest'
&& Alexa.getIntentName(handlerInput.requestEnvelope) === 'AskWeatherIntent';
},
handle(handlerInput) {
const speechText = 'The weather today is sunny.';
return handlerInput.responseBuilder
.speak(speechText)
.withSimpleCard('The weather today is sunny.', speechText)
.getResponse();
}
};
const AskWeatherIntentHandler : RequestHandler = {
canHandle(handlerInput : HandlerInput) : boolean {
const request = handlerInput.requestEnvelope.request;
return request.type === 'IntentRequest'
&& request.intent.name === 'AskWeatherIntent';
},
handle(handlerInput : HandlerInput) : Response {
const speechText = 'The weather today is sunny.';
return handlerInput.responseBuilder
.speak(speechText)
.withSimpleCard('The weather today is sunny.', speechText)
.getResponse();
},
};
In the code, the canHandle()
function detects if the incoming request is an IntentRequest
, and returns true
if the intent name is AskWeatherIntent
. The handle()
function returns a response with Alexa speech that says the weather.
HelpIntent handler
The following code configures a handler that Alexa invokes when the skill receives the built-in intent AMAZON.HelpIntent
. For details about how user utterances trigger built-in intents, see Standard Built-in Intents.
To add a HelpIntent handler
- Paste the following code after the previous handler in your
index.js
file.
const HelpIntentHandler = {
canHandle(handlerInput) {
return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest'
&& Alexa.getIntentName(handlerInput.requestEnvelope) === 'AMAZON.HelpIntent';
},
handle(handlerInput) {
const speechText = 'You can ask me the weather!';
return handlerInput.responseBuilder
.speak(speechText)
.reprompt(speechText)
.withSimpleCard('You can ask me the weather!', speechText)
.getResponse();
}
};
const HelpIntentHandler : RequestHandler = {
canHandle(handlerInput : HandlerInput) : boolean {
const request = handlerInput.requestEnvelope.request;
return request.type === 'IntentRequest'
&& request.intent.name === 'AMAZON.HelpIntent';
},
handle(handlerInput : HandlerInput) : Response {
const speechText = 'You can ask me the weather!';
return handlerInput.responseBuilder
.speak(speechText)
.reprompt(speechText)
.withSimpleCard('You can ask me the weather!', speechText)
.getResponse();
},
};
Similar to the previous handler, the HelpIntent
handler matches an IntentRequest
with the expected intent name. The handler returns a response in which Alexa provides the suggestions you specify in the handler.
CancelAndStopIntent handler
You can use a single handler to respond to two different intents. The following example uses a single handler to respond to both the AMAZON.CancelIntent
and the AMAZON.StopIntent
built-in intents. The response to both intents is the same, so having a single handler reduces repetitive code.
To add a CancelAndStopIntent handler
- Paste the following code after the previous handler in your
index.js
file.
const CancelAndStopIntentHandler = {
canHandle(handlerInput) {
return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest'
&& (Alexa.getIntentName(handlerInput.requestEnvelope) === 'AMAZON.CancelIntent'
|| Alexa.getIntentName(handlerInput.requestEnvelope) === 'AMAZON.StopIntent');
},
handle(handlerInput) {
const speechText = 'Goodbye!';
return handlerInput.responseBuilder
.speak(speechText)
.withSimpleCard('Goodbye!', speechText)
.withShouldEndSession(true)
.getResponse();
}
};
const CancelAndStopIntentHandler : RequestHandler = {
canHandle(handlerInput : HandlerInput) : boolean {
const request = handlerInput.requestEnvelope.request;
return request.type === 'IntentRequest'
&& (request.intent.name === 'AMAZON.CancelIntent'
|| request.intent.name === 'AMAZON.StopIntent');
},
handle(handlerInput : HandlerInput) : Response {
const speechText = 'Goodbye!';
return handlerInput.responseBuilder
.speak(speechText)
.withSimpleCard('Goodbye!', speechText)
.withShouldEndSession(true)
.getResponse();
},
};
SessionEndedRequest handler
Although your skill can't return a response after receiving a SessionEndedRequest
, you can provide a handler that contains clean-up logic. The following example shows how to create a handler for a SessionEndedRequest
.
To add a SessionEndedRequest handler
- Paste the following code after the previous handler in your
index.js
file.
const SessionEndedRequestHandler = {
canHandle(handlerInput) {
return Alexa.getRequestType(handlerInput.requestEnvelope) === 'SessionEndedRequest';
},
handle(handlerInput) {
// Any clean-up logic goes here.
return handlerInput.responseBuilder.getResponse();
}
};
const SessionEndedRequestHandler : RequestHandler = {
canHandle(handlerInput : HandlerInput) : boolean {
const request = handlerInput.requestEnvelope.request;
return request.type === 'SessionEndedRequest';
},
handle(handlerInput : HandlerInput) : Response {
console.log(`Session ended with reason: ${(handlerInput.requestEnvelope.request as SessionEndedRequest).reason}`);
return handlerInput.responseBuilder.getResponse();
},
};
Error handler
You can put your error-handling logic in an error handler. For example, you can add logic that handles unhandled requests, API service timeouts, and so on. The following code adds an error handler to your skill to ensure that your skill returns a meaningful message for all errors.
To add an error handler
- Paste the following code after the previous handler in your
index.js
file.
const ErrorHandler = {
canHandle() {
return true;
},
handle(handlerInput, error) {
console.log(`Error handled: ${error.message}`);
return handlerInput.responseBuilder
.speak('Sorry, I don\'t understand your command. Please say it again.')
.reprompt('Sorry, I don\'t understand your command. Please say it again.')
.getResponse();
}
};
const ErrorHandler : ErrorHandler = {
canHandle(handlerInput : HandlerInput, error : Error ) : boolean {
return true;
},
handle(handlerInput : HandlerInput, error : Error) : Response {
console.log(`Error handled: ${error.message}`);
return handlerInput.responseBuilder
.speak('Sorry, I don\'t understand your command. Please say it again.')
.reprompt('Sorry, I don\'t understand your command. Please say it again.')
.getResponse();
}
};
Lambda handler
The Lambda handler is the entry point for your AWS Lambda function. The following code creates a Lambda handler function to route all inbound request to your skill.
To add a Lambda handler
- Paste the following code after the previous handler in your
index.js
file.
let skill;
exports.handler = async function (event, context) {
console.log(`REQUEST++++${JSON.stringify(event)}`);
if (!skill) {
skill = Alexa.SkillBuilders.custom()
.addRequestHandlers(
LaunchRequestHandler,
AskWeatherIntentHandler,
HelpIntentHandler,
CancelAndStopIntentHandler,
SessionEndedRequestHandler,
)
.addErrorHandlers(ErrorHandler)
.create();
}
const response = await skill.invoke(event, context);
console.log(`RESPONSE++++${JSON.stringify(response)}`);
return response;
};
let skill;
exports.handler = async (event, context) => {
console.log(`REQUEST++++${JSON.stringify(event)}`);
if (!skill) {
skill = SkillBuilders.custom()
.addRequestHandlers(
LaunchRequestHandler,
AskWeatherIntentHandler,
HelpIntentHandler,
CancelAndStopIntentHandler,
SessionEndedRequestHandler,
)
.addErrorHandlers(ErrorHandler)
.create();
}
const response = await skill.invoke(event, context);
console.log(`RESPONSE++++${JSON.stringify(response)}`);
return response;
};
The Lambda handler function creates an SDK Skill
instance by using the SkillBuilders.custom()
builder function. The addRequestHandlers()
builder function registers the request handlers that you created in the previous steps. The code exports the function as the Lambda handler function.
Alternatively, ASK SDK v2 for Node.js provides a lambda
builder function that you can use to construct the Lambda handler function that invokes the Skill
instance and returns the response. The following example shows how to use the lambda
builder function.
exports.handler = Alexa.SkillBuilders.custom()
.addRequestHandlers(
LaunchRequestHandler,
AskWeatherIntentHandler,
HelpIntentHandler,
CancelAndStopIntentHandler,
SessionEndedRequestHandler)
.addErrorHandlers(ErrorHandler)
.lambda();
exports.handler = SkillBuilders.custom()
.addRequestHandlers(
LaunchRequestHandler,
AskWeatherIntentHandler,
HelpIntentHandler,
CancelAndStopIntentHandler,
SessionEndedRequestHandler,
)
.addErrorHandlers(ErrorHandler)
.lambda();
Step 4: Create the skill package
With the skill code complete, you can create the skill package that you upload to AWS Lambda in a subsequent step.
To create a skill package
-
Create a zip file that contains the contents of your skill code folder.
The zip file containsindex.js
,package.json
, and thenode_modules
folder.Important: Make sure to compress the contents of the skill code folder, not the skill code folder itself.
Step 5: Create an AWS Lambda function
In the previous steps, you created the code for a Lambda function. You must also create the corresponding Lambda function in the AWS console, and then upload your skill code to the Lambda function.
To create an AWS Lambda function
- Sign in to the AWS Lambda console.
- In the upper-right corner of the console, from the Region drop-down list, select one of the allowed AWS regions for Alexa skills, such as US East (N. Virginia).
For a list of allowed regions for Alexa skills, see Select the optimal region for your AWS Lambda function. - If you have no Lambda functions yet, click Get Started Now.
- If you have one or more Lambda functions, click Create function.
- Select Author from scratch.
- For Function name, enter a name for your Lambda function.
- For Runtime, select Node.js 16.x or later.
- For Permissions, expand Change default execution role, and then select Create a new role from AWS policy templates.
- For Role name, enter a name for the role.
- From the Policy templates list, select Simple Microservice permissions.
- At the bottom of the page, click Create function.
- Click Function overview, and then click Add trigger.
- For Trigger configuration, select Alexa Skills Kit.
- For Skill ID verification, select Disable.
- Click Add.
- In the middle of the page, click the Code tab.
- On the right, click Upload from, and then select .zip file.
- Upload the zip file you produced in Step 4: Create the skill package.
- At the top right of your Lambda function page, click Copy ARN, and then paste the ARN somewhere you can access it later.
You need the ARN when you configure your skill in the Alexa developer console in the next step.
Step 6: Create and configure your skill
Now that your skill code is in AWS Lambda, you can create and configure your skill in the developer console.
To create and configure an Alexa skill in the Alexa developer console
Follow the steps to create a new skill in the developer console. When prompted to choose a model, select the Custom model. Select to host your skill code on AWS Lambda, and then follow these steps to build your voice interaction model.
- On the left, click Invocation.
- For Skill Invocation Name, enter
my sdk weather
, and then click Save Model.
To launch your skill, say, "Alexa, open my sdk weather." - On the left, expand Interaction Model, click Intents, and then click Add Intent.
- Under Create custom intent, enter
AskWeatherIntent
, and then click Create custom intent. - Under Sample Utterances, add some sample utterances that a user might say to ask for the weather, and click the plus sign (+) or press Enter after each entry.
You can add the following sample utterances; feel free to add others.what is the weather what's the weather what is it like out what's it like out
Note: BecauseAMAZON.CancelIntent
,AMAZON.HelpIntent
, andAMAZON.StopIntent
are built-in Alexa intents, you don't need to provide sample utterances for them. - At the top, click Save Model.
- At the top, click Build Model.
- On the left, expand Assets, and then click Endpoint.
- Replace the Default Region with the AWS Lambda ARN you copied in Step 5: Create an AWS Lambda function.
- At the top, click Save Endpoints.
Step 7: Test your skill
You can test your skill by using the Alexa Simulator in the developer console or by using an Alexa-enabled device, such as an Echo device. For details about testing skills, see Test and Debug Your Skill.
To test your skill in the developer console
- At the top of the developer console, click the Test tab.
- On the left, at the top, for Test is disabled for this skill, select Development.
- In the Alexa Simulator, click in the Type or click and hold the mic field, type
open my sdk weather
, and then press Enter. - Enter or say "Alexa, what's the weather?"
Alexa should respond, "The weather is sunny."
You can also test your skill by using an Alexa-enabled device, such as an Echo device, that's registered to the same Amazon account as the account in which you created your skill.
To test your skill by using an Alexa-enabled device
- Say to your Alexa-enabled device, "Alexa, open my sdk weather."
- After Alexa opens your skill, ask, "Alexa, what's the weather?"
If Alexa can't find your skill, make sure that you register your Alexa-enabled device to the same Amazon account that you used to create the skill.
Related topics
Last updated: Aug 29, 2024