Reduce Latency for your APL Documents

Users expect skills to respond to their requests without any delays. When your skill includes a visual component, latency in displaying the content might degrade the user experience.

Use these best practices to improve the performance of your Alexa Presentation Language (APL) document and reduce the latency that the user might notice.

Use Alexa Vector Graphics (AVG) instead of images

Images make the content more engaging, but they can also increase latency. When you display an image in an APL document, the device must load the image from the image source URL that you provide.

You can decrease latency by displaying a vector graphic instead of an image. The Alexa Vector Graphics (AVG) format lets you define a graphic with JSON code. You then display the graphic by placing a VectorGraphic component in your document.

For details about the AVG format, see Alexa Vector Graphics Format.

For details about the VectorGraphic component, see VectorGraphic.

Use dynamic data sources for long, scrolling lists

When you display a long, scrolling list of items, use a dynamic data source. You send your data to the device in smaller batches. Alexa requests additional data from your skill as the user scrolls through the list and your skill responds with an updated data source with the new data to display.

You can use progressive loading ("lazy loading") with the responsive templates that display lists:

When building your own document, you can use progressive loading with the following components:

To use progressive loading for your list

  1. Define your data source with your list items as a dynamicIndexList data source. For details, see dynamicIndexList data source.
  2. In your APL document, bind the data source to the component that displays the list.
    • When you use a responsive template, bind the data source to the listItems property.
    • When you build your own list from primitive components, such as Sequence, bind the data source to the data property.

    For details, see Bind a dynamic data source to your APL document

  3. In your skill code, use directives to manage the list as the user scrolls. For details, see Use directives and requests to manage the list.

For a dynamic data source example, see APL Lazy Loading Lists Demo.

Limit the number of URL-based package imports

APL packages let you define common layouts in resources in a separate file and then import them into your document with the import property. Packages are a key element for creating modular APL documents that are easier to maintain. However, package imports do impose a cost because the device must retrieve the package from a URL or from the cache before rendering your document. Furthermore, packages can import other packages, which can increase the load.

Guidelines when importing packages:

  • Make sure you need all the packages you import. Remove any packages that you don't reference within your APL document.
  • Importing a single, larger package is better than importing several small packages due to the time to open connections and download the package.

One good strategy to consider is to import alexa-layouts for the responsive components and layouts, and then one additional custom package with your own custom layouts as needed.

Use the backstack to return to previous documents

The backstack extension lets users navigate to previously-viewed APL documents. When you use the backstack to go back to an earlier document, the device can render the document faster because the document was already inflated.

Using the backstack also eliminates any requirement to send a request to your skill and wait for your skill to return the RenderDocument directive with the previous document.

For details about the backstack extension, see APL Backstack Extension.

Use layouts when possible

A layout works as a custom component built from primitive components and layouts. Layouts help you build more modular documents, which are easier to maintain. You can also re-use layouts in your document, which simplifies the code.

Using layouts helps reduce latency. The device caches the layouts when inflating your document. Therefore, the layout loads faster as the device displays your document.

For details about building a custom layout, see APL Layout.

Do on-device updates instead of round-trips to your skill code

You can use the SendEvent command in your APL document to send a UserEvent request to your skill. Your code handles this event and returns a response. The response might include content to speak, the RenderDocument directive to display an updated APL document, or the ExecuteCommands directive to run commands that update the existing document.

The SendEvent command is useful for notifying your skill about updates taking place on the device and triggering Alexa voice responses, but relying on this "round-trip" between the device and your skill adds latency. Resending the RenderDocument directive from the UserEvent request to render an updated APL document is also a slower and more costly operation.

Instead, use APL commands to update the visual presentation directly without sending a request back to your skill and waiting on a response. Avoid resending the entire document with the RenderDocument directive when possible.

You can then use the SendEvent command after making the visual changes to notify your skill of the change if necessary. The user sees the visual update right away, without waiting on the round-trip back to your skill.

For example, the following array of commands updates a bound property called PressCount, runs an animation to fade a Text component into view, and then sends the skill a UserEvent with the latest value of the bound property. From the user's perspective, the screen updates right away with no latency.

[
    {
        "type": "SetValue",
        "property": "PressCount",
        "value": "${PressCount + 1}"
    },
    {
        "when": "${PressCount == 1}",
        "type": "AnimateItem",
        "duration": 2000,
        "componentId": "buttonPressCount",
        "value": {
            "property": "opacity",
            "to": 1
        }
    },
    {
        "type": "SendEvent",
        "arguments": [
            {
                "buttonPressed": "pressCountButton",
                "pressCount": "${PressCount}"
            }
        ]
    }
]

The following example shows the full APL document. The Count the presses button increments a counter and displays the total number of button presses on the screen. The Reset the count button resets the counter to zero and hides the text noting the number of button presses. Both buttons call SendEvent to notify the skill of the current button press count after the other commands finish.

The following example shows a request handler for the UserEvent generated by the two buttons. Because the SendEvent takes place after the visual update, the delay during the round trip to the skill is less noticeable.

Copied to clipboard.

This sample code uses the Alexa Skills Kit SDK for Node.js (v2).

const ButtonPressEventHandler = {
    canHandle(handlerInput){
        // Use this handler for both buttons

        const requestEnvelope = handlerInput.requestEnvelope;

        return Alexa.getRequestType(requestEnvelope) === 'Alexa.Presentation.APL.UserEvent'
         && (requestEnvelope.request.source.id === 'pressCountButton'
         || requestEnvelope.request.source.id === 'resetButton');

    },
    handle(handlerInput){
        console.log("In the ButtonPressEventHandler");

        // Get button data from the arguments and log it. In a real
        // skill, we might save these values to persistent storage or
        // create a voice response specific to the input
        const buttonData = handlerInput.requestEnvelope.request.arguments[0];

        console.log("We got data about the button press from the device.");
        console.log("Button press reported: " + buttonData.buttonPressed);
        console.log("Latest button press count: " + buttonData.pressCount);

        // Return a spoken response just for the reset button.
        if (buttonData.buttonPressed === 'resetButton'){
            return handlerInput
                .responseBuilder
                .speak("I've reset your button count to zero.")
                .getResponse();
        }

    }
};

For details about how APL commands work, see APL Commands. For the set of available commands, see:

For details about the RenderDocument directive and UserEvent request, see Alexa.Presentation.APL Interface Reference.