Content Launcher Integration Guide
This document explains how to integrate Content Launcher into your app. Media applications typically require integration with three key APIs:.
- The Content Launcher API
- Vega Media Controls API
- Account Login API
Content Launcher and Vega Media Controls APIs are implemented in an interactive component, which is the main component handling Vega media queries. The Account Login API is implemented as a service component.
Step 1: Update your App’s manifest file
In your app’s manifest.toml file, include Content Launcher support. This example assumes your package ID is com.amazondeveloper.keplervideoapp
. Replace this package ID with your app’s package ID.
Your app must be properly configured to interact with the Vega Media Content Launcher APIs.
schema-version = 1
[package]
title = "<Your app title>"
id = "com.amazondeveloper.media.sample"
[components]
[[components.interactive]]
id = "com.amazondeveloper.media.sample.main"
runtime-module = "/com.amazon.kepler.keplerscript.runtime.loader_2@IKeplerScript_2_0"
launch-type = "singleton"
# The category "com.amazon.category.kepler.media" is only necessary for the primary component, which is identified in the [[extras]]
# section of the manifest using the "component-id" value.
categories = ["com.amazon.category.main", "com.amazon.category.kepler.media"]
[processes]
[[processes.group]]
component-ids = ["com.amazondeveloper.media.sample.main"]
[offers]
[[offers.interaction]]
id = "com.amazondeveloper.media.sample.main"
[[message]]
uri = "pkg://com.amazondeveloper.media.sample.main"
# Match the privileges used in [[offers.interaction]]. If privileges are not added, then use "*".
sender-privileges = ["*"]
receiver-privileges = ["self"]
[[offers.module]]
id = "/com.amazondeveloper.media.sample.module@ISomeUri1"
includes-messages = ["pkg://com.amazondeveloper.media.sample.main"]
[[extras]]
key = "interface.provider"
component-id = "com.amazondeveloper.media.sample.main"
[extras.value.application]
[[extras.value.application.interface]]
interface_name = "com.amazon.kepler.media.IContentLauncherServer"
# The "override_command_component" field is only necessary when the "component-id" specified in the [[extras]]
# section differs from the one you're providing here. This allows you to use a different component for
# command execution than the one initially defined in the extras, giving you flexibility in your
# configuration setup.
# For example, if you're using Account Login interface in addition to the Content Laucher interface
# you would need to override the Account Login status attribute to be directed to the service
# component with the following line:
# override_command_component = { Status = "com.amazondeveloper.media.sample.interface.provider" }
attribute_options = ["partner-id"]
static-values = { partner-id = "<Your partner id>" }
[needs]
[[needs.module]]
id = "/com.amazon.kepler.media@IContentLauncher1"
partner-id
is the same unique identifier (PARTNER_ID) used in Fire OS launcher integration. Contact your Amazon representative for support and further clarification.Step 2: Include the necessary package dependencies in your app
In the package.json file, add the @amazon-devices/kepler-media-content-launcher
package as a dependency.
"dependencies": {
"@amazon-devices/kepler-media-content-launcher": "^2.0.0",
},
Step 3: Implement the Content Launcher API
-
Define the Content Launcher handler.
Instantiate a new
ContentLauncherServerComponent
. Develop a handler object that encapsulates the callback function.import { ILauncherResponse, IContentLauncherHandler, ContentLauncherStatusType, ContentLauncherServerComponent, IContentSearch, ILaunchContentOptionalFields, } from '@amazon-devices/kepler-media-content-launcher'; ... // Create an instance of ContentLauncherServerComponent let factory = new ContentLauncherServerComponent(); // Create a handler that is called when content is requested to be launched. const contentLauncherHandler: IContentLauncherHandler = { async handleLaunchContent( contentSearch: IContentSearch, autoPlay: Boolean, _optionalFields: ILaunchContentOptionalFields, ): Promise<ILauncherResponse> { console.log('Content_Launcher_Sample: handleLaunchContent invoked'); //Iterate here to fetch data, //business logic to handle launch request let launcherResponse = factory .makeLauncherResponseBuilder() .contentLauncherStatus(ContentLauncherStatusType.SUCCESS) .build(); return Promise.resolve(launcherResponse); }, };
The handler should process the request, return a Promise to
ILauncherResponse
, and create it with an instance of theContentLauncherServerComponent
. Set the status ofcontentLauncherStatus
forLauncherResponse
toContentLauncherStatusType.SUCCESS
if your app successfully processed the request. Set the status toContentLauncherStatusType.AUTH_FAILED
if your app can’t process the request due to authorization issues. Set the status toContentLauncherStatusType.URL_NOT_AVAILABLE
for everything else. -
Implement the Vega Media Content Launcher in your interactive app.
To implement the Vega Media Content Launcher in your interactive app, start by obtaining a singleton instance of
IContentLauncherServerAsync
. You can do this by using thegetOrMakeServer
method on yourContentLauncherServerComponent
instance. Next, create a handler object implementing theIContentLauncherHandler
interface to process content launch requests. Associate this handler with the correct component by calling thesetHandlerForComponent
method for theIContentLauncherServerAsync
instance. Pass the handler and the appropriateIComponentInstance
. In an interactive app, you can obtain theIComponentInstance
using theuseComponentInstance
method. For React Native apps, set up the handler within theuseEffect
hook. It should initialize Content Launcher as soon as the component mounts and theIComponentInstance
are available. This will tightly integrate Content Launcher functionality with your component's lifecycle. It also allows your app to handle Vega Content Launcher commands efficiently from the moment it's initialized. This setup is important for apps with multiple components, as it ensures that each component usesIComponentInstance
, preventing confusion in callback routing.import { useComponentInstance , IComponentInstance } from '@amazon-devices/react-native-kepler'; export const App = () => { const componentInstance: IComponentInstance = useComponentInstance(); useEffect(() => { const factory = new ContentLauncherServerComponent(); const contentLauncherHandler: IContentLauncherHandler = { async handleLaunchContent( contentSearch: IContentSearch, autoPlay: boolean, _optionalFields: ILaunchContentOptionalFields, ): Promise<ILauncherResponse> { console.log('Content_Launcher_Sample: handleLaunchContent invoked.'); // Iterate to fetch data.. //..here const launcherResponse = factory .makeLauncherResponseBuilder() .contentLauncherStatus(ContentLauncherStatusType.SUCCESS) .build(); return Promise.resolve(launcherResponse); }, }; const contentLauncherServer = factory.getOrMakeServer(); contentLauncherServer.setHandlerForComponent(contentLauncherHandler,componentInstance); return () => {}; }, []); // Create a user interface for your provider app here. };
Implementation details
The IContentLauncherHandler
handler takes three parameters that define what content to play or show search results.
- A pointer to an object implementing
IContentSearch
interface. - A boolean value called
autoPlay
. - Optional additional fields passed through a pointer to an object implementing the
ILaunchContentOptionalFields
interface.
Use autoPlay to determine what action to perform.
If autoPlay
is true, it is a quick play request. Requested content should start playing directly without further interaction by the user. If autoPlay
is false, then show the search results. The user can then review and select from the available options.
Retrieve contentSearch:IContentSearch values.
This parameter includes the content the user sent by Content Launcher and Alexa. The following schema is for the values stored in contentSearch:IContentSearch
.
1 "parameterList": [{
1.1 "type": "<entity type>",
1.2 "value": "<entity value>",
1.3 "externalIdList": [{
1.3.1 "name": "<externalId name>",
1.3.2 "value": "<externalId value>"
}]
}]
1 ParameterList
has one or more entries. contentSearch.getParameterList().length
is used to retrieve the full list.
1.1 <entity type> represents the type of the entity listed in the parameter. For a list of all supported entity types, see Enumeration ContentSearchParamType. For example, “type”
is “ContentSearchParamType::VIDEO”
if it's a movie or TV Show. Call getParamType()
to fetch the type.
1.2 <entity value> represents the value of the entity mentioned in the type. Call getValue()
to retrieve this field.
1.3 parameterList
has one or more external IDs. Use getExternalIdList().length
to get the size of the list. getExternalIdList()
will provide the full list of externalIdList
.
1.3.1 getName()
usually retrieves the <externalId name>. If the externalId
name is amzn_id
, look for its value.
1.3.2 <externalId value> represents the value of the externalId
. To retrieve the value, use getValue()
. getValue()
contains the same <ID> or <launchId> values used in your catalog integration, allowing you to know which content the user desires to watch.
externalId
value may contain catalogContentId
or <catalog id>, both of which will have the same value as amzn_id. However, the catalogContentId
and <catalog id> elements will be deprecated soon, so ignore them and use only amzn_id
launchId
is present, the externalId
value is the launchId
. If the launchId
is not present in your catalog, the <ID> value is sent. If Alexa voice initiates the request, you get only the <ID> value regardless of the presence of the launchId
in the catalog. When you use the entity ID value to search your catalog, search both ID and launchId
fields of your catalog. Example: Extract and search for the requested search parameter
The following code example demonstrates how to extract and search for the requested search parameter. This approach consolidates various pieces of information into a single string that you can modify to and use within the handleLaunchContent
method.
This example launches an episode using the following Alexa utterance: “watch The SeaShow: The Real story, season two, episode five in Streamz.”
// Iterator to fetch data.
let searchParameters = contentSearch.getParameterList();
if (searchParameters.length > 0) {
for (var j = 0; j < searchParameters.length; j++) {
let paramType = searchParameters[j].getParamType();
let searchString = searchParameters[j].getValue();
let additionalInfoList = searchParameters[j].getExternalIdList();
for (var i = 0; i < additionalInfoList.length; i++) {
let searchName = additionalInfoList[i].getName();
let entityID = additionalInfoList[i].getValue();
if (searchName == 'amzn_id') {
// Use this entity ID to get exact content from your catalog.
} else {
// ex:
// entityID= "ENTITY_ID" :
// searchName = "amzn1.p11cat.merged-video.087c9371-6bb7-5edb-bcef-f8717fde0a8a"
//
}
}
}
if (autoPlay) {
console.log(`Content_Launcher_Sample: Quickplay`);
// Handle play logic here using the data retrieved above.
} else {
console.log(`Content_Launcher_Sample: In-App search`);
// Handle search logic here using the data retrieved above.
}
} else {
console.log('Content_Launcher_Sample: Error fetching search string');
}
// Iterator to fetch data.
Content Launcher request examples
The examples below explain contentSearch
parameter values for some key content launcher use cases. All supported use cases are listed. Content Launcher will be invoked and the application will be launched for every use case.
The following sample catalog for streamz_us
includes example entries for the movie Seabound and the TV show The SeaShow: The Real Story.
...
<Movie>
<ID>1700000725</ID>
<Title locale="en-US">Seabound</Title>
<Offers>
<SubscriptionOffer>
<LaunchDetails>
<Quality>UHD</Quality>
<Subtitle>en-US</Subtitle>
<LaunchId>tv.streamz/movie/46720001</LaunchId>
</LaunchDetails>
</SubscriptionOffer>
<FreeOffer>
<Regions>
<Territories>US</Territories>
</Regions>
<LaunchDetails>
<Quality>SD</Quality>
<Subtitle>en-US</Subtitle>
<LaunchId>tv.streamz/movie/467200002</LaunchId>
</LaunchDetails>
</FreeOffer>
</Offers>
</Movie>
<TvShow>
<ID>1700000123</ID>
<Title locale="en-US">The SeaShow: The Real story</Title>
<Offers>
<FreeOffer>
<Regions>
<Territories>US</Territories>
</Regions>
<LaunchDetails>
<Quality>HD</Quality>
<Subtitle>en-US</Subtitle>
<LaunchId>459800033</LaunchId>
</LaunchDetails>
</FreeOffer>
</Offers>
</TvShow>
<TvSeason>
<ID>1700000234</ID>
<Title locale="en-US">Season 1</Title>
<Offers>
<FreeOffer>
<Regions>
<Territories>US</Territories>
</Regions>
<LaunchDetails>
<Quality>HD</Quality>
<Subtitle>en-US</Subtitle>
<LaunchId>453200012</LaunchId>
</LaunchDetails>
</FreeOffer>
</Offers>
<ShowID>1700000123</ShowID>
<SeasonInShow>2</SeasonInShow>
</TvSeason>
<TvEpisode>
<ID>1700000825</ID>
<Title locale="en-US">The Seashow. Story Starts</Title>
<Offers>
<FreeOffer>
<Regions>
<Territories>US</Territories>
</Regions>
<LaunchDetails>
<Quality>HD</Quality>
<Subtitle>en-US</Subtitle>
<LaunchId>453100008</LaunchId>
</LaunchDetails>
</FreeOffer>
</Offers>
<ShowID>1700000123</ShowID>
<SeasonID>1700000234</SeasonID>
<EpisodeInSeason>5</EpisodeInSeason>
</TvEpisode>
...
Launch content through the remote
Launch the movie Seabound using a remote from the Vega TV Home screen.
"parameterList": [
{ // parameter 0
"type": 13, // ContentSearchParamType::VIDEO,
"value": , // Content title will not be populated
"externalIdList": [{
"name": "catalogContentId", // Will be deprecated. Ignore this
"value": "tv.catalog/movie/46720000" // ID or LaunchId from catalog
},
{
"name": "amzn_id",
"value": "tv.catalog/movie/46720000" // ID or LaunchId from catalog
}
]
}
]
The application should identify the movie using tv.streamz/movie/46720000
for the LaunchId
, and play it directly.
LaunchId
, <ID> will be passed as the value.Quickplay with voice
Play movie Seabound through voice. Use the utterance “Alexa, Play Seabound.”
autoPlay
will be true
here. contentSearch: IContentSearch
will have values as seen in the following sample. The application will be launched and it should play content directly using ID 1700000725
.
[
{ // parameter 0
"type": 13, // ContentSearchParamType::VIDEO
"value": "Seabound", // search string
"externalIdList": [{
"name": "streamz_us" // your catalog id. Will be deprecated. Ignore this
"value": "1700000725" // ID from catalog
},
{
"name": "amzn_id"
"value": "1700000725" // ID from catalog
}
]
}
]
streamz_us
is a placeholder for the catalog ID in this example. Alexa will not use LaunchID
even when it is present in the catalog.Playing a specific episode with voice
The catalog sample below represents a TV Show SeaShow: The Real story, its season, and an episode. The Alexa utterance “Alexa, Play Season 2 Episode 5 from The SeaShow: The Real story,” will invoke the application to play the specific episode.
autoPlay
will be true
here. contentSearch
will have only the ID of the show, not the episode ID. The application must identify the exact episode using ID 1700000123
, ContentSearchParamType::SEASON
, and ContentSearchParamType::EPISODE
values.
[
{ // parameter 0
"type": 13, // ContentSearchParamType::VIDEO
"value": "Season Two Episode Five The SeaShow: The Real story",
"externalIdList": [{
"name": "streamz_us", // Will be deprecated, Ignore this
"value": "1700000123" // ID of the Show from catalog
},
{
"name": "amzn_id",
"value": "1700000123" // ID of the Show from catalog
}]
},
{ // parameter 1
"type": 14, // ContentSearchParamType::SEASON
"value": "2", // Season number in catalog
"externalIdList": []
},
{ // parameter 2
"type": 15, // ContentSearchParamType::EPISODE
"value": "5", // episode number in catalog
"externalIdList": []
}
]
In-app search for a content title using voice
Search for movie, Seabound, using voice. Do do this, use the utterance "Alexa, find Seabound in Streamz."
The application must show the search result with Seabound and related content. The search logic is left to the app. autoPlay
will be false
here. contentSearch: IContentSearch
will have the following values.
[
{ // parameter 0
"type": 13, // ContentSearchParamType::VIDEO
"value": "Seabound", // Search keyword to use in search
"externalIdList": [{
"name": "streamz_us", // Will be deprecated. Ignore this
"value": "1700000725" // ID from catalog
},
{
"name": "amzn_id",
"value": "1700000725" // ID from catalog
}
]
}
]
In-app search for a genre using voice
Search for a genre using voice with the utterance “Alexa, find comedy movies in Streamz.”
autoPlay
will be false
. contentSearch: IContentSearch
will have following values. Alexa will return multiple genres and types. You can chose your own logic to implement search.
[
{ // parameter 0
"type": 6, // ContentSearchParamType::GENRE
"value": "Comedy", // Search keyword to use in search
"externalIdList": []
},
{ // parameter 1
"type": 6, // ContentSearchParamType::GENRE
"value": "Dark Comedy", // Search keyword to use in search
"externalIdList": []
},
{ // parameter 2
"type": 6, // ContentSearchParamType::GENRE
"value": "Romantic Comedy", // Search keyword to use in search
"externalIdList": []
},
{ // parameter 3
"type": 13, // ContentSearchParamType::TYPE for VIDEO
"value": "comedy movies", // keyword to use in search
"externalIdList": []
}
]
In-app search for an actor using voice
Search for an actor using voice with the utterance “Alexa, find Sean Connery movies in Streamz.”
autoPlay
will be false
. contentSearch: IContentSearch
will have following values.
[
{ // parameter 0
"type": 0, // ContentSearchParamType::ACTOR
"value": "Sean Connery" // Keyword to use in search
"externalIdList": []
},
{ // parameter 1
"type": 13, // ContentSearchParamType::TYPE for VIDEO
"value": "Sean Connery movies", // Keyword to use in search
"externalIdList": []
}
]
Last updated: Sep 30, 2025