Skip to main content

Living Apps SDK

Every module is accessible from a single entry-point:

window.laSdk;

laSdk.ready()

Resolves when your custom logic is ready to be run.

danger

Don't use other SDK methods until this promise is resolved!

Optionally, you can set a default laName that would be used as fallback.

laSdk.ready(opts?: ReadyOpts): Promise<void>


interface ReadyOpts {
/**
* Default name of the living app if query param `?laName` is undefined.
*/
laName?: string;
/**
* Keep the Splash screen
* false by default
*
* if set, `laSdk.removeSplash()` can be called later to remove the Splash screen.
* by default, the Splash screen will be automatically removed after 10s with no calls unless this option is on.
*/
keepSplash?: boolean;
}

Example:

window.laSdk
.ready({ laName })
.then(() => {
root.render(
<React.StrictMode>
<App />
</React.StrictMode>,
);
})
.catch((err) => {
// error
});

laSdk.removeSplash()

Remove splash screen if keepSplash option has been used in ready() method. Therefore the Living App can decide when to remove the splash screen. It will be automatically executed after 10s with no calls.

Example:

window.laSdk
.ready({ laName, keepSplash: true })
.then(() => {
return initAppAndLoadData();
})
.then(() => {
window.laSdk.removeSplash();
});

laSdk.close()

Close your Living App.

laSdk.close(): void

laclose event

There are several ways to close your Living App. Calling laSdk.close() is just one possibility.

When user press "HOME" key on the remote control, the SDK emits laclose event. The app has 10ms to perform a clean shutdown before actually end your aura session and closing the browser. Use this delay to save persistence data, unsubscribe from external systems, etc.

React example:

// ...

const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement,
);

laSdk.ready().then(() => {
root.render(laSdk.channel === 'movistar-home' ? <MhApp /> : <StbApp />);

window.addEventListener('laclose', () => {
root.unmount();
});
});

// ...

Using root.unmount() will unmount your entire application and run your unmount logic.

laSdk.KEYS

get KEYS map. Therefore you can set lakeypress listeners based on these key names

laSdk.KEYS: Record<string, number>

Example:

window.addEventListener('lakeypress', (ev: KeyboardEvent) => {
if (ev.keyCode === window.laSdk.KEYS.KEY_BACK) {
// ...
}
});

available keys

laSdk.KEYS.KEY_0;
laSdk.KEYS.KEY_1;
laSdk.KEYS.KEY_2;
laSdk.KEYS.KEY_3;
laSdk.KEYS.KEY_4;
laSdk.KEYS.KEY_5;
laSdk.KEYS.KEY_6;
laSdk.KEYS.KEY_7;
laSdk.KEYS.KEY_8;
laSdk.KEYS.KEY_9;
laSdk.KEYS.KEY_OK;
laSdk.KEYS.KEY_LEFT;
laSdk.KEYS.KEY_UP;
laSdk.KEYS.KEY_RIGHT;
laSdk.KEYS.KEY_DOWN;
laSdk.KEYS.KEY_BACK;
laSdk.KEYS.KEY_PLAY;
laSdk.KEYS.KEY_PAUSE;
laSdk.KEYS.KEY_PLPAUSE;
laSdk.KEYS.KEY_FORWARD;
laSdk.KEYS.KEY_REWIND;
laSdk.KEYS.KEY_STOP;
laSdk.KEYS.KEY_RECORD;
laSdk.KEYS.KEY_PROG_UP;
laSdk.KEYS.KEY_PROG_DN;
laSdk.KEYS.KEY_RED;
laSdk.KEYS.KEY_GREEN;
laSdk.KEYS.KEY_YELLOW;
laSdk.KEYS.KEY_BLUE;
laSdk.KEYS.KEY_MENU;
laSdk.KEYS.KEY_HELP;
laSdk.KEYS.KEY_EPG;
laSdk.KEYS.KEY_TV;
laSdk.KEYS.KEY_WWW;
laSdk.KEYS.KEY_KEYB;
laSdk.KEYS.KEY_TXT;
laSdk.KEYS.KEY_MIC;

laSdk.http

HTTP client. You must use this HTTP client for your HTTP requests.

laSdk.http: HttpClient

