Developer Console

Step 5: Build Your Web Player (VSK Echo Show)

In this step, you will build your own web player. The web player will reference and initialize the Alexa JavaScript library and provide other functionality.

Web player requirements

As you build your own web player, keep in mind these requirements around codecs, formats, and standards:

Video requirements:

  • MP4 H.264
  • Widevine DRM Level 1
  • Encrypted Media Extensions (EME)
  • Media Source Extensions (MSE)

Audio requirements:

  • MP4 with AAC
  • WebM with Vorbis
  • WebM with Opus
  • AAC-LC is supported, but AAC-SBR is not. Media should follow the audio specifications defined for "chromium" to ensure proper playback. More information on chromium can be found in Audio/Video in the Chromium Projects site.

Screen resolution requirements

Video content sent to Amazon devices cannot be of a higher resolution than the display’s resolution. Check the display’s resolution in your web app with the following:

var displayHeight = window.screen.height * window.devicePixelRatio;
var displayWidth = window.screen.width * window.devicePixelRatio;

Your web player must select a video resolution less than or equal to the height and width calculated above. If your video resolution is greater than the display’s resolution, the device may experience dropped frames, lagging, or sometimes not play your video content at all.

The user agent string (window.navigator.userAgent) will always be prepended with AlexaWebMediaPlayer.

  • Example of a user agent string: AlexaWebMediaPlayer/1.0 (Linux; Android 7.1.2)

If any of the requirements above are different from your existing stream-picking logic, use the user agent string to check if you are running on an Echo Show device. If you are, use the above guidance.

Build your own web player

To build your own web player, complete the high-level tasks described in each of the following sections.

Migrate or build your web player

If you have existing web assets that deliver your content, isolate the web player component and supporting functionality such as metrics reporting, advertisement logic, and other dependencies. Your video must play exclusively in full-screen mode. Links to any other website are restricted.

Style your web player

Style your web player to apply the visual controls and non-video elements of your player. For certification guidelines related to the video experience, see Test for Certification.

Include the Alexa Video JavaScript library

The alexa-web-player-controller JavaScript library provides a communication bridge between Alexa and your web player. Load the JavaScript library with the following script tag in your HTML:

<script type="text/javascript" src=""></script>

Initialize the Alexa Video JavaScript library

In your web app's initialization code, wait for the Alexa object to be ready, then initialize the alexa-web-player-controller library with your readyCallback and errorCallback. The readyCallback is invoked when the library is ready for execution.

In the readyCallback, you receive a controller object to communicate with the library, which includes the control methods. The errorCallback is invoked if there is an error that causes the web player to close. The user receives a human-readable error message.

The alexa-web-player-controller library closes the web container after sending the error message. During initialization of the library, you may also optionally register event handlers by adding an argument containing a map of callback functions keyed by event names. Otherwise you can register handlers using the controller.on(handlers) / controller.on(event, handler) method explained in the next section. The handlers play, pause, and resume are required.

If your player supports closed captions, call the getClosedCaptionsState method during initialization. The initialization sequence is considered complete when the setPlayerState method is called with state IDLE. More information about the getClosedCaptionsState and setPlayerState methods is provided in the following sections.

// Load Alexa Video JavaScript library before this script.
AlexaWebPlayerController.initialize(readyCallback, errorCallback);


AlexaWebPlayerController.initialize(readyCallback, errorCallback, handlers);

Register event handlers

Register handlers using the controller.on(handlers) /controller.on(event, handler) method. The handlers play, pause, and resume are required.

