One of the coolest things about Amazon's line of echo devices is the fact that the developer can build new skills for users to use on their devices. As a developer, you can build a variety of skills - this post will focus on a Custom Skill. A custom skill is a skill where you design what the skill can handle and the words that users say to invoke your skill. These skills can be games, such as trivia or choose-your-own-adventure skills, helpful skills, such as alarm clocks or list skills, and education skills, such as spelling skills or counting skills.

One useful thing that you can use in your custom skill is your user's address information. This information can be used for a variety of reasons. If you were building a skill to request a ride-share such as Uber or Lyft, you would need to know a user's exact address. For a skill used by a retailer to find the closest physical store, knowing the zip code might be enough. If you were building a game skill and you wanted to keep high scores by location, knowing what part of the country might be sufficient. In the interest of protecting your privacy, address information requires the user to grant permission to the skill to have access to your physical address. In this tutorial we are going to cover the steps to accomplish this. We will build a skill that will allow the end user to ask for specific pieces of their address such as, "What city do I live in?", and "What is my address?".

Note: This tutorial assumes that you already have a working knowledge of how to build an Alexa Skill. If you do not know how to build an Alexa Skill, please refer to the first post in this series by Maddie Stigler.

Prerequisites

  1. Log in to or create an AWS account. Go here to create one.
  2. IDE of choice. I will be using Visual Studio Code.
  3. Installed Node.js. More information on Node.js.
  4. Access to the Alexa Developer Portal. Click here to sign in.

Configuring Your Skill

After you have created your skill and set up your intents and utterances, you will need to add permissions for your skill to request the user's location. To do this, click on the Permissions tab on the left and select Device Address. Then choose:

  1. Full Address
  2. Country & Postal Code Only

These options are self explanatory - for my skill, I selected Full Address. After saving, click the Build Model button and you are ready to add the code to your lambda function.

Amazon Alexa Skills Permissions

Write Handler Code

After configuring your skill to ask for permissions for the user's address, you have to write the application logic to retrieve the address. In order to request the user's address, you need to retrieve the deviceId and apiAccessToken from the incoming request. The request object also contains the apiEndpoint that you'll need to make the request for address. The Device Address API location varies depending on the geographic location of your skill.

const accessToken = this.event.context.System.apiAccessToken;
const deviceId = this.event.context.System.device.deviceId;
const apiEndpoint = this.event.context.System.apiEndpoint;

Amazon provides a sample address implementation that includes a client for communicating with the Device Address API location. Since we are writing this function with Typescript, I have included our implementation below.

import * as Https from 'https';

