User Interest
Document Status: Candidate Specification
See Firebolt Requirements Governance for more info.
Contributor | Organization |
---|---|
Eugene Chung | Comcast |
Tim Dibben | Sky |
Mike Horwitz | Comcast |
Jeremy LaCivita | Comcast |
1. Overview
In additional to traditional discovery APIs such as Watch History and Watch Next, Firebolt provides a more abstract API that facilitates impromptu content discovery connections between first-party Aggregated Experiences and third-party Apps.
The User Interest Capability enables Apps to provide meta-data on content that the user has expressed an interest in to Aggregated Experience Apps that have been given access to use this Capability.
This allows for open ended design of Aggregated Experience App features that present App-specific content to re-engage the user with the content inside the originating App.
While the functionality and UX is left to the Aggregated Experience App, typically designed by each Firebolt Distributor, the Firebolt API enables events to register user interest and pass entity meta-data:
Which generally enables Aggregated Experiences to present that entity
meta-data in some way that leads to re-launching the original App at a
later point, using a navigateTo
notification:
This is just one example of what an Aggregated Experience App might do with the User Interest API.
Note that this API SHOULD NOT be used to implement Watch History or Watch Next features. These concepts are much more fundamental to Firebolt and have explicit APIs so that Firebolt Distributors can keep track of which apps are using them separately.
2. Table of Contents
3. User Interest Flows
3.1. User Interest from an in-app UX
Some Apps will have a built-in user interface for users to express interest in content from the App. This could be a “Favorite” button, an in-app “My List” button, etc.
If the App wants to leverage any additional exposure from the device’s Aggregated Experience, it can wire up its own UI to the Firebolt User Interest API, in addition to any in-app features that it’s already invoking.
By calling the Discovery.userInterest
method with the relevant entity
meta-data, the device’s Aggregated Experience will be notified of the
user’s interest in that entity:
Discovery.userInterest(type: InterestType, reason: InterestReason, entity: EntityDetails)
The type
parameter denotes the directionality of the interest:
interest
disinterest
The reason
parameter denotes why or how the user has expressed interest:
Reason | Description |
---|---|
playlist |
Interested in adding to a list |
reaction |
Interested in submitting a reaction, e.g. like or dislike |
recording |
Interest in scheduling a recording |
share |
Interest in sharing the content on social media |
NOTE: We can remove some of these (not playlist
) these are here for now to illustrate the purpose for the reason paramater.
An app MUST provide
the xrn:firebolt:capability:discovery:interest
capability in order to call Discovery.userInterest
.
When this method is called with a valid EntityDetails
, the platform
MUST dispatch a Content.onUserInterest
notification to all Apps
that have registered for it (typically Aggregated Experience Apps) with
information about the app, interest type, and the entity.
The Content.onUserInterest
event has a result type of Interest
:
property | type | description |
---|---|---|
appId | string | The id of the app that pushed the user interest. |
type | InterestType |
the type of interest. |
reason | InterestReason |
the reason for the interest |
entity | EntityDetails |
The entity the user expressed interest in. |
An Aggregated Experience can register for the Content.onUserInterest
notification, and it will receive notifications when an EntityDetails
is
returned from the active App after a Discovery.userInterest
call is
fulfilled.
An app MUST have permissions to use
the
xrn:firebolt:capability:discovery:interest
capability in order to
listen to the Content.onUserInterest
notification.
If the result is not a valid entity, i.e. does not match
the EntityDetails schema, then no Content.onUserInterest
notification will be dispatched.
The Discovery.userInterest
method SHOULD NOT be used in place of more
specific Discovery methods, e.g. Discovery.watchNext
or
Discovery.watched
. These methods facilitate specific UX flows that may
have separate legal opt-outs for each user.
The Discovery.userInterest
method SHOULD NOT be called unless the user
is activating a UI element in the app, or in a second screen experience
that is communicating with the app, that implies interest of some kind.
3.2. User Interest from a platform UX
Firebolt platforms may provide a platform UX, e.g. voice or and RCU, to express user interest in content from an active App. To facilitate this Apps will need to be told about the user’s expressed interest in their content.
First, the Aggregated Experience (or some app with this
capability) detects that the user is interested in something. In this
picture the interest is triggered by an RCU button, but how this occurs
is outside the scope of this document. When this happens, the Aggregated
Experience app calls Content.requestUserInterest()
, which will trigger the
platform to identify the best Provider Candidate
and call that app’s userInterest
method via the Provider RPC method:
Discovery.onRequestUserInterest
.
Next, the provider app receives and responds to the request with an
EntityDetails, which is returned as the result to the pending
Content.requestUserInterest
method:
Once an App’s callback is invoked, that app will have interestTimeout
milliseconds to return a value or throw an error. Values returned after
that time MUST be ignored. The timeout value is stored in the
device’s configuration manifest.
To be notified when a user expresses interest in the currently displayed
content, an App MUST provide the
xrn:firebolt:capability:discovery:interest
capability by enabling the
Discovery.onRequestUserInterest
notification.
If there is a valid entity to return, then the method registered by the App MUST return the currently displayed entity meta-data.
If there is no valid entity to return, then the method MUST throw an exception.
If the provider app returns a valid EntityDetails
before the timeout,
then, the returned value MUST be used.
If there is no app registered the an error MUST be returned.
User Interest Errors
An app is expected return either a valid result or an appriate error.
If neither happens before interestTimeout
expires then the platform MUST return a Provider timed-out error:
{
"id": 1,
"error": {
"code": -50400,
"message": "Provider timed-out",
"data": {
"capability": "xrn:firebolt:capability:discovery:interest",
}
}
}
If an app recieves a request for user interest when there is nothing appropriate to return, e.g. nothing selected or presented that maps to an Entity, then the app SHOULD return an error with a valid JSON-RPC error response, e.g.:
{
"id": 1,
"error": {
"code": -40400,
"message": "No entities currently presented."
}
}
The platform API Gateway MUST append, or overwrite, the data.capability
value to any errors returned by the app, e.g.:
{
"id": 1,
"error": {
"code": -40400,
"message": "No entities currently presented.",
"data": {
"capability": "xrn:firebolt:capability:discovery:interest",
}
}
}
3.3. Upstream User Interest Intent
In some cases, e.g. a voice assistant, some upstream component will inform the platform that the user is interested in whatever is currently being presented.
To do this, the upstream system MUST send a Interest
intent, which describes the type of and reason for the interest.
{
"action": "interest",
"data": {
"type": "interest",
"reason": "playlist"
}
}
When a Firebolt platform receives this intent, it SHOULD initiate the platform’s user interest flow.
3.4. User Interest Bulk Updates
Sending bulk interest updates, e.g. Entities the user expressed interest in on a different platform, is not supported.
4. Core SDK APIs
The following APIs are exposed by the Firebolt Core SDK as part of the
Discovery
module.
4.1. InterestType
This is an enum with the following values:
"interest"
"disinterest"
4.2. InterestReason
This is an enum with the following values:
Reason | Description |
---|---|
playlist |
Interested in adding to a list |
reaction |
Interested in submitting a reaction, e.g. like or dislike |
recording |
Interest in scheduling a recording |
share |
Interest in sharing the content on social media |
4.3. Discovery.userInterest
This is a push API that allows Apps to push entities that the user has expressed interest in to the platform.
To push an entity that the user is interested in pass an EntityDetails
object to the method:
Discovery.userInterest(type: InterestType, reason: InterestReason, entity: EntityDetails): Promise<void>
4.4. Discovery Interest Provider
To respond to requests for the current entity, because the user has expressed interest in some way that the platform manages, register a provider:
interface IDiscoveryInterestProvider {
function userInterest(type: InterestType, reason: InterestReason): Promise<EntityDetails>
}
Discovery.provide("xrn:firbolt:capability:discovery:interest", IDiscoveryInterestProvider)
4.5. InterestIntent
An InterestIntent
denotes that the user has expressed interest in the
currently displayed and/or selected content:
type InterestIntent {
action: "interest"
data: {
type: "interest" | "disinterest",
reason: "playlist" | "reaction" | "recording"
},
context: {
source: "rcu" | "voice"
}
}
5. Discovery SDK APIs
The following APIs are exposed by the Firebolt Discovery SDK as part of the
Content
module.
5.1. Interest Types
This type stores the various attributes of an Interest response or event:
type InterestType = "interest" | "disinterest"
type InterestReason = "playlist" | "reaction" | "recording" | "share"
type Interest {
appId: string
entity: EntityDetails
type?: InterestType
reason?: InterestReason
}
5.2. Content.requestUserInterest
This method triggers the corresponding Discovery provider API for the provider app.
Content.requestUserInterest(type: InterestType, reason: InterestReason): Promise<Interest>
5.3. Content.onUserInterest
This notification allows Aggregated Experience Apps to be informed when a user expresses interest in some Content, and the content resolves to a valid Entity from some App.
Content.listen('userInterest', Interest => void): Promise<void>
The callback will be passed an Interest
object with
the appId, type, reason, and information about the entity that the user expressed interest in.