as

Settings
Sign out
Notifications
Alexa
Amazon Appstore
AWS
Documentation
Support
Contact Us
My Cases
Get Started
Design and Develop
Publish
Reference
Support

Get Started with Vega Content Personalization

Here’s what you need to know to integrate Vega Content Personalization into your app for Fire TV. If you want to review some of the types of data used for this integration, see the Data Type Reference.

If the data is not accessible or needs to be transformed, this integration may take longer. Confirm your data is stored in the requested format using the documentation below.

Prerequisites

  • Access to the source code of your Fire TV app.
  • A Fire TV device that supports this integration. Check with your Amazon contact for a list of device types currently supported.
  • Your app must participate in the Catalog Ingestion process, so Fire TV recognizes the content IDs.
  • Your app must share entitlements for each customer, so Fire TV shows the entitled provider as part of our content discovery experience. For more information, reach out to your Amazon contact.
  • Your app must complete the Content Launcher integration.

Integration steps

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.

Copied to clipboard.

"dependencies": {
    "@amazon-devices/react-native-kepler": "~2.0.0",
    "react": "18.2.0",
    "react-native": "0.72.0",
    "@amazon-devices/kepler-content-personalization": "^1.2.0",
    "@amazon-devices/kepler-epg-provider": "^1.0.0",
    "@amazon-devices/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

Update your manifest.toml file to include Content Personalization support. Below is an example for a sample app:

Copied to clipboard.

schema-version = 1

## Define your package
[package]
title = "Vega Video app"
version = "2.17.0"
id = "com.amazondeveloper.keplervideoapp"

[components]
## Define your app's interactive component (if it doesn't already exist)
[[components.interactive]]
id = "com.amazondeveloper.keplervideoapp.main"
library-name = "com.amazondeveloper.keplervideoapp"
runtime-module = "/com.amazon.kepler.keplerscript.runtime.loader_2@IKeplerScript_2_0"
categories = ["com.amazon.category.kva"]
launch-type = "singleton"

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

## Define a process group for each component
[processes]
[[processes.group]]
component-ids = ["com.amazondeveloper.keplervideoapp.main"]

[[processes.group]]
component-ids = ["com.amazondeveloper.keplervideoapp.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"

[needs]
## 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"

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

## Defines the interactive component of your app
[[offers.interaction]]
id = "com.amazondeveloper.keplervideoapp.main"

## Add extras to declare support for Content Personalization
[[extras]]
key = "interface.provider"
## If you're utilizing account login or content launcher interface,
## replace component-id with appropriate service component. Follow Account Login Integration Guide
component-id = "com.amazondeveloper.keplervideoapp.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.keplervideoapp.content.dataRefresh.provider"

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

Copied to clipboard.

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

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

Copied to clipboard.

[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:

Copied to clipboard.

// Example playback event generated when user starts watching content

const playbackEvent: IPlaybackEvent = new PlaybackEventBuilder()
    .playbackPositionMs(0)
    .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:

Copied to clipboard.

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:

Copied to clipboard.

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 call received

Step 5. Make API calls as part of in-app functionality

For each data type, review the data type's When to Send section to understand where in your code to make calls to Vega Content Personalization. Find the relevant parts of your code that run when customers take each action and add an API call. Each data type has different triggers.

For example, when a customer adds an item to their watchlist, we expect you to call the reportNewCustomerListEntry API with the relevant information. First locate the code in your app that adds items to the watchlist, and then make the API call as part of your logic.

Step 6. Implement your data pull service for background or off-device data

To allow Amazon to pull data from your app, implement the service as described below. The service contains everything needed to setup and connect, only requiring you to implement the functions to send data to a receiver object. This object allows you to share data in chunks, as needed. This prevents loading large lists into memory.

  1. Create a service.js file with the same path where package.json is located with the following content. This tells the system about the entry points for your content.dataRefresh.provider service.

    Copied to clipboard.

    import { HeadlessEntryPointRegistry } from '@amazon-devices/headless-task-manager';
    
    import {
    onStartService,
    onStopService,
    } from './src/headless/HeadlessService';
    
    HeadlessEntryPointRegistry.registerHeadlessEntryPoint2(
    'com.amazondeveloper.keplervideoapp.content.dataRefresh.provider::onStartService',
    () => onStartService,
    );
    
    HeadlessEntryPointRegistry.registerHeadlessEntryPoint2(
    'com.amazondeveloper.keplervideoapp.content.dataRefresh.provider::onStopService',
    () => onStopService,
    );
    
    
  2. Create your Headless Service Interface file under src/headless/HeadlessServiceInterface.ts with the following content:

    Copied to clipboard.

    import {
    IComponentInstance,
    } from "@amazon-devices/react-native-kepler";
    
    export interface HeadlessServiceInterface {
    /**
     * This function is called when native service onStart is called.
     * @param {IComponentInstance} componentInstance - The headless component instance.
     */
    onStart(componentInstance: IComponentInstance): Promise<void>;
    
    /**
     * This function is called when native service onStop is called.
     * @param {IComponentInstance} componentInstance - The headless component instance.
     */
    onStop(componentInstance: IComponentInstance): Promise<void>;
    }
    
  3. Create your data pull service under src/headless/HeadlessService.ts with the following content:

    Copied to clipboard.

    import { ContentPersonalizationServer, CustomerListType, IContentEntitlementsHandler, IContentEntitlementsProvider, ICustomerListEntriesHandler, ICustomerListEntriesProvider, IPlaybackEventsHandler, IPlaybackEventsProvider } from "@amazon-devices/kepler-content-personalization";
    import { HeadlessServiceInterface } from "./HeadlessInterface";
    import { IComponentInstance } from "@amazon-devices/react-native-kepler";
    
    /*********** Content Personalization Handlers *************/
    const contentEntitlementsHandler: IContentEntitlementsHandler = {
       getAllContentEntitlements: (
          contentEntitlementsProvider: IContentEntitlementsProvider,
       ) => {
          contentEntitlementsProvider.addContentEntitlementChunk(<ADD ENTITLEMENTS>);
          contentEntitlementsProvider.commit();
       },
    };
    
    const customerListEntriesHandler: ICustomerListEntriesHandler = {
       getAllCustomerListEntries: (
          listType: CustomerListType,
          customerListEntriesProvider: ICustomerListEntriesProvider,
       ) => {
          customerListEntriesProvider.addCustomerListChunk(listType, <ADD LIST ENTRIES>);
          customerListEntriesProvider.commit();
       },
    };
    
    const playbackEventsHandler: IPlaybackEventsHandler = {
       getPlaybackEventsSince: (
          sinceTimestamp: Date,
          playbackEventsProvider: IPlaybackEventsProvider,
       ) => {
          playbackEventsProvider.addPlaybackEventChunk(<ADD PLAYBACK EVENTS>);
          playbackEventsProvider.commit();
       },
    };  
    
    /*********** Assign the Content Personalization Handlers *************/
    class HeadlessService implements HeadlessServiceInterface {
       onStart(componentInstance: IComponentInstance): Promise<void> {
          ContentPersonalizationServer.setContentEntitlementsHandlerForComponent(
          contentEntitlementsHandler, componentInstance
          );
          ContentPersonalizationServer.setCustomerListEntriesHandlerForComponent(
          customerListEntriesHandler, componentInstance
          );
          ContentPersonalizationServer.setPlaybackEventsHandlerForComponent(
          playbackEventsHandler, componentInstance
          );
    
          return Promise.resolve();
       }
    
       onStop(componentInstance: IComponentInstance): Promise<void> {
          return Promise.resolve();
       }
    }
    
    const HeadlessServiceInstance = new HeadlessService() as HeadlessServiceInterface;
    
    export const onStartService = (componentInstance: IComponentInstance): Promise<void> => {
       return HeadlessServiceInstance.onStart(componentInstance);
    };
    
    export const onStopService = (componentInstance: IComponentInstance): Promise<void> => {
       return HeadlessServiceInstance.onStop(componentInstance);
    };
    
    

Implementation details

Make changes to your catalog integration when directed by your Amazon contact

To make use of the entitlement and activity data, Fire TV needs the following data from your existing Fire TV catalog integration. Fire TV’s public catalog integration documentation will be updated to include these elements in the future, but here is a preview of what’s needed concerning the Vega Content Personalization integration. Your Amazon contact will inform you of when to begin these catalog changes.

  • TVOD (Purchases and Rentals) - Add new purchase and rental offers to applicable titles. They will look identical to subscription offers, but without a Subscription ID.
  • International - For expansion into other countries, Fire TV is moving from per-country catalogs to Fire TV’s global catalog format. The above mentioned catalog changes enable an easier transition if included and launched as part of your global catalog. However, Fire TV still supports per-country catalogs.

Amazon content ID

Vega Content Personalization supports content identification across different namespaces. All content IDs must be passed with an associated namespace in order for Amazon to identify the content item. Amazon supports the following namespace:

Namespace Description
cdf_id This is the ID space, since data is shared in your Amazon catalog integration. These are the IDs you have specified for each piece of content. It corresponds to the CommonWorkType/ID field in the Catalog Data Format (CDF).

Amazon profile ID

All data types allow you to share an associated profile ID. Since there are different profile types, specify the namespace. Amazon currently supports the following profile ID namespace:

Namespace Description
app_internal This namespace indicates you are sharing a string representation of your internal profile ID for the active profile. This ID serves to identify specific profiles in your app, so we can attribute activity to the right Fire TV profile. Do not provide the actual ID you use internally. The provided value should not allow for the identification of the customer. We recommend taking a hash value of your internal profile ID, which should be the same across all devices. Also, do not send us the profile name provided by the customer. Even if your app doesn't use profiles, provide a consistent value.

Reporting updates

The SDK contains functionality to share information using three types of operations:

  • New (example: reportNewCustomerListEntry)- Represents an incremental update to add a new entry to the dataset.
  • Removed (example: reportRemovedCustomerListEntry) - Represents a decremental update to remove an entry from the dataset.
  • Refreshed (example: reportRefreshedCustomerList) - Indicates that there have been changes to the dataset due to off-device action, and a new refreshed version of the list needs to be fetched using the data pull service.

New and Removed are useful when the customer interacts with content in the app, and it performs adds or removes. The Refreshed update is useful when there are significant changes to the list due to customer sign-in, off-device activity, or if you suspect the list is out of sync for another reason.

Providing large sets of data

When supplying large amounts of data through the data pull service, pull the data in reasonably small pages from your cloud backend and call the provider APIs as the data is is being pulled down. This will limit memory usage for your service and prevents your app from being terminated by the system.

An example flow might look something like this:

Copied to clipboard.

const contentEntitlementsHandler: IContentEntitlementsHandler = {
    getAllContentEntitlements: (
      provider: IContentEntitlementsProvider,
    ) => {
        let myCloudHasMoreData = true;
        while(myCloudHasMoreData){
            let myCloudResponse = getNextPageFromMyBackend(); 
            let myCloudData = myCloudResponse.getData();
            let entitlements: IContentEntitlements[] = [];
            for(let element in myCloudData){
                let entitlement = <build data with ContentEntitlementBuilder>
                entitlements.push(entitlement)
            }
            provider.addContentEntitlementChunk(entitlements);

            myCloudHasMoreData = myCloudResponse.hasMoreData();
        }
        provider.commit();
    },
  };

Last updated: Sep 30, 2025