export class AlexaDeviceAddressClient {
 deviceId: string;
 consentToken: string;
 endpoint: string;
 constructor(apiEndpoint, deviceId, consentToken) {
 this.deviceId = deviceId;
 this.consentToken = consentToken;
 this.endpoint = apiEndpoint.replace(/^https?:\/\//i, "");
 }

 getFullAddress(): Promise {
 const options = this.__getRequestOptions(`/v1/devices/${this.deviceId}/settings/address`);

 return new Promise((fulfill, reject) => {
 this.__handleDeviceAddressApiRequest(options, fulfill, reject);
 });
 }

 getCountryAndPostalCode(): Promise {
 const options = this.__getRequestOptions(
 `/v1/devices/${this.deviceId}/settings/address/countryAndPostalCode`);

 return new Promise((fulfill, reject) => {
 this.__handleDeviceAddressApiRequest(options, fulfill, reject);
 });
 }

 __handleDeviceAddressApiRequest(requestOptions, fulfill, reject) {
 Https.get(requestOptions, (response) => {
 console.log(`Device Address API responded with a status code of : ${response.statusCode}`);

 response.on('data', (data: string) => {
 let responsePayloadObject = JSON.parse(data);

 const deviceAddressResponse = {
 statusCode: response.statusCode,
 address: responsePayloadObject
 };

 fulfill(deviceAddressResponse);
 });
 }).on('error', (e) => {
 console.error(e);
 reject();
 });
 }

 __getRequestOptions(path) {
 return {
 hostname: this.endpoint,
 path: path,
 method: 'GET',
 'headers': {
 'Authorization': 'Bearer ' + this.consentToken
 }
 };
 }
}

The class has methods for retrieving the full address, or just the country and postal code. After retrieving the deviceId, apiAccessToken,and apiEndpoint, we can create a new instance of an AlexaDeviceAddressClient to retrieve the address information.

const alexaDeviceAddressClient = new AlexaDeviceAddressClient(apiEndpoint, deviceId, accessToken);

We can then use this to get the full address information. The getFullAddress() method has the following possible responses.

Response Description
200 OK Successfully retrieved the address associated with the deviceId.
204 No Content Usually an indication that the user has granted permission, but no address data has been provided for the device.
403 Forbidden The authentication token is invalid or doesn't have access to the address information. This is how you will know that the user hasn't granted permission to their address.
405 Method Not Alowed The method is not supported.
429 Too Many Requests The skill has been throttled due to an excessive number of requests.
500 Server Error An unexpected error has occurred.

Note: previously, the apiAccessToken was sent as consentToken within the session.user.permissions and context.System.user.permissions. It is still sent for backwards compatibility, but should no longer be used. The presence of the consentToken would indicate that the user had granted permission to their address. It is now recommended that the service call be used instead.

If the user has authorized address access for your skill, you can inspect request.intent.slots.LocationType.value to see what information the user requested. For this skill, you will set up a custom slot for the GetAddress intent that defines the type of information a user can request. LocationType will be the name of the custom slot. This list defines the valid items that may be requested. Below is the definition for the custom slot.

{
 "name": "LocationType",
 "values": [
 {
 "name": {
 "value": "State Code"
 }
 },
 {
 "name": {
 "value": "Country Code"
 }
 },
 {
 "name": {
 "value": "Country"
 }
 },
 {
 "name": {
 "value": "County"
 }
 },
 {
 "name": {
 "value": "District"
 }
 },
 {
 "name": {
 "value": "Postal Code"
 }
 },
 {
 "name": {
 "value": "Region"
 }
 },
 {
 "name": {
 "value": "Address Line 2"
 }
 },
 {
 "name": {
 "value": "Address Line 3"
 }
 },
 {
 "name": {
 "value": "Address Line 1"
 }
 },
 {
 "name": {
 "value": "Zip Code"
 }
 },
 {
 "name": {
 "value": "Zip"
 }
 },
 {
 "name": {
 "value": "Address"
 }
 },
 {
 "name": {
 "value": "State"
 }
 },
 {
 "name": {
 "value": "City"
 }
 }
 ]
}

When the API returns a 403, that means that the user hasn't granted permission to your skill to retrieve their address. When that happens you need to respond with a AskForPermissionsConsent card. This can be done like this.

this.emit(':tellWithPermissionCard', 'You have refused to allow where am I access to the address information in the Alexa app. Where am I cannot function without address information. To permit access to address information, enable where am I again, and consent to provide address information in the Alexa app.', ["read::alexa:device:all:address"]);

The important thing to keep in mind is that you also have to pass requested permissions. In this example, we are sending read::alexa:device:all:address since our skill uses full address. If it only used country and postal code, the permissions would be read::alexa:device:all:address:country_and_postal_code. The permissions card will look like this in your mobile app.

Permission Card

Testing Your Skill

Typically you would test your skill in the Alexa Developer Portal, however, because the Alexa Simulator doesn't have a deviceId you will never be able to retrieve the location. If you have an Alexa device that is linked to the same email address as your Amazon Developer account you can test your skill on it. The other option is to use the Alexa app on your mobile device.

First, you must enable the access in the mobile application before testing. Normally you would do this when adding the skill, but since you are developing the skill, it is automatically added to your devices linked to your developer email. To add the permissions in the Alexa App, click on Skills from the menu and find your skill. When you click on it, it will look similar to the screen below.

Skill Settings

Click on Settings. The settings screen will look like this.

Enable Address

You will need to select Device Address and save. You should now be able to test retrieving address information from your Alexa device or your mobile device's Alexa application.

Conclusion

After reading and working through this tutorial, you should have a good understanding of how to enable location access in your Alexa Skill. The source code for this tutorial can be found here.

Next in Alexa Blog Series

In the next blog post in this Alexa series, Zakk Lefkowits will walk us through custom user authentication in an Alexa Skill.