Understanding Amazon Fire TV Content Launcher Integration: A Developer's Guide

:loudspeaker: Previous posts can be used in conjunction with this one. The 2024 Guide is also listed as part of this guidance and is available under the following link (we’ve since updated our service):

July 31st 2025, by @cebratec, @Mark_Schuster, @Peter_Hammel, @Tushar_Jadhav, @rsack

Universal Search and Browse, Account Login & Personalization

Fire TV supports searching and launching content using a Fire TV remote, touch, or voice. The modality agnostic Content Launcher API supports searching, browsing, and playing content using different interfaces.


Image 1: Universal Search and Browse

This guide will focus on a step by step walkthrough to achieve the following three areas:

    1. Universal Search and Browse
    1. Adding Account Login
    1. Adding Personalization (Continue Watch) Feature

Your entry point to anything Content Launcher in the documentation on our Dev Portal is here.


Before you start (Prerequesite)

All catalog integrated apps must integrate the Content Launcher API. Catalog integration is the process of describing your app’s media according to Amazon’s Catalog Data Format (CDF), and then regularly uploading the catalog to an S3 bucket at Amazon. Contact your Amazon representative if you have any questions around that specifically.

We also recommend reading the Content Launcher Overview before diving. in.


1. Universal Search and Browse

Universal Search and Browse allows users to discover your app’s content on Fire TV, even if they don’t have the app installed. Catalog file integrates your app’s media’s metadata into the Fire TV home screen and global search results. This catalog file allows your app’s content to appear in users searches and in watch options on the content details pages.

This guide will cover a real life example, the general guidance can be found here:

Step 1: Update your manifest file

This part can be also found as part of our documentation on the developer portal, here.

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.

If you are unsure about your PartnerID contact your Amazon representative.

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>" }

Step 2: Include the necessary package dependencies in your app:

(...)

"dependencies": {
    "@amzn/react-native-kepler": "~2.0.0",
    "@amzn/kepler-media-content-launcher": "^2.0.0",
    (...)
},

(...)

Step 3: Implement the Content Launcher API

In your App.tsx you will want to include the following setup:

import {
  usePreventHideSplashScreen,
  useHideSplashScreenCallback,
  useComponentInstance,
  IComponentInstance,
} from '@amzn/react-native-kepler';

import {
  ILauncherResponse,
  IContentLauncherHandler,
  ContentLauncherStatusType,
  ContentLauncherServerComponent,
  IContentSearch,
  ILaunchContentOptionalFields,
} from '@amzn/kepler-media-content-launcher';

// (...)

const AppInitialization = () => {
    
    const componentInstance: IComponentInstance = useComponentInstance();

    // Content Launcher setup
  useEffect(() => {
    if (componentInstance) {
      const factory = new ContentLauncherServerComponent();

      const contentLauncherHandler: IContentLauncherHandler = {
        async handleLaunchContent(
          contentSearch: IContentSearch,
          autoPlay: boolean,
          _optionalFields: ILaunchContentOptionalFields
        ): Promise<ILauncherResponse> {

          try {
            const searchParameters = contentSearch.getParameterList();
            if (searchParameters.length > 0) {
              for (const searchParameter of searchParameters) {
                const paramType = searchParameter.getParamType();
                const searchString = searchParameter.getValue();

                const additionalInfoList = searchParameter.getExternalIdList();
                for (const additionalInfo of additionalInfoList) {
                  const searchName = additionalInfo.getName();
                  const entityID = additionalInfo.getValue();

                  if (searchName === 'amzn_id') {
                    // Use this entity ID to get exact content from your catalog.
                    console.log('Found Amazon ID:', entityID);

                    // Content Launcher should always navigate directly to video player
                    console.log('Content Launcher - loading and playing content:', entityID);

                    // Load the content first, then navigate to video player
                    try {
                       // IMPLEMENT HERE
                      // load content and navigate to your video player and play content
                    } catch (error) {
                      console.log('Content Launcher - error loading content:', entityID, error);
                    }
                  } else {
                    // ex:
                    // entityID= "ENTITY_ID" :
                    // searchName = "amzn1.p11cat.merged-video.087c9371-6bb7-5edb-bcef-f8717fde0a8a"
                    //
                    console.log('Other search identifier:', searchName, entityID);

                    // For other search identifiers, also load and play content
                    console.log(
                      'Content Launcher - loading and playing content for identifier:',
                      entityID
                    );
                    try {
                      const content = await ContentHelper.loadContent(
                        entityID,
                        Content.movieDetailRequiredFields,
                        false
                      );
                      if (content !== undefined && content !== null) {
                        ContentHelper.handlePlay(
                          refNavigation.current as unknown as NavigationProp<RootStackParamList>,
                          content,
                          VideoType.Default,
                          false
                        );
                        console.log(
                          'Content Launcher - successfully initiated playback for identifier:',
                          entityID
                        );
                      } else {
                        console.log(
                          'Content Launcher - failed to load content for identifier:',
                          entityID
                        );
                      }
                    } catch (error) {
                      console.log(
                        'Content Launcher - error loading content for identifier:',
                        entityID,
                        error
                      );
                    }
                  }
                }
              }
              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');
            }

            const launcherResponse = factory.makeLauncherResponseBuilder()
              .contentLauncherStatus(ContentLauncherStatusType.SUCCESS)
              .build();

            return Promise.resolve(launcherResponse);
          } catch (error) {
            console.log('Error handling content launch:', error);

            const launcherResponse = factory.makeLauncherResponseBuilder()
              .contentLauncherStatus(ContentLauncherStatusType.URL_NOT_AVAILABLE)
              .build();

            return Promise.resolve(launcherResponse);
          }
        },
      };

      const contentLauncherServer = factory.getOrMakeServer();
      contentLauncherServer.setHandlerForComponent(contentLauncherHandler, componentInstance);

      console.log('Content Launcher initialized successfully');

      return () => console.log('Content Launcher cleanup');
    }
  }, [componentInstance, refNavigation]);


// (...)

}