interface HttpClient {
get<K>(
url: string,
opts?: {
params?: Record<string, string | number | boolean>;
headers?: Record<string, string>;
proxy?: boolean;
proxyCacheSeconds?: number;
oauth1?: OAuth1;
useLabContentsApi?: boolean;
blob?: boolean; // enables "blob" xhr responsetType
},
): Promise<{ json: K; status: number; blob?: Blob }>;

post<K>(
url: string,
opts?: {
params?: Record<string, string | number | boolean>;
json: Record<string, string | number | boolean>;
headers?: Record<string, string>;
proxy?: boolean;
oauth1?: OAuth1;
useLabContentsApi?: boolean;
},
): Promise<{ json: K; status: number }>;
}

Example

laSdk.http
.get<{ msg: string }>('https://api.livingappsmaker.com/whatever', {
params: { search: 'foo' },
headers: {
Authorization: 'Bearer whatever',
},
})
.then((res) => console.log(res.json.msg));
.catch((err) => console.log(res.json.status));

Content-Type

POST requests use Content-Type: application/json by default:

laSdk.http.post('/foo/bar', {
json: { param1: 'value1' },
});

will generate:

POST https://api.example.com/foo/bar
Content-Type: application/json

{
"param1": "value1"
}

However, its possible to use Content-Type: application/x-www-form-urlencoded instead:

laSdk.http.post<>('/foo/bar', {
json: { param1: 'value1' },
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
});

will generate:

POST https://api.example.com/foo/bar
Content-Type: application/x-www-form-urlencoded

param1=value1

useLabContentsApi

Use Contents LAB API host for given path, SDK will inject the right API KEY.

Example

laSdk.http.get<{ msg: string }>('/foo/bar', { useLabContentsApi: true });

it will GET <contents_lab_url>/foo/bar with right header x-api-key: ....

abortSignal

Use an AbortSignal object created from the AbortController.signal property.

When a fetch request is initiated, we pass abortSignal as an option. This associates the signal and controller with the fetch request and allows us to abort it by calling AbortController.abort().

As seen in the example below, we can use this option to abort a fetch request after a certain amount of time.

const abortController = new AbortController();
const timeout = setTimeout(() => abortController.abort(), 10000); // 10 sec

laSdk.http
.get<{ msg: string }>('/foo/bar', { signal: abortController.signal })
.finally(() => clearTimeout(timeout));

React example

const User = () => {
const [user, setUser] = useState({ name: '' });

useEffect(() => {
const abortController = new AbortController();

laSdk.http
.get('foo/user', { abortSignal: abortController.signal })
.then((response) => response.json())
.then((data) => setUser(data));

return () => {
abortController.abort();
};
}, []);

return <div>{user.name}</div>;
};

HTTP proxy

Sometimes you'll need to avoid CORS problems or inject some secrets into your HTTP requests.

When using { proxy: true } option, Living Apps SDK HTTP client will POST Living Apps Platform HTTP Proxy endpoint and we'll perform the HTTP request "backend to backend" and inject your environment secrets when using ###CONFIG_NAME### in your params, headers or json.

proxyCacheSeconds option will make LA Platform HTTP proxy cache GET responses using all params hash as a cache key

Example:

laSdk.http
.get<{ msg: string }>('https://api.livingappsmaker.com/whatever', {
params: { search: 'foo' },
headers: {
Authorization: 'Bearer ###BEARER_TOKEN###',
},
proxy: true
})
.then((res) => console.log(res.json.msg));
.catch((err) => console.log(res.json.status));

HTTP proxy bearerLogin

The bearerLogin option allows to authenticate an HTTP request using an access token obtained through a previous request. This is useful when the target API requires authentication using a bearer token.

laSdk.http.get<{ msg: string }>('https://api.livingappsmaker.com/whatever', {
method: 'GET'
proxy: true,
bearerLogin: {
url: 'https://auth.livingappsmaker.com/token',
body: {
client_id: '###CLIENT_ID###', // LA platform will inject this secret
client_secret: '###CLIENT_SECRET###', // LA platform will inject this secret
},
tokenPath: 'data.access_token', // token will be extracted from `response.data.access_token`
cacheSeconds: 60,
},
});

The Living Apps Platform HTTP proxy will POST https://auth.livingappsmaker.com/token with body (after replacing secret config entries). If the request is successful, the platform will extract the access token from response.data.access_token, and cache the token for the number of seconds specified in cacheSeconds.

After the access token is obtained and cached, the platform will add Authorization: Bearer <access token> header to the target request.

