APL Data Store Extension
Use the data store extension in your Alexa Presentation Language (APL) document to access data stored in the data store on a device. The data store is an area installed locally to a device that contains data an APL document can access with data binding. Widgets use the data store to display content without sending requests to your skill and waiting on a response.
You must use the data store extension to use data-binding expressions that bind to data in the data store.
Extension summary
Minimum supported APL version |
APL 1.4 |
Extension URI |
|
Settings | |
Environment properties | |
Live data properties | |
Commands | |
Event handlers | |
Required in skill manifest? |
Yes. Add |
Auto-initialized settings? |
No |
About the data store and the data store extension
The data store extension is available on devices that support on-device data storage for skill data. These devices include all devices that support widgets.
Data store hierarchy
The data store on a device stores data as an object or an array of objects. The data store organizes these objects or arrays in a hierarchy consisting of a region, namespace, and key.
The following list provides definitions for the data store hierarchy terms:
- Region – Globally isolated storage partition in the data store that stores data. Your skill has access to a specific region based on the skill ID. Data store commands and operations set this region for you automatically. You don't specify this location directly.
- Namespace – Partition within the region. You define the data store namespaces to use with your skill.
- Key – Unique identifier within a namespace. You define the keys to use within a namespace.
- Object – Content to store, in the form of an object or an array of objects. You access a data store object with the hierarchical identifier that consists of the region, namespace, and key.
Data store security
The data store prevents unauthorized access to stored content. To read or write objects in the data store, an APL document must have read or write permissions. The following list shows the security policies that apply at each level in the data store hierarchy:
- Region – If the APL document has read or write permissions at the region level, the document can read or write content for all keys in all namespaces in the region. Your skill has read and write access to a region based on the ID of your skill. Your skill can't access the data store regions for any other skills.
- Namespace – If the APL document has read or write permissions at the namespace level, the document can read or write content for all keys in the namespace.
- Key – If the APL document has read or write permissions at the key level, the document can read or write the object or array stored against the single key in the data store.
Enable the data store extension
Enable the extension in your skill manifest and in the APL document. You must include the extension in both places to use it. Then, configure the document-level settings for the extension in the document settings
property.
The URI for the data store extension is alexaext:datastore:10
.
To add the extension to the skill manifest, add alexaext:datastore:10
to the requestedExtensions
property in the ALEXA_EXTENSION
object in the manifest.apis.custom.interfaces
array.
The following example shows how to enable the extension in the skill manifest.
{
"manifest": {
"apis": {
"custom": {
"interfaces": [
{
"type": "ALEXA_EXTENSION",
"autoInitializedExtensions": [],
"requestedExtensions": [
{
"uri": "alexaext:datastore:10"
}
]
}
]
}
}
}
}
For details, see Request an extension in the skill manifest.
To request the extension in your APL document, add alexaext:datastore:10
to an object in the extensions
array in your document and assign it a name
. You use this name to refer to the extension in your document.
The following example requests the data store extension and gives it the name DataStore
.
{
"type": "APL",
"version": "2024.2",
"extensions": [
{
"name": "DataStore",
"uri": "alexaext:datastore:10"
}
]
}
For details about requesting an APL extension in the APL document, see Request an extension in the APL document.
Verify device support for the data store extension
In your document, use the environment.extension
property to determine whether the device supports the data store extension. For example, if you use DataStore
for the name
in the extensions
property, the following data-binding expression returns true
when the device supports the data store.
${environment.extension.DataStore}
Extension settings
The following table shows the settings for the data store extension.
Name | Type | Default | Description |
---|---|---|---|
|
Object |
|
Object array to define data store bindings. |
To configure these settings in your APL document, use settings.AssignedName
, where AssignedName
is the name you assigned the extension in the extensions
property.
The following example assigns the extension the name DataStore
, and then sets the dataBindings
property.
{
"type": "APL",
"version": "2024.2",
"extensions": [
{
"name": "DataStore",
"uri": "alexaext:datastore:10"
}
],
"settings": {
"DataStore": {
"dataBindings": []
}
},
"mainTemplate": {}
}
dataBindings
An array of objects. Each object in this array defines a live data DataBinding
object with the specified dataBindingName
. The DataBinding
object represents an object in the data store. You use the dataBindingName
in the data-binding expressions in your document to retrieve data from that object in the data store.
Each definition in the dataBindings
array must have the properties shown in the following table.
Name | Type | Default | Description |
---|---|---|---|
|
String |
Required |
Set to the data store namespace that stores the object to access. Must be unique within the region for your skill. The namespace must be a be a non-empty string that meets the follow requirements:
The |
|
String |
Required |
Set to the data store key that identifies the object to access. This key should be within the specified
The |
|
String |
Required |
Set to a name to use to access the |
|
String |
object |
Data type for the object to access. Allowed values: |
|
Number |
0 |
Applies when |
|
Number |
–1 |
Applies when |
namespace and key
Set these properties to reference the object you want to access in your data-binding expressions. You define the namespace
and key
for your data.
The following example shows a data binding that specifies a namespace
called LocationWeather
and a key
called DS_Weather
.
{
"settings": {
"DataStore": {
"dataBindings": [
{
"namespace": "LocationWeather",
"key": "weather",
"dataBindingName": "DS_Weather"
}
]
}
}
}
dataBindingName
Set to a name to use to access the DataBinding
object. The data store extension adds this name to the data-binding context available to your document. You use this name in your data-binding expressions to access the data in the object stored at the specified namespace
and key
in the data store.
The previous example showed a dataBindingName
set to DS_Weather
. To access data in the weather
object, use this name in your data-binding expressions: ${DS_Weather.propertyName}
, where propertyName
is a property in the stored object. For a full example, see Example: Configure dataBindings and access data.
The extension always creates a DataBinding
object with the specified dataBindingName
, regardless of whether an object exists in the data store at the specified namespace
and key
.
- If the object doesn't exist, the provided
dataBindingName
is set tonull
. - If the object exists, the provided
dataBindingName
is set to the object.
dataType
Data type of the item stored in the data store. Can be OBJECT
or ARRAY
.
startIndex, endIndex
The startIndex
and endIndex
properties apply when dataType
is ARRAY
. The properties specify the starting and ending index values for a range of items from the array stored at the specified namespace
and key
. When you set these properties, the live data DataBinding
object initializes to a sub-array containing elements starting with startIndex
and ending with endIndex
.
The range includes the element at startIndex
and the element at endIndex
.
The startIndex
and endIndex
properties are ignored when the dataType
is OBJECT
.
You can modify the range of elements loaded into the DataBinding
object with the UpdateArrayBindingRange
command.
Example: Configure dataBindings and access data
The following example shows the relationship between the content stored in the data store, the dataBindings
setting, and the data-binding expressions in your document. Assume your skill writes data to the data store at the following location within the region provided for your skill:
- Namespace:
LocationWeather
- Key:
weather
Your skill uses the Data Store REST API to add the following content to the data store on a device.
{
"location": "Seattle, WA",
"details": {
"temperature": "5 °C",
"precipitation": "20%",
"humidity": "70%",
"wind": "4 km/h"
}
}
In your document, you configure the data store extension with the following item in dataBindings
.
{
"settings": {
"DataStore": {
"dataBindings": [
{
"namespace": "LocationWeather",
"key": "weather",
"dataBindingName": "DS_Weather"
}
]
}
}
}
With this configuration, the expression ${DS_Weather.location}
returns the string "Seattle, WA".
The following example shows an APL document for a widget that uses this configuration to display the weather data stored in the data store.
If your skill later uses the Data Store REST API to update the data store with new weather information, the widget updates to display the new data. To simulate a data store update in the code sandbox:
- Click the Data Store tab.
- Click Edit Data Store.
- Enter a data store command in in the Commands pane. The example defaults to a sample
PUT_OBJECT
command that changes thetemperature
,precipitation
, andhumidity
values. - Click Execute Commands to send the command.
Environment properties (static)
The data store extension adds the following static environment properties.
Name | Type | Description |
---|---|---|
|
String |
The data store extension version. |
Access environment properties in the data-binding context with environment.extension.AssignedName
where AssignedName
is the name you assigned the extension in the extensions
property.
For example, ${environment.extension.DataStore.version}
returns the extension version, assuming you assigned the extension the name DataStore
.
For more details about the environment.extension
property in the data-binding context, see extension
.
Live data properties
The data store extension adds live data properties to the data-binding context. Live data properties are data objects that can change during the lifecycle of the APL document.
For more details about live data, see Extension live data.
DataBinding
The data store DataBinding
live data object represents an object or array in the data store at a specific namespace
and key
, within the region provided for your skill.
The properties of the DataBinding
depend on the structure of the object or array in the data store. To access the data, use the dataBindingName
for the object configured in the extension settings.
For an example, see Example: Configure dataBindings and access data.
Commands
The data store extension adds new extension commands.
To run a data store command, set the type
property for the command to AssignedName:CommandName
, where AssignedName
is the name you assigned the extension in the extensions
property. For example, if you assign the extension the name DataStore
, you can run the WatchObject
command with DataStore:WatchObject
.
GetObject
The GetObject command retrieves data store object. The command is asynchronous. After you run this command, the OnObjectReceived
handler returns the requested object.
The following table shows the properties of this command.
Property | Type | Default | Description |
---|---|---|---|
|
String |
Required |
Name of |
|
String |
Required |
Name of |
|
String |
"" |
Optional token you provide. The |
The following example runs the GetObject
command when the widget initially inflates. The OnObjectReceived
handler then uses a SetValue
command to set the value of the location
bind variable, which then displays in the Text
component. This example doesn't use the live data DataBinding
property, so if you run a data store command such as PUT_OBJECT
to update the data store, the value displayed in the widget doesn't change.
WatchObject
The WatchObject
command configures the document to watch a specified data store object for modification. When the object changes, the OnObjectChanged
event handler runs. Use this command and handler to run other APL commands in response to changes in the data store.
When you run WatchObject
, the command invokes the OnObjectChanged
handler and sets the document to watch for changes to the data store object. Future changes to the data store object invoke OnObjectChanged
.
The following table shows the properties of this command.
Property | Type | Default | Description |
---|---|---|---|
|
String |
Required |
Name of |
|
String |
Required |
Name of |
If the specified object doesn't exist or is deleted, the data
property for OnObjectChanged
returns null
.
The following example shows a WatchObject
command that runs when the document displays. The OnObjectChanged
handler runs the SetValue
command.
Later, if your skill uses the Data Store REST API to update the data store object at the namespace LocationWeather
and the key weather
, the OnObjectChanged
handler runs again. This triggers the SetValue
command to update the temperature
bind variable.
UnwatchObject
The UnwatchObject
configures the document to stop watching a specified data store object that was the target of the WatchObject
command. After UnwatchObject
runs, the OnObjectChanged
handler no longer runs in response to changes to the data store object.
The UnwatchObject
command doesn't return a result.
The following table shows the properties of this command.
Property | Type | Default | Description |
---|---|---|---|
|
String |
Required |
Name of |
|
String |
Required |
Name of |
The following example shows a TouchWrapper
that runs the UnwatchObject
command when the user taps the button.
{
"type": "APL",
"version": "2024.2",
"extensions": [
{
"name": "DataStore",
"uri": "alexaext:datastore:10"
}
],
"settings": {
"DataStore": {
"dataBindings": [
{
"namespace": "LocationWeather",
"key": "weather",
"dataBindingName": "DS_Weather"
}
]
}
},
"mainTemplate": {
"item": {
"type": "TouchWrapper",
"item": {
"type": "Text",
"text": "Stop watching object from DataStore"
},
"onPress": {
"type": "DataStore:UnwatchObject",
"namespace": "LocationWeather",
"key": "weather"
}
}
}
}
UpdateArrayBindingRange
The UpdateArrayBindingRange
command modifies the range of elements to load into the live data DataBinding
array.
The following table shows the properties of this command.
Property | Type | Default | Description |
---|---|---|---|
dataBindingName |
String |
Required |
Name of a |
startIndex |
Number |
Required |
Specifies the starting index for a range of items from the data store array. The live data array identified by |
endIndex |
Number |
Required |
Specifies the ending index for a range of items from the data store array. The live data array identified by |
The UpdateArrayBindingRange
applies when the dataBindingName
refers to an ARRAY
. If the dataBindingName
refers to an OBJECT
, the command doesn't run.
Event handlers
The data store extension adds new extension event handlers. To respond to events generated by the data store extension, add the handler to the top-level properties in your APL document. For the handler name, use AssignedName:EventHandlerName
, where AssignedName
is the name you assigned the extension in the extensions property and EventHandlerName
is the name of the handler.
For example, assuming you named the extension DataStore
, you would use DataStore:OnObjectChanged
to respond to events from the OnObjectChanged
handler.
OnObjectChanged
Invoked in the following situations:
- When the
WatchObject
runs. - When the data store object configured with the
WatchObject
command changes.
The following table shows the properties that the OnObjectChanged
handler adds to the event context.
Name | Type | Default | Description |
---|---|---|---|
|
String |
Required |
The |
|
String |
Required |
The |
|
Object |
Required |
The updated value of the data store object that changed. Returns null in the following situations:
|
The OnObjectChanged
handler generates an event with the following form.
{
"namespace": "LocationWeather",
"key": "weather",
"data": {
"location": "Pune, MH",
"details": {
"temperature": "27 °C",
"precipitation": "7%",
"humidity": "51%",
"wind": "5 km/h"
}
},
"event": {
"source": {
"type": "Document",
"handler": "DataStore:OnObjectChanged",
"id": null,
"uid": null,
"value": null
}
}
}
The following example shows an APL document that runs the SetValue
command when a watched object updates.
{
"type": "APL",
"version": "2024.2",
"extensions": [
{
"name": "DataStore",
"uri": "alexaext:datastore:10"
}
],
"settings": {
"DataStore": {
"dataBindings": [
{
"namespace": "LocationWeather",
"key": "weather",
"dataBindingName": "DS_Weather"
}
]
}
},
"DataStore:OnObjectChanged": [
{
"type": "SetValue",
"componentId": "txtTemperature",
"property": "temperature",
"value": "${event.data.details.temperature}"
}
],
"mainTemplate": {
"item": {
"type": "Text",
"id": "txtTemperature",
"bind": [
{
"name": "temperature",
"value": "30 °C"
}
],
"text": "The temperature at ${DS_Weather.location} is: ${temperature}"
}
}
}
OnObjectReceived
Invoked as a response to the GetObject
command. The event context provides the requested object.
The following table shows the properties that the OnObjectReceived
handler adds to the event context.
Name | Type | Default | Description |
---|---|---|---|
|
String |
Required |
The |
|
String |
Required |
The |
|
Object |
Required |
The value of the requested data store object. Returns null when the requested object doesn't exist. |
|
String |
"" |
The optional token provided in the |
The OnObjectReceived
handler generates an event with the following form.
{
"namespace": "LocationWeather",
"key": "weather",
"data": {
"location": "Pune, MH",
"details": {
"temperature": "27 °C",
"precipitation": "7%",
"humidity": "51%",
"wind": "5 km/h"
}
},
"token": "thisIsADummyToken",
"event": {
"source": {
"type": "Document",
"handler": "DataStore:OnObjectReceived",
"id": null,
"uid": null,
"value": null
}
}
}
The following example shows an APL document that retrieves an object with GetObject
, and then runs the SetValue
command with data from the retrieved object.
{
"type": "APL",
"version": "2024.2",
"extensions": [
{
"name": "DataStore",
"uri": "alexaext:datastore:10"
}
],
"settings": {
"DataStore": {
"dataBindings": []
}
},
"onMount": {
"type": "DataStore:GetObject",
"namespace": "LocationWeather",
"key": "weather",
"token": "thisIsADummyToken"
},
"DataStore:OnObjectReceived": [
{
"type": "SetValue",
"when": "${event.token == 'thisIsADummyToken'}"
"componentId": "txtContent",
"property": "text",
"value": "The temperature at ${event.data.location} is: ${event.data.details.temperature}"
}
],
"mainTemplate": {
"items": [{
"type": "Text",
"id": "txtContent",
"bind": [
{
"name": "dsContent",
"value": "dummyValue"
}
],
"text": "Waiting for content from DataStore"
}]
}
}
Rules for data binding with the data store
When you bind a property in your APL document to an object in the data store, make sure that you adhere to the following rules:
- Don't bind non-dynamic properties to the data store
- Don't bind the "when" property to the data store
- Don't use an array nested in an
OBJECT
for data array inflation
Don't bind non-dynamic properties to the data store
Not all properties on an APL component are dynamic. A dynamic property on an APL component can re-evaluate during the lifetime of the APL document. A non-dynamic property evaluates one time, when the document initially inflates.
If you bind a data store property to a non-dynamic property and then update the content of the data store, the non-dynamic property won't reflect the change.
For details about which base component properties are dynamic, see the table of properties in APL Base Component Properties. The "Dynamic" column indicates whether the property is dynamic. For details about which component-specific properties are dynamic, see the topic for that component. The properties table in each component topic also has a "Dynamic" column.
Don't bind the "when" property to the data store
You use the when
property on a component to determine whether to inflate and show the component. However, the when
property isn't dynamic. The runtime evaluates when
one time, when the document initially inflates. Therefore, the expression in when
doesn't update if you later update the data store.
Instead, to display or hide a component based on a property in the data store, use the component display
property.
In the following examples, assume that you configured the data store with the dataBindingName
set to MyDataStore
. The object stored at this location has a property called shouldDisplayText
that can be true
or false
.
The following example shows a Text
component that attempts to use when
with the shouldDisplayText
property in the data store. When the document inflates, ${MyDataStore.shouldDisplayText}
evaluates to false
so the component doesn't display. Later, you update this object in the data store and change the shouldDisplayText
property to true
. However, because when
isn't dynamic, the component still doesn't display.
Incorrect: Using 'when' to hide or show a component based on a data store property
{
"when": "${MyDataStore.shouldDisplayText}",
"type": "Text",
"text": "This is a sample text."
}
The following example corrects this problem with the display
property. When the document initially inflates, ${MyDataStore.shouldDisplayText}
is false
. The component sets display
to none
and doesn't show the component. Later, you update the object in the data store and change the shouldDisplayText
property to true
. Because the display
property is dynamic, it re-evaluates and updates to normal
. The component becomes visible.
Correct: Using a dynamic property to hide or show a component based on a data store property
{
"type": "Text",
"text": "This is a sample text.",
"display": "${MyDataStore.shouldDisplayText ? 'normal' : 'none'}"
}
Don't use an array nested in an OBJECT
for data array inflation
You can assign an array to the data
property on a multi-child component, such as a Sequence
. The component then uses the data array inflation method. This means that the components in items
inflate one time for each value in the array.
When working with the data store, you can't use an array nested within an OBJECT
for data array inflation. Instead, you must configure a DataBinding
object with the dataType
property set to ARRAY
, and then bind the component data
property to the data binding object.
Incorrect: Binding the 'data' property to a property in an OBJECT
The following example shows an object that contains a text field (headerTitle
) and a property containing an array (arrayOfItems
).
{
"headerTitle": "This is the title",
"arrayOfItems": [
{
"displayName": "item 1"
},
{
"displayName": "item 2"
},
{
"displayName": "item 3"
}
]
}
You can configure an OBJECT
data binding for this object.
{
"settings": {
"DataStore": {
"dataBindings": [
{
"namespace": "ObjectAndArrayExample",
"key": "mainWidgetData",
"dataBindingName": "dsWidgetData",
"dataType": "OBJECT"
}
]
}
}
}
In this example, you can bind a component property to the ${dsWidgetData.headerTitle}
property of the object. However, binding data
to ${dsWidgetData.arrayOfItems}
doesn't work.
To correct this problem and use data array inflation with the data store, configure a DataBinding
object with the dataType
property set to ARRAY
, and then bind the component data
property to the data binding object. When you update the data store, set the object at the namespace and key to the array of data you want to show.
Correct: Binding the 'data' property to an ARRAY
The following example shows the array arrayOfItems
, now stored as an array and not nested within an OBJECT
.
[
{
"displayName": "item 1"
},
{
"displayName": "item 2"
},
{
"displayName": "item 3"
}
]
Configure the DataBinding
object as an array.
{
"settings": {
"DataStore": {
"dataBindings": [
{
"namespace": "ObjectAndArrayExample",
"key": "arrayOfItems",
"dataBindingName": "dsArrayOfItems",
"dataType": "ARRAY"
}
]
}
}
}
In the Sequence
, bind the data
property to dsArrayOfItems
, and then use data
to access the array in the Sequence
.
{
"type": "Sequence",
"height": "100%",
"width": "100%",
"padding": "@spacingSmall",
"data": "${dsArrayOfItems}",
"items": [
{
"type": "Text",
"text": "${data.displayName}"
}
]
}
To bind properties to both arrays and objects, define multiple DataBinding
objects. The following example defines two DataBinding
objects, one as an OBJECT
and one as an ARRAY
.
{
"settings": {
"DataStore": {
"dataBindings": [
{
"namespace": "ObjectAndArrayExample",
"key": "mainWidgetData",
"dataBindingName": "dsWidgetData",
"dataType": "OBJECT"
},
{
"namespace": "ObjectAndArrayExample",
"key": "arrayOfItems",
"dataBindingName": "dsArrayOfItems",
"dataType": "ARRAY"
}
]
}
}
}
The following example shows an APL document that uses both an OBJECT
and an ARRAY
in the data store.
The following two PUT_OBJECT
commands update both the object and the array in the data store.
[
{
"type": "PUT_OBJECT",
"namespace": "ObjectAndArrayExample",
"key": "mainWidgetData",
"content": {
"headerTitle": "This is the header title"
}
},
{
"type": "PUT_OBJECT",
"namespace": "ObjectAndArrayExample",
"key": "arrayOfItems",
"content": [
{
"displayName": "item 1"
},
{
"displayName": "item 2"
},
{
"displayName": "item 3"
}
]
}
]
Related topics
Last updated: Dec 06, 2023