2. Adding Account Login (with Headless)

If you are integrating into an existing headless setup, this guide will be most applicable to you. If you don’t have an existing headless implementation, you can refer to the docs directly on the Developer Portal.

The Vega Media Account Login API provides a way for apps to report their authentication status to the system. Apps need to refresh the user’s login status upon each launch, which is done by the Account Login API. There are two account login states: signed in, and signed out. By keeping the login status up-to-date, apps make sure that users have access to appropriate content and features.


Image 2: Example of an authenticated state for Universal Search


Image 3: Example of a non-authenticated state for Universal Search

Apps should update the system with their login status in the following situations:

  • During the app’s initial launch
  • When there’s a change in the user’s subscription status
  • Upon request from other services

Step 1: Update the app manifest

 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"]
+
+[[components.service]]
+id = "com.amazondeveloper.media.sample.interface.provider"
+runtime-module = "/com.amazon.kepler.headless.runtime.loader_2@IKeplerScript_2_0"
+launch-type = "singleton"

 [processes]
 [[processes.group]]
 component-ids = ["com.amazondeveloper.media.sample.main"]
+
+[[processes.group]]
+component-ids = ["com.amazondeveloper.media.sample.interface.provider"]

 [offers]
 [[offers.interaction]]
 id = "com.amazondeveloper.media.sample.main"