info

bearerLogin object will be used to generate a cache key, so all requests with the same bearerLogin parameter will use the same access token until it expires.

Note that the bearerLogin option only works with the proxy option set to true.

laSdk.telefonicaApi

Telefonica APIs (aka 4th Platform) HTTP client. You must use this HTTP client for your all requests to Telefonica Kernel.

Living Apps SDK will fetch the Living Apps Platform Telefonica Kernel API proxy using user Living Apps Access token. This HTTP proxy will authenticate user using Delegated Auth (JWT Bearer) and inject user T. Kernel access token into the final request.

Please contact the team in order to provide your Living App Telefonica Kernel configuration:

  • client ID
  • client secret
  • issuer
  • private key
  • purposes

When your App does not need to speak in the name of a specific user (note this does not mean it can't consume Personal Information resources), then the authorization can be easier and use client credentials this is the simplest OAuth grant-type. To use it just need to pass {clientCredentials: true} to the request options.

laSdk.telefonicaApi: TelefonicaApiClient

interface TelefonicaApiClient {
readonly isLoggedIn: boolean;

login(
levelOfAccess: 2 | 3,
queryparamsOnRestore?: Record<string, string>,
): void;

get<K>(
telefonicaApiPath: string,
opts?: {
params?: Record<string, string | number | boolean>;
clientCredentials?: boolean;
},
): Promise<{ json: K; status: number }>;

post<K>(
telefonicaApiPath: string,
opts?: {
params?: Record<string, string | number | boolean>;
json: Record<string, string | number | boolean>;
clientCredentials?: boolean;
},
): Promise<{ json: K; status: number }>;
}

Example

laSdk.telefonicaApi
.get<{ msg: string }>('/userprofile/v3/users/me', {
params: { search: 'foo' },
})
.then((res) => console.log(res.json.msg))
.catch((err) => console.log(err.json.status));

laSdk.telefonicaApi.login() LoA 2/3

laSdk.telefonicaApi.login(
levelOfAccess: 2 | 3,
queryparamsOnRestore?: Record<string, string>,
pinIDPTransaction?: PinIDPTransaction

): void;

laSdk.telefonicaApi.login() allows users to authenticate using a higher level of access

  • levelOfAccess 2: PIN IDP / Mobile Connect
  • levelOfAccess 3: DNI / PASSWORD

Note that the current Living App session will be closed and a new session will be created after user completes authentication. Thanks to queryParamsOnRestore your Living App could be initialized with custom query params. Use them to initialize your app in a different way.

Example:

laSdk.telefonicaApi.login(3, { entrypoint: 'restart-router' });

PIN IDP Transaction

The pinIDPTransaction object activates the PIN Identity Provider for Level of Access (LoA) 2, allowing you to configure the data displayed on the PIN screen.

type PinIDPTransaction = {
title?: string;
subtitle?: string;
description?: string;
image?: string;
legalTermsURL?: string;
transactionType?: 'dataAccess' | 'purchase' | 'subcription' | 'activation';
};

laSdk.telefonicaApi.logout()

Log out from Telefonica Kernel. Note that it does not really close session on Telefonica Kernel. It just make the Living App forget about the authorization id.

laSdk.telefonicaApi.isLoggedIn; // true
laSdk.telefonicaApi.logout();
laSdk.telefonicaApi.isLoggedIn; // false

laSdk.telefonicaApi.isLoggedIn check if logged with LoA 2/3

Example:

if (laSdk.telefonicaApi.isLoggedIn) {
navigate('/wherever');
}

laSdk.telefonicaApi.storeAuth()

Store current Telefonica Kernel auth for the current Living App so it can be restored in a future session. Error will be thrown if user is not authenticated.

laSdk.telefonicaApi.storeAuth(seconds: number): Promise<void>

Example:

// when LA is init with expected query params, via queryParamsOnRestore, meaning user it's comming from a successful authentication:

if (laSdk.isLoggedIn) {
await laSdk.telefonicaApi.storeAuth(60 * 60); // 1h
}

laSdk.telefonicaApi.restoreAuth()

Restore Telefonica Kernel auth for the current Living App

laSdk.telefonicaApi.restoreAuth(): Promise<void>

Example:

try {
await laSdk.telefonicaApi.restoreAuth();
} catch (err) {
if (!laSdk.isLACoreWebError(err)) {
throw err;
}

switch (err.code) {
case 'telefonicaApi.noAuthToRestore':
case 'telefonicaApi.storedAuthExpired':
laSdk.telefonicaApi.login(2, { entrypoint: 'foo' });
break;
default:
throw err;
}
}

laSdk.getMakerContentsXXX

The following methods fetch content stored in Maker CMS.

These are wrapper methods and could potentially be re-implemented using laSdk.http while setting the correct specifics.

laSdk.getMakerContents()

getMakerContents<K>(id: string): Promise<{
json: K;
status: number
}>;

laSdk.getMakerContentsHome()

getMakerContentsHome<K>(): Promise<{
json: K;
status: number
}>;

laSdk.getMakerContentsSettings()

type LivingAppMakerContentsStyles = {
custom_font?: string | null;
focus_color?: string | null;
focus_font_color?: string | null;
stb_logo?: string | null;
mh_logo?: string | null;
stb_splash?: string | null;
mh_splash?: string | null;
};

getMakerContentsSettings(): Promise<{
json: LivingAppMakerContentsStyles;
status: number;
}>;

laSdk.getMakerContentsSearch()

getMakerContentsSearch<K>(utterance: string): Promise<{
json: K;
status: number
}>;

laSdk.getMakerContentsConfigEntries()

Retrieve the Configuration Entries that are stored in the Maker CMS.

These entries are set using the Maker CMS and can be used as env vars.

getMakerContentsConfigEntries(laName: string): Promise<{
json: Record<string, string>;
status: number
}>;

Example:

screenshot of an example config entries at Maker CMS

const { json: configEntries } = await getMakerContentsConfigEntries(
'my-living-app',
);

console.log(configEntries);

// {
// API_KEY: 'your-api-key',
// API_URL: 'https://api.example.com',
// ...
// }

laSdk.video

Play a HTML5 or HLS.js video on the background.

note

Use laSdk.player instead if need to play a video with the default key-management and/or the default visual UI.

💃 Check video-player for more details.

laSdk.video: VideoBackgroundClient

interface VideoBackgroundClient {
readonly duration: number;
readonly isLoading: boolean;
readonly isPaused: boolean;
readonly isPlaying: boolean;
readonly videoSessionId: string | null;
readonly src: string;
readonly timeLeft: number | null;
currentTime: number;

load(url: string, opts?: VideoBackgroundLoadOpts): Promise<void>;
play(): Promise<void>;
pause(): Promise<void>;
plpause(): Promise<void>;
stop(): Promise<void>;
restart(): Promise<void>;
}

Example:

/*
* loads the video on foreground,
* from the beginning,
* as soon as it's loaded,
* remote (and voice controls) are enabled,
* will not loop on end,
* no loading image,
* 16:9
*/
await laSdk.video.load('url');

VideoBackgroundLoadOpts (load options)

interface VideoBackgroundLoadOpts {
/**
* Jump to given second as soon as the video is loaded.
*
* The video will load from position 0 otherwise.
*
* `0` by default
*/
initialPosition?: number;

/**
* `16/9` by default
*/
aspectRatio?: number;

/**
* Play the video as soon as it's loaded
*
* `true` by default
*/
autoPlay?: boolean;

/**
* Image to show while the video is loading
*
* `undefined` by default
*/
loadingImage?: string;

/**
* Play the video from the begining on end.
*
* `false` by default
*/
playOnLoop?: boolean;

/**
* Video title shown top-left in the control UI.
* It will be send along with `lavideoevent` events
*
* `undefined` by default
*/
title?: string;

/**
* Extra parameters to be send along with `lavideoevent` events
*
* `undefined` by default
*/
analyticsMetadata?: Record<string, string | number | boolean>;
}

To send extra parameters along with lavideoevent events, use analyticsMetadata option:

await laSdk.video.load('url', {
analyticsMetadata: {
foo: 'bar',
},
});

video events

subscribe to lavideoevent to handle pure video events (one from ):

window.addEventListener('lavideoevent', (ev: LACoreWeb.VideoEvent) => {
switch (ev.detail.state) {
case 'error':
// video error
break;
case 'ended':
// video ended
break;
case 'loadeddata':
// video fully loaded
break;
case 'loadstart':
// video starts loading
break;
case 'pause':
// video paused
break;
case 'play':
// video has begun (not paused)
break;
case 'playing':
// Playback is ready to start after having been paused or delayed due to lack of data.
break;
case 'timeupdate':
// video run 1 sec
break;
}
});
caution

Don't forget window.removeEventListener('lavideoevent', f).

laSdk.player

HTML5 + HLS.js Video Player (with default key-management and visual UI).

note

Use laSdk.video instead if need to override the default key-management or customize the visual UI.

💃 Check video-player for more details.

laSdk.player: PlayerClient

interface PlayerClient {
readonly currentTime: number;
readonly duration: number;
readonly isLoading: boolean;
readonly isPaused: boolean;
readonly isPlaying: boolean;
readonly src: string;
readonly timeLeft: number | null;

init(): Promise<void>;
load(url: string, opts?: PlayerLoadOpts): Promise<void>;
play(): Promise<void>;
pause(): Promise<void>;
plpause(): Promise<void>;
stop(): Promise<void>;
enableRemoteControl(): void
disableRemoteControl(): void
}

Example

/*
* loads the video on foreground,
* from the beginning,
* as soon as it's loaded,
* remote (and voice controls) are enabled,
* will not loop on end,
* no loading image,
* default controller elements UI
* 16/9
*/
await laSdk.player.load('url');

PlayerLoadOpts

interface PlayerLoadOpts {
/**
* `16/9` by default
*/
aspectRatio?: number;

/**
* Play the video as soon as it's loaded
*
* `true` by default
*/
autoPlay?: boolean;

/**
* Jump to given second as soon as the video is loaded.
* We can also send showModal property to show if we want to continue or reproduce from the beginning.
*
* The video will load from position 0 if nothing specified.
*
* `0` by default
*/
initialPosition?:
| number
| {
position: number;
showModal: boolean;
};

/**
* By default, the player shows controller elements UI such as:
*
* - progress bar,
* - play/pause button
* - restart button
* - feedback msgs.
* - title (if enabled)
* - ...
*
* Unless this option is set:
*
* ```js
* {
* hideControlUI: true
* }
* ```
*
* `false` by default
*/
hideControlUI?: boolean;

/**
* By default, the video will listen to remote control events
*
* `true` by default
*/
enabledRemoteControl?: boolean;

/**
* By default, video tag has z-index: "-1". However, it's possible
* to force it to z-index: "9" by using this property
*
* `false` by default
*/
showVideoOverContent?: boolean;

/**
* Restore the previously focused DOM element when video ends
*
* `false` by default
*/
restoreFocusOnStop?: boolean;

/**
* Image to show while the video is loading
*
* `undefined` by default
*/
loadingImage?: string;

/**
* Play the video from the begining on end.
*
* `false` by default
*/
playOnLoop?: boolean;

/**
* Video title shown top-left in the control UI.
*
* `undefined` by default
*/
title?: string;

/**
* Defines the next element to be focused when needs to navigate outside the
* bounds of the controls ui.
*
* `undefined` by default
*/
navigation?: {
down?: string;
up?: string;
};

/**
* Function that returns how much you want to jump with each press of forward keys
*
* by default apply the same movistar video player logic
*
* `undefined` by default
*/
forwardLogic?(): number;

/**
* Function that returns how much you want to jump with each press of backward keys
*
* by default apply the same movistar video player logic
*
* `undefined` by default
*/
backwardLogic?(): number;
}

player events

subscribe to laplayerevent to handle events related to the video player controls:

window.addEventListener('laplayerevent', (ev: LACoreWeb.PlayerEvent) => {
switch (ev.detail.state) {
case 'showControls':
// show player controls
break;
case 'hideControls':
// hide player controls
break;
case 'showFeedback':
// show feedback message
break;
case 'hideFeedback':
// hide feedback message
break;
}
});
caution

Don't forget window.removeEventListener.


laSdk.stb

STB wrapper to run some actions on the STB device.

interface Stb {
playMusic(): Promise<void>;
stopMusic(): Promise<void>;
runDetail(params: Record<string, unknown>): Promise<void>;
checkChannelAvailable(channel: number): Promise<boolean>;
}

laSdk.stb: Stb

Play background music (only available on Movistar STB via channel 0)

laSdk.stb.playMusic();

Stop background music (only available on Movistar STB via channel 0)

laSdk.stb.stopMusic();

Run detail action on STB. Eg: show channel info (only available on Movistar STB). It throws an exception otherwise.

laSdk.stb.runDetail({ productType: 0, productID: '1' });

laSdk.stb.tv

Check if a channel is subscribed and can be shown in the STB. The channel param is the dial of the channel. It throws an exception otherwise. It returns a promise that resolves a boolean indicating the availability of the channel.

laSdk.stb.tv.checkChannelAvailable(1);

Get the current channel in the STB, retrieve the sid, status and name of the channel.

laSdk.stb.tv.getCurrentChannel(): Promise<{ sid: number; status: number; name: string }>;

Play channel in the STB in background. The channel param is the dial of the channel.

laSdk.stb.tv.playChannel(1);

Stop live video in the STB.

laSdk.stb.tv.stopLiveVideo();

Set video window mode. The video window is the rectangle where the video is shown. The window param has the following properties:

  • left: left position of the window, 0 is te left side of the screen
  • top: top position of the window, 0 is the top of the screen
  • width: width of the window
  • height: height of the window

If no attribute is set, the default value is used, which is the full screen.

laSdk.stb.tv.setVideoWindow(window);

laSdk.sendKey()

Make your Living App receive a lakeypress event

laSdk.sendKey(code: number): void

Example:

onClick={() => {
laSdk.sendKey(laSdk.KEYS.KEY_BACK)
}}

laSdk.sendText()

Send voice command programmatically

laSdk.sendText(text: string): Promise<void>;

laSdk.setDialogContext()

Define the events your app will receive when user says something using voice remote control or Movistar Home.

laSdk.setDialogContext(commands: Record<string, string>): void

Example:

  laSdk.setDialogContext({
'hello living app': 'hello',
'buy product': 'buy',
});

...

window.addEventListener('lavoiceevent', (ev: CustomEvent) => {
if (ev.detail.event === 'hello') {
// user said "hello living app" (or close sentence)
} else if (ev.detail.event === 'buy') {
// user said "buy" (or close sentence)
}
});

synonyms

Provide multiple synonyms for the same event using |

laSdk.setDialogContext({
'hello living app|hello app|hi there': 'hello',
'buy product|purchase|deal': 'buy',
});

click events

Sometimes you'll just need to map voice events to "clicks" on DOM elements:

laSdk.setDialogContext({
'go home': 'click:home-button',
});

By using click: prefix, Living Apps Core SDK will automatically click on a DOM element with id home-button with no need to set any lavoiceevent listener.

key events

Sometimes you will need to trigger some key events using your voice:

laSdk.setDialogContext({
'go back': 'send_key:KEY_BACK',
});

By using send_key: prefix, Living Apps Core SDK will automatically try to trigger the key that you specified (see laSdk.KEYS for reference) with no need to set any lavoiceevent listener.

laSdk.getDialogContext()

Get current dialogContext

laSdk.getDialogContext(): <Record<string, string>>;

laSdk.addToDialogContext()

Add commands to the current dialog context.

laSdk.addToDialogContext(commands: Record<string, string>): Promise<void>;

laSdk.removeFromDialogContext()

Remove commands from the current dialog context.

laSdk.removeFromDialogContext(commands: Record<string, string>): Promise<void>;

laSdk.clearDialogContext()

Clear last dialogContext, same as setDialogContext({})

laSdk.clearDialogContext(): void;

laSdk.createSuggestions()

UI Component: Draw footer Suggestion Pill buttons.

laSdk.createSuggestions(
suggestions: [{ text: string; onClick: () => {}; up: string; aliases?: string[] }],
voice: boolean = true, // set Dialog Context for these entries
opts?: {
className?: string // added to div.la-suggestions
}
)

Example:

laSdk.createSuggestions([
{ text: 'Restart Router', onClick: routerRestar, up: 'home-element' },
{
text: 'Check Wifi',
onClick: checkWifi,
up: 'home-element',
aliases: ['Check internet', 'Check connection'],
},
]);

By using aliases we can create alternative ways to click a suggestion with our voice.

laSdk.removeSuggestions()

UI Component: Remove latest Suggestion Pills from DOM

laSdk.removeSuggestions(): void;

laSdk.persistenceDrop()

Remove all persistence entries for current user and living app

laSdk.persistenceDrop(): Promise<void>;

laSdk.persistenceWrite()

Store encoded string on a persistent database. This database is unique per user and Living App.

laSdk.persistenceWrite(key: string, value: string): Promise<void>;

laSdk.persistenceRead()

Read value for your previously stored key-value pair

laSdk.persistenceRead(key: string): Promise<unknown>;

Example:

await laSdk.persistenceWrite('user', JSON.stringify({ name: 'John' }));
const data = await laSdk.persistenceRead('user');
const name = JSON.parse(data);

laSdk.sendMh()

💃 Check Movistar Home

laSdk.sendStb()

💃 Check Movistar Home

laSdk.enableNavigable()

Enable Navigation Framework. If enabled, use laSdk.focus() and laSdk.focusedElement to focus DOM elements programatically.

laSdk.enableNavigable(): void
note

💃 Check Navigation

laSdk.disableNavigable()

Disable Navigation Framework. Useful if you need to block the UI while loading info.

laSdk.disableNavigable(): void
note

💃 Check Navigation

laSdk.currentFocus

Get current focused DOM element

laSdk.currentFocus: HtmlElement | null
note

💃 Check Navigation

laSdk.focus()

UI Component: focus DOM element by node (HTMLElement) or id

laSdk.focus(elem: HtmlElement | string): void
note

💃 Check Navigation

laSdk.userData

Get info about current user context: user identity and the device where the app is running on:

laSdk.userData: {
userId: string,
deviceId: string,
}

laSdk.channel

Channel where the LA is running on.

laSdk.channel: 'movistar-home' | 'set-top-box-haac'

laSdk.browserName

Browser where the Living App is running on.

type BrowserName =
| 'base'
| 'mh'
| 'gvp'
| 'desktop-stb'
| 'movistar'
| 'desktop-mh';

laSdk.browser: BrowserName

laSdk.locale

Get Living App environment locale: es-ES or pt-BR.

laSdk.locale: 'es-ES' | 'pt-BR'

laSdk.labUrl

Living Apps Backend URl

laSdk.labUrl: string

laSdk.env

Environment where the living app is running. Could be used to apply different local config.

laSdk.env:
| 'es-stg'
| 'es-pre'
| 'es-pro'
| 'br-stg'
| 'br-pre'
| 'br-pro';

laSdk.createToast()

UI Component: Display message with an animation from topside

laSdk.createToast(
toast: {
text: string;
type: 'info' | 'error' | 'success' | 'warning' | 'loading';
duration?: number; // in milliseconds
permanent?: boolean;
code?: string;
}
);

Example:

laSdk.createToast({
text: 'Lorem ipsum dolor sit amet.',
type: 'warning',
code: 'general.101',
duration: 10000,
});

laSdk.removeToast()

UI Component: Remove latest Toast from DOM

laSdk.removeToast();

UI Component: Open Magic Link experience.

magic link

Throws error if user is already inside magic link. Promise must be resolved before calling again.

Note that your Living App must have access to these T. Kernel APIs in order to use Magic Link:

caution

Magic Link notifications are not available for non "telco" Movistar users (~1%)

laSdk.createMagicLink(
config: {
flowId: string;
home?: {
title?: string;
description?: string;
};
appAction?: {
title?: string;
description?: string;
};
noAppAction?: {
title?: string;
description?: string;
androidQrUrl?: string;
iosQrUrl?: string;
webQrUrl?: string;
};
}) : Promise<void>

Example:

await laSdk.createMagicLink({
flowId: 'myFlowId',
home: {
title: 'Lorem ipsum dolor sit amet.',
description: 'Lorem ipsum dolor sit amet.',
},
appAction: {
title: 'Lorem ipsum dolor sit amet.',
description: 'Lorem ipsum dolor sit amet.',
},
noAppAction: {
title: 'Lorem ipsum dolor sit amet.',
description: 'Lorem ipsum dolor sit amet.',
androidQrUrl: 'https://example.com',
iosQrUrl: 'https://example.com',
webQrUrl: 'https://example.com',
},
});

laSdk.createQr()

Create QR dataURL image based on url

Example:

const qrImage = await laSdk.createQr('https://example.com');

<img src={qrImage} alt="example.com QR code" />;

Params:

URL

The url for the qr link.

OPTS

Object with the following keys:

  • useLab - boolean (false by default) : Enabling this option allows the inclusion of the final URL within the Lab-URL, which redirects to the specified URL (url parameter) while sending the metric la_url_access, instead of creating the final URL directly using the url parameter.

Example

const qrImage = await laSdk.createQr('https://example.com', { useLab: true });

// URL --> 'LAB_API_URL/s/LA_NAME?url=https://example.com';

<img src={qrImage} alt="example.com QR code with useLab" />;

laSdk.createLogger()

We export a wrapper to console.log() that "groups" given name and adds some minor feats:

Example:

const logger = laSdk.createLogger('My Super Screen');

logger object exposes 4 methods:

logger.debug(...data);
logger.info(...data);
logger.warn(...data);
logger.error(...data);

All four methods will work as their built-in counterparts. With the extra feature of mark a topic [[topic]] in your message if needed.

logger.debug('just an example');
logger.info('[[sendMessage]] >> %o', msg);
logger.info('[[receiveMessage]] << %o', ev);
logger.warn('[[onRender]] something happened: ', error);

laSdk.trackEvent()

Track event on Living Apps monitoring platform.

Living Apps SDK already tracks multiple events. We strongly believe that your app could be fully monitored with only core events: HTTP requests, focus, clicks, etc. Please think twice before adding your custom events.

info

Contact Living Apps Platform team in order to access to your application events.

Events already tracked by SDK:

  • la_webapp_load: app loaded
  • la_start: app fully started
  • la_close: app closed
  • la_send_command: command sent to Aura
  • la_receive_command: command received from aura
  • la_navigation_click: click on navigable HTML element (include id)
  • la_navigation_focus: focus navigable HTML element (include id)
  • la_video: video play/error/end/load/pause events (include video url, title, duration, video session id)
  • Ajax HTTP requests: all HTTP requests performed by the browser.

All events include the following core fields:

  • userId: unique user ID on Living Apps ecosystem.
  • sessionId: session Id shared on the entire Living App navigation.
  • deviceId: unique device ID (STB)
  • appUrl: application URL
  • livingAppName: your Living App name (AKA laName)

HTTP request events include the following core fields:

  • full url
  • HTTTP method
  • duration
  • req/res headers
  • status code

Custom events

Your custom events will be registered as la_custom with your laCustomEventName field.

laSdk.trackEvent<K>(name: string, data: Record<string, string> | K): void;

Example:

laSdk.trackEvent('show_product', { product_id: 'x234s1' });

will register at our Monitoring platform a la_custom event with the key laCustomEventName set to show_product; all 5 regular parameters - userId, sessionId, deviceId, appUrl, livingAppName - plus product_id

laSdk.trackScreen()

trackEvent shortcut to track when your Living App screen has been rendered.

laSdk.trackScreen(name: string): void;

same as:

laSdk.trackEvent(name: 'la_screen', {}): void;

React Example:

When a new screen component is mounted.

useEffect(() => {
laSdk.trackScreen('home');
}, []);

Opens another Living App. A.K.A. deep-link feature.

It will close the current Living App and open the target one, allowing developers to add specific query parameters so the target Living App could be initialized in a different way.

When the target Living App is closed, the previous one will be opened again, unless skipRestoreLivingAppOnExit is used. It's also possible to add some query parameters (via queryParamsOnRestore) so the first Living App could restore its state.

openLivingAppDeepLink(
laName: string,
opts?: {
queryParams?: Record<string, string>;
skipRestoreLivingAppOnExit?: boolean;
queryParamsOnRestore?: Record<string, string>;
},
): Promise<void>;

Example:

openLivingAppDeepLink('movistar-gaming', {
queryParams: {
entrypoint: 'latest-games',
},
queryParamsOnRestore: {
entrypoint: 'go-to-movistar-gaming',
},
});

laSdk.closeAndNavigateToExternalUrl()

Close current Living App session and navigate to a different URL outside the app.

closeAndNavigateToExternalUrl(url: string): Promise<void>;

Example:

await closeAndNavigateToExternalUrl(
'https://www.livingappsdevelopers.telefonica.com/',
);

laSdk.notifications

Notifications client. Opens a web-socket through which Telefonica kernel sends real-time notifications to the logged-in customer.

subscribe()

Requires as input a callback function to be invoked when a message is received for the customer. Returns the current state of the WebSocket connection, any value other than 1 (OPEN) should be considered an error.

Example:

    function callback<T>(data: T, error?: Error) {...}
const socketReadyState = await laSdk.notifications.subscribe( callback );
note

Check real time notifications for more details