function readyCallback(controller) {
    var Event = AlexaWebPlayerController.Event;
    var handlers = {
        Event.LOAD_CONTENT: function handleLoad(params) {},
        Event.PAUSE: function handlePause() {},
        Event.RESUME: function handleResume() {},
        Event.ADJUST_SEEK_POSITION: function handleAdjustPos(offsetInMilliseconds) {},
        Event.NEXT: function handleNext() {},
        Event.PREVIOUS: function handlePrevious() {},
        Event.CLOSED_CAPTIONS_STATE_CHANGE: function handleCCState(state) {},
        Event.PREPARE_FOR_CLOSE: function handlePrepareForClose() {},
        Event.ACCESS_TOKEN_CHANGE: function handleAccessToken(accessToken) {}

The following table describes the various handlers and their parameters.

Key Key Desc. Handler Parameter Type Param. Desc.
LOAD_CONTENT Load a given piece of content. params.contentUri string URI of content provided in Video Skill API response.
params.accessToken string User credentials
params.offsetInMilliseconds integer Offset from beginning of content to begin playback.
params.autoplay boolean Flag to automatically play content after loading. We expect the player to initiate playback when autoplay=true and to load into a PAUSED state when autoplay=false.
PAUSE Pause playback none
RESUME Resume playback none
ADJUST_SEEK_POSITION Change playback position by an offset from the current position. offsetInMilliseconds integer If positive, offset from start. If negative, offset from end.
NEXT Advance to the next video, if available. none
PREVIOUS Go back to the previous video, if available. none
CLOSED_CAPTIONS_STATE_CHANGE Update closed captions state state object Closed captions state including enabled, text, background, window background.
PREPARE_FOR_CLOSE Prepare for the device to close the web container in 250 ms, and handle any remaining actions none
ACCESS_TOKEN_CHANGE Update access token accessToken string User credentials

Implement handlers

How you handle commands depends on the implementation of your player. All handlers must return a Promise object to be resolved on successful handling of the command or rejected with an error object with errorType and message if there is a failure. If a failure occurs for PLAY, PAUSE or RESUME, the device calls PREPARE_FOR_CLOSE and tries to close the web player.

For the LOAD_CONTENT operation, your handler receives parameters including contentUri sent in your AWS Lambda function response representing the content to be played. If your service requires the user be authenticated to stream content, an accessToken is included as well. Additional details may also be included, such as offsetInMilliseconds if the user is picking up in the middle of content, or autoplay if the content needs to auto play after loading. The handler returns a Promise object to be resolved on successful handling of the play command or rejected with an error object with errorType and message if there is a failure.

Hide loading overlay

Your player is not visible until controller.showLoadingOverlay is called with a value of false. Make the call after loading your assets are loaded and the experience is ready to show. You must call this method to disable the overlay when the content is loaded and UI presentable. The loading overlay is always shown during initialization.

Subsequent calls to load content (such as calls for new, unrelated content) allow you to turn on the loading overlay and turn it off appropriately, but is not required. If you want a custom loading screen, you can disable this before content is ready and provide your own visualizations. This must not be called when content is playing.


Send playback lifecycle events to Alexa

When your player changes state, use the controller.setPlayerState(playerState) method to pass along the lifecycle events to Alexa. The playerState includes two properties, State and positionInMilliseconds.

Call the controller.setPlayerState(playerState) method any time the player state changes.

The playerState needs to match the current content playback behavior so Alexa doesn’t close the web container during playback or persist the container for too long when playback is paused or stalled.

    state: AlexaWebPlayerController.State.IDLE,
    positionInMilliseconds: 0

The following table lists the player states.

Player States
State Description
IDLE Player is idle; no content is loaded or playing. Player is ready to stream content.
BUFFERING Playback is suspended due to content buffering.
PLAYING Player is actively streaming content.
PAUSED Playback is suspended during content.

Configure allowed operations

When the allowed operations for Alexa change, set the allowed operations by using controller.setAllowedOperations(allowedOperatons) through the JavaScript library. Allowed operations require handlers, which are not pre-implemented. By default, an operation is not allowed until the handler has been implemented and the operation is set to true in allowedOperations.

    adjustRelativeSeekPositionForward: true,
    adjustRelativeSeekPositionBackwards: true,
    setAbsoluteSeekPositionForward: true,
    setAbsoluteSeekPositionBackwards: true,
    next: true,
    previous: true,
setAllowedOperations Parameters
Name Type Prerequisite Handler Description
allowedOperations object N/A Allowed operations for content currently in the player.
adjustRelativeSeekPositionForward boolean adjustSeekPosition If true, allow user to seek forward relative to the current position.
adjustRelativeSeekPositionBackwards boolean adjustSeekPosition If true, allow user to seek backwards relative to the current position.
setAbsoluteSeekPositionForward boolean setSeekPosition If true, allow user to seek forward to an absolute position.
setAbsoluteSeekPositionBackwards boolean setSeekPosition If true, allow user to seek backwards to an absolute position.
next boolean next If true, allow user to request the next content in the play queue.
previous boolean previous If true, allow the user to request the previous content in the play queue.

Send content metadata to Alexa

Pass along metadata for the current content in the controller.setMetadata(metadata) method. Do this for both the initial content and any new content played thereafter.

    type: AlexaWebPlayerController.ContentType.TV_SERIES_EPISODE,
    value: {
        name: "name",
        closedCaptions: {
            available: true
        durationInMilliseconds: 1000,
        series: {
            name: "name",
            seasonNumber: 1
        episode: {
            number: 1,
            name: "name"

Metadata for other video:

    type: AlexaWebPlayerController.ContentType.VIDEO,
    value: {
        name: "",
        closedCaptions: {
             available: true
        durationInMilliseconds: 1000,
setMetadata Parameters
Name Description Req'd Type Values
type Content type of the metadata. Yes String AlexaWebPlayerController.ContentType
value Value of the metadata. Each type may have a different set of values. Yes Object JSON object
name Name of the video. Yes String Example: Interstellar
closedCaptions Closed captions of the video. Yes Object JSON object
available Availability of the closed captions. Yes Boolean true, false
durationInMilliseconds Duration of the video in milliseconds. No Number Example: 3141343
series Metadata of a series. No Object JSON Object
name Name of a series. No String Example: Survivor: Borneo
seasonNumber Number of the season. No String Example: 1
episode Metadata of an episode. No Object JSON Object
name Name of the episode. No String Example: The Marooning
number Number of the episode. No String Example: 1
Content Types for AlexaWebPlayerController
Value (string) Description
TV_SERIES_EPISODE TV_SERIES_EPISODE Content type for TV series episode
VIDEO VIDEO Content type for video

Get and set the state of closed captions

Retrieve the device-level setting for closed captions at the beginning of playback by using the controller.getClosedCaptionsState() method. To toggle closed captions on and off, use the controller.setClosedCaptionsStateEnabled(enabled) method.


controller.setClosedCaptionsStateEnabled(isEnabled: boolean);

Closed captions state:

    enabled: ,
    text: {
        size: ,
        color: ,
        opacity: ,
        font: ,
        edge: ,
    background: {
        color: ,
        opacity: ,
    windowBackground: {
        color: ,
        opacity: ,
closedCaptions Parameters
Name Description Type Values
enabled Whether the closed captions are enabled Boolean true, false
text Text preference Object N/A
size Size of the text Number Text Size (in pixels)

Example: 10

color Color of the text String Text Color (RGB value in HEX code)

Example: #ff0000
opacity Color opacity of the text Number Text Color Opacity (alpha value between 0 - 1.0)

Example: 1.0
font Font of the text. String Font (from Google Fonts)

  1. Default (Selected by caption author)
  2. Casual ( = "ComingSoon")
  3. Cursive ( = "DancingScript-Regular")
  4. Monospace Sans ( = "DroidSansMono")
  5. Monospace Serif ( = "CutiveMono")
  6. Sans Serif ( = "Roboto-Regular")
  7. Serif ( = "NotoSerif-Regular")
  8. Small Capitals (= "CarroisGothicSC-Regular")
edge Edge style of the text. Number Edge Style:

  1. None ( = 0, no character edges)
  2. Uniform ( = 1, uniformly outlined character edges)
  3. Drop Shadowed ( = 2, drop-shadowed character edges)
  4. Raised ( = 3, raised bevel character edges)
  5. Depressed ( = 4, depressed bevel character edges)
background Text background preference. Object N/A
color Color of the text background. String Text Background color(This is the RGB value of the color)

Example: #ff0000
opacity Opacity of the text background Number Text Background Opacity* Percentage (disabled when Text Background Color set to default; alpha value between 0 - 1.0)

Example: 1.0
windowBackground Window background preferences Object N/A
color Color of the closed captions window background. String Window Background color (RGB value)

Example: #ff0000
opacity Opacity of the closed captions window background. Number Window Background Opacity (disabled when Window Background Color set to default; alpha value between 0 - 1.0)

Example: 1.0

Report fatal errors

If your player encounters an error and is unable to play content, use the controller.sendError(error) method to send a fatal error to Alexa. Alexa hides the web app, call the PREPARE_FOR_CLOSE handler and close the web player. For non-fatal errors, there is no need to send back to Alexa.

    type: AlexaWebPlayerController.ErrorType.PLAYER_ERROR,
    message: 'Error message as string'
Error Types
Error Type Description
PLAYER_ERROR Send PLAYER_ERROR event when there is an unrecoverable error having to do with the media player.
CLIENT_ERROR For any client side error not related to the player, send an CLIENT_ERROR.
SERVER_ERROR SERVER_ERROR indicates an error occurred in server side including failed requests, unable to buffer content, unreachable assets, and any connectivity issues.

Create ending experience

When you think the play session has ended, call controller.close() method to inform Alexa. Alexa then hides the web app, calls the PREPARE_FOR_CLOSE handler, and ends the experience.


Host the web player on a publicly accessible URL

Finally, make your player available on a public URL. Make sure your web player can be accessed by using HTTPS, because Alexa devices require a secure connection.

At this point, your web player is almost ready to be tested on a multimodal device. But first, you must implement the required Video Skill APIs in your skill's Lambda function as described in the next section, Step 6: Respond to Alexa Directives Delivered to Lambda.

Next steps

Go on to Step 6: Respond to Alexa Directives Delivered to Lambda.

Last updated: Jan 04, 2023