+
+[[offers.service]]
+id = "com.amazondeveloper.media.sample.interface.provider"
+required-privileges = ["com.amazon.multimedia.privilege.session.manage"]

 [[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>" }
+attribute_options = ["partner-id"]
+static-values = { "partner-id" = "<Your partner id>" }
+
+[[extras.value.application.interface]]
+interface_name = "com.amazon.kepler.media.IAccountLoginServer"
+attribute_options = ["Status"]
+# In this manifest example, we have both Content Launcher and Account Login interfaces defined.
+# Since the Account Login cluster should be handled by a service component instead of an
+# interactive one for responsiveness, we use "override_attribute_component" to redirect
+# calls for the "Status" attribute to the service component.
+override_attribute_component = { Status = "com.amazondeveloper.media.sample.interface.provider" }
+
+[needs]
+[[needs.module]]
+# The dot (.) after "media" is intentional in this format. This notation will be changed in a 
+# future release.
+id = "/com.amazon.kepler.media.@IAccountLogin1"
+
+[[needs.module]]
+id = "/com.amazon.kepler.media@IContentLauncher1"

Step 2: Include package dependencies

The Vega Media Account Login API is offered to TypeScript developers using the system turbo module amzn/kepler-media-account-login . This turbo module is part of the SDK package. To use the API, update the package.json file to take the turbo module as a dependency, and add amzn/headless-task-manager to create a headless service app.

(...)
"dependencies": {
  "@amzn/kepler-media-account-login": "^1.1.0",
  "@amzn/headless-task-manager": "^1.1.0",
  (...)
}
(...)

Step 3-7: Add the Vega Media Account Login business logic

Step 3 to 7 are combined in this example, if you want to go through them one by one, you can read up about it here.

Create a file named AccountLoginWrapper.ts to contain the core business logic for the Vega Media Account Login API. In this file, create and export a class named AccountLoginWrapper . This class has a single member variable: an instance of the IAccountLoginServerAsync interface, used to interact with the Account Login server. This file will also globally create an instance of AccountLoginServerComponent and store it in a variable named accountLoginServerComponent .

import {
  AccountLoginServerComponent,
  IAccountLoginHandlerAsync,
  IAccountLoginServerAsync,
  IStatus,
  StatusType,
} from '@amzn/kepler-media-account-login';
import { IComponentInstance } from '@amzn/react-native-kepler';
import AsyncStorage from '@react-native-async-storage/async-storage';

export const accountLoginServerComponent = new AccountLoginServerComponent();

const getLoginStatus = async (): Promise<string> => {
  const getItemStatus = await AsyncStorage.getItem('loginStatus');
  console.log('get login status: ', getItemStatus);
  return getItemStatus;
};

export class AccountLoginWrapper {
  accountLoginServer?: IAccountLoginServerAsync;

  onStart(componentInstance: IComponentInstance): Promise<void> {
    this.setupAccountLoginServer();
    this.setupAccountLoginHandler(componentInstance);
    return Promise.resolve();
  }

  onStop(): Promise<void> {
    // Add any cleanup code here.
    return Promise.resolve();
  }

  async getAccountLoginStatus(): Promise<IStatus> {
    return accountLoginServerComponent
      .makeStatusBuilder()
      .status(
        // Fetch status from persistent storage.
        (await getLoginStatus()) ? StatusType.SIGNED_IN : StatusType.SIGNED_OUT
      )
      .build();
  }

  createAccountLoginHandler(): IAccountLoginHandlerAsync {
    return {
      handleReadStatus: async (): Promise<IStatus> => {
        console.log('handleReadStatus() invoked.');
        return await this.getAccountLoginStatus();
      },
    };
  }

  setupAccountLoginServer() {
    console.log('setupAccountLoginServer() invoked.');
    try {
      this.accountLoginServer = accountLoginServerComponent.getOrMakeServer();
    } catch (error) {
      this.accountLoginServer = undefined;
      console.error('setupAccountLoginServer() failed creating Account Login server: ', error);
      return;
    }
  }

  setupAccountLoginHandler(componentInstance: IComponentInstance) {
    if (this.accountLoginServer === undefined) {
      console.log('AccountLoginServer is undefined');
      return;
    }
    try {
      this.accountLoginServer.setHandlerForComponent(
        this.createAccountLoginHandler(),
        componentInstance
      );
    } catch (error) {
      console.log(error);
    }
  }

  async updateStatus(loginStatus: boolean) {
    console.log('updateStatus() invoked.');
    const status = accountLoginServerComponent
      .makeStatusBuilder()
      .status(loginStatus ? StatusType.SIGNED_IN : StatusType.SIGNED_OUT)
      .build();
    try {
      this.accountLoginServer?.updateStatus(status);
    } catch (error) {
      console.error('updateStatus() Failed updating login status: ', error);
    }
  }
}

export const AccountLoginWrapperInstance = new AccountLoginWrapper();

export const onStartService = (componentInstance: IComponentInstance): Promise<void> => {
  return AccountLoginWrapperInstance.onStart(componentInstance);
};

export const onStopService = (): Promise<void> => {
  return AccountLoginWrapperInstance.onStop();
};

Step 8: Adjust your headless service

Assuming you are already using headless for your playback, you service.js file will most likely look like this:

import { HeadlessEntryPointRegistry } from "@amzn/headless-task-manager";
import { onStartService, onStopService } from "./src/services/PlayerService";
import {
  onStartService as onStartAccountLoginService,
  onStopService as onStopAccountLoginService,
} from "./src/util/other/AccountLoginWrapper";

HeadlessEntryPointRegistry.registerHeadlessEntryPoint(
  "<your-app-package-name>.service::onStartService",
  () => onStartService
);

HeadlessEntryPointRegistry.registerHeadlessEntryPoint(
  "<your-app-package-name>.service::onStopService",
  () => onStopService
);

HeadlessEntryPointRegistry.registerHeadlessEntryPoint2(
  "<your-app-package-name>.interface.provider::onStartService",
  () => onStartAccountLoginService
);

HeadlessEntryPointRegistry.registerHeadlessEntryPoint2(
  "<your-app-package-name>.interface.provider::onStopService",
  () => onStopAccountLoginService
);

Fire TV system components automatically invoke onStartService() to initialize the Account Login server as a headless service. During this process, the handleReadStatus() function is registered for the specific service component instance.

When the system invokes this handler later, handleReadStatus() returns the current login state (signed-in or signed-out) as reported by the app.

Step 9: Initialize the Account Login server to report the login state

The interactive component (UI app) must also initialize the Account Login server to report the user’s login state using the updateStatus() method. - E.g. within your App.tsx

// These imports are probably already there in your app and just serve a visual anchor point
import {
  NavigationContainer,
  NavigationState,
  useNavigationContainerRef,
} from '@amzn/react-navigation__native';
import { createStackNavigator } from '@amzn/react-navigation__stack';
import React, { useCallback, useEffect, useState } from 'react';

// (...)

// start here
import {
  usePreventHideSplashScreen,
  useHideSplashScreenCallback,
  useComponentInstance,
  IComponentInstance,
} from '@amzn/react-native-kepler';

import { AccountLoginWrapperInstance } from './util/other/AccountLoginWrapper';

// (...)

const AppInitialization = () => {
    // (...)
    const componentInstance: IComponentInstance = useComponentInstance();

    useEffect(() => {
        AccountLoginWrapperInstance.onStart(componentInstance);

        return () => {
            AccountLoginWrapperInstance.onStop();
       };
    }, []);

// (...)
}

Step 10: Send login status updates

The interactive component (UI app) must call the updateStatus() method with the current login status in the following scenarios:

  1. When the app is launched.
  2. When the user’s login status changes

Each time, the status must be stored in persistent storage before calling updateStatus(), so that handleReadStatus() retrieves and returns the correct value. This way, the system consistently reflects the user’s authentication state, providing a seamless user experience.

This setup allows your app to manage login status requests, even when the main app is not actively running.

AccountLoginWrapperInstance.updateStatus('<send login status>');

Troubleshooting & Testing


3. Adding Personalization (Continue Watching) Feature

Sharing customer activity with Fire TV through the Content Personalization API enables customers to discover more personalized movie and TV show content. By providing information on watch activity, watchlist additions, DVR recordings, and purchases, Fire TV is able to help the customer more easily resume in-progress content, and make more accurate recommendations for new movies and TV shows.


Image 4: Personalization Continue Watching

Developer Portal Documentation Links:

Step 1: Include the package dependencies in your app

Add the kepler-content-personalization and headless-task-manager as well as amzn/kepler-epg-provider dependencies in your package.json file.

"dependencies": {
    "@amzn/react-native-kepler": "~2.0.0",
    "react": "18.2.0",
    "react-native": "0.72.0",
    "@amzn/kepler-content-personalization": "^1.2.0",
    "@amzn/kepler-epg-provider": "^1.0.0",
    "@amzn/headless-task-manager": "^1.0.0",
    (...)
  }
(...)
  • The kepler-content-personalization package provides APIs for sending your content personalization data to the system.
  • The amzn/kepler-epg-provider package would provide the dependencies used for channelDescriptor in PlaybackEvent data model.
  • The headless-task-manager package provides APIs to register your data-pull background service with the system. More details are given below.

Step 2. Update your manifest file

+## Define your app's service component which can handle data request.
+[[components.service]]
+id = "com.amazondeveloper.media.sample.content.dataRefresh.provider"
+runtime-module = "/com.amazon.kepler.headless.runtime.loader_2@IKeplerScript_2_0"
+launch-type = "singleton"

+[[processes.group]]
+component-ids = ["com.amazondeveloper.media.sample.content.dataRefresh.provider"]

+[wants]
+## Defines that your app has a dependency on the Content Personalization data service
+[[wants.service]]
+id = "com.amazon.tv.developer.dataservice"

+## Defines the privilege your app needs in order to use the Content Personalization interface to provide data
+[[needs.privilege]]
+id = "com.amazon.tv.content-personalization.privilege.provide-data"

+## Defines the data refresh service component of your app
+[[offers.service]]
+id = "com.amazondeveloper.media.sample.content.dataRefresh.provider"

+## Defines support for the Content Personalization interface and the attributes
+[[extras.value.application.interface]]
+interface_name = "com.amazon.kepler.media.IContentPersonalizationServer"
+attribute_options = ["SupportedCustomerLists", "DataRefreshComponentId"]

+[extras.value.application.interface.static_values]
+SupportedCustomerLists = ["Watchlist"]
+DataRefreshComponentId = "com.amazondeveloper.media.sample.content.dataRefresh.provider"

:warning: Warning: Each interface configuration must be kept separate. Do not combine or mix attributes between different interfaces in the manifest file.

:white_check_mark: Here is an example of the correct way to define multiple interfaces:

[extras.value.application]
[[extras.value.application.interface]]
interface_name = "com.amazon.kepler.media.IContentPersonalizationServer"
attribute_options = ["SupportedCustomerLists", "DataRefreshComponentId"]

[extras.value.application.interface.static_values]
SupportedCustomerLists = ["Watchlist"]
DataRefreshComponentId = "com.amazondeveloper.keplervideoapp.content.dataRefresh.provider"

[[extras.value.application.interface]]
interface_name = "com.amazon.kepler.media.IContentLauncherServer"
override_command_component = { LaunchContent = "com.amazondeveloper.keplervideoapp.main" }
attribute_options = ["partner-id"]

[extras.value.application.interface.static_values]
partner-id = "<Your partner id>"

:cross_mark: And here is an incorrect way to do this. Do not do it this way.

[extras.value.application]
[[extras.value.application.interface]]
interface_name = "com.amazon.kepler.media.IContentPersonalizationServer"
attribute_options = ["SupportedCustomerLists", "DataRefreshComponentId"]

[[extras.value.application.interface]]
interface_name = "com.amazon.kepler.media.IContentLauncherServer"
override_command_component = { LaunchContent = "com.amazondeveloper.keplervideoapp.main" }
attribute_options = ["partner-id"]

[extras.value.application.interface.static_values]
partner-id = "<Your partner id>"
SupportedCustomerLists = ["Watchlist"]
DataRefreshComponentId = "com.amazondeveloper.keplervideoapp.content.dataRefresh.provider"

Step 3. Make a sample API call

Begin with a sample/mock event generated at the app launch. To construct the event and send it, use the following code - make these changes where applicable in your app (e.g. when sending play-beacon events from the player:

const playbackEvent: IPlaybackEvent = new PlaybackEventBuilder()
    .playbackPositionMs(1000)
    .playbackState(PlaybackState.PLAYING)
    .durationMs(2000)
    .eventTimestamp(new Date())
    .contentId(
    new ContentIdBuilder()
        .id('content_CDF_ID')
        .idNamespace(ContentIdNamespaces.NAMESPACE_CDF_ID)
        .build(),
    )
    .profileId(
    new ProfileIdBuilder()
        .id('myProfileId')
        .idNamespace(ProfileIdNamespaces.NAMESPACE_APP_INTERNAL)
        .build(),
    )
    .buildActiveEvent();

// Send the event
ContentPersonalizationServer.reportNewPlaybackEvent(playbackEvent);

Step 4. Validate the integration

Trigger the sample event code you constructed to run inside your app. After you run the code successfully, view the logs to validate the SDK has been linked to your app and is processing the message.

You can validate the steps by searching your app logs:

journalctl --follow |grep -Ei 'kepler.tv.personalization'

The log message you receive for the event shown in Step 3 should contain at least one of the following logs:

Dec 15 00:53:15.705114 carat-3fc19fb5ae526e4d local0.info keplerscript-ru[22814]: 1483317178 INFO kepler.tv.personalization.ancp.turbomodule:reportNewPlaybackEvent called
Dec 15 00:53:15.711945 carat-3fc19fb5ae526e4d local0.info keplerscript-ru[22814]: 1483317178 INFO kepler.tv.personalization:PlaybackEventBuilder buildActiveEvent() called
Dec 15 00:53:15.711990 carat-3fc19fb5ae526e4d local0.info keplerscript-ru[22814]: 1483317178 INFO kepler.tv.personalization:reportNewPlaybackEvent async call received

Additional Integration Steps

To make API calls as part of in-app functionality or to implement a pull data service for background or off-device data, please follow our in depth documentation on the Developer Portal.


Wrap-Up

By integrating your catalog, deep linking, account login, and callback handlers, you can fully support Fire TV’s Universal Search and Browse experience. This makes it easier for users to find and watch your content seamlessly, whether through voice, search, or remote control.

Resources