TelemetryX Applications SDK
Welcome to the TelemetryX Applications SDK! This document will guide you through building applications for TelemetryX.
What is TelemetryX?
TelemetryX is a platform for running web applications on devices connected to displays, such as TVs and touch screen kiosks. It can manage thousands of devices per account, enabling organizations to create, manage, and deploy dynamic content and interactive applications across their physical locations.
Key features of the platform include:
- Run single-page applications on display devices.
- Support containers that run alongside applications.
- Run worker scripts that operate continuously in the background.
- Compose content with our Freeform Editor for visual layouts.
- Support content playlists and scheduling.
- Manage devices at scale.
Standard Applications in TelemetryX
Standard applications are web applications that run within TelemetryX's Freeform Editor. The Freeform Editor is our default visual content composition tool that allows users to create layouts by positioning applications alongside media, text, and other visual elements.
Your standard application will be embedded as an iframe within the Freeform Editor and can be positioned, resized, and scheduled as part of content playlists that display on physical devices like digital signage and kiosks.
Mount Points
Standard applications define mount points in their telemetry.config.json
file:
settings
- The configuration interface that appears in the Freeform Editor's sidebar when your application is selected. This runs in the administration UI where customers configure your app.
render
- The actual content that displays on devices and in the Freeform Editor's canvas. This is what end users see.
And optionally a worker script:
background
- A worker that runs continuously in the background, even when your application is not currently visible in the playlist rotation.
Integration with Freeform Editor
Since your application runs within the Freeform Editor, you get additional capabilities:
- Control playlist navigation - Move between playlist pages or modify page timing
- Trigger content overrides - Display emergency alerts or priority content that interrupts the normal playlist flow
- Communicate with other applications - Discover and embed other applications within your own interface
Getting Started
To get started, add the SDK to your project:
Installation
With npm:
npm install @telemetryx/sdk
Or include it directly in your HTML:
<script src="https://cdn.jsdelivr.net/npm/@telemetryx/sdk"></script>
Basic Configuration
Import and configure the SDK with your application name:
import { configure } from '@telemetryx/sdk';
configure('myAppName')
Or using the global object if you included the script directly:
telemetry.configure('myAppName')
The SDK automatically extracts the application ID from URL parameters, which is essential for proper functioning of the store's local and deviceLocal scopes.
Core SDK Features
Storage API
The SDK provides a powerful storage system with multiple scopes:
- Global - Shared across all instances of your application within an account. Use for app-wide settings like branding or global configuration.
- Local - Specific to this application instance (uses applicationId). Perfect for settings ↔ render communication since both mount points share the same instance.
- DeviceLocal - Stored only on the current device, never synced across devices. Survives device restarts. Ideal for kiosk interactions or device-specific calibration.
- Shared - Inter-application communication using namespace strings. Applications can coordinate by agreeing on namespace and key conventions.
The applicationId
is automatically provided when your application is embedded, ensuring that multiple instances of your app maintain separate configurations.
Example usage:
import { store } from '@telemetryx/sdk';
await store().global.set('companyBranding', { logo: 'url', colors: {...} });
await store().local.set('city', 'New York');
await store().deviceLocal.set('calibrationData', { brightness: 0.8 });
await store().shared.set('weather-data', 'temperature', '72°F');
const cityHandler = (newCity) => {
console.log(`City updated to: ${newCity}`);
updateWeatherDisplay(newCity);
};
store().local.subscribe('city', cityHandler);
store().local.unsubscribe('city', cityHandler);
Store subscriptions are essential for real-time applications. When a setting is changed (e.g., in the settings mount point), the render mount point will receive immediate updates through store subscriptions.
Application Discovery
Applications can discover and embed other applications:
import { applications } from '@telemetryx/sdk';
const widgets = await applications().getAllByMountPoint('dashboard-widget');
const url = await applications().getUrl('weather-app', 'render');
const iframe = document.createElement('iframe');
iframe.src = url;
document.body.appendChild(iframe);
Media Access
Access media content uploaded to TelemetryX:
import { media } from '@telemetryx/sdk';
const folders = await media().getFoldersByTag('marketing');
const content = await media().getMediaContentByFolderId(folderId);
const mediaItem = await media().getMediaContentById(mediaId);
const publicUrl = mediaItem.publicUrls[0];
Account and User Information
Access information about the current account and user:
import { accounts, users } from '@telemetryx/sdk';
const account = await accounts().getCurrent();
const userResult = await users().getCurrent();
const userId = userResult.user.id;
Playlist Control
Control the Freeform Editor's playlist state, allowing your application to navigate through playlist pages and modify timing:
import { playlist } from '@telemetryx/sdk';
await playlist().nextPage();
await playlist().previousPage();
await playlist().setDuration(30);
Content Overrides
Manage content overrides within the Freeform Editor to temporarily display specific content:
import { overrides } from '@telemetryx/sdk';
await overrides().setOverride('emergency-alert');
await overrides().clearOverride('emergency-alert');
Communication Patterns
The SDK uses a request-response pattern for most operations. All requests have a 30-second timeout by default to prevent hanging promises:
try {
const result = await someAsyncSdkOperation();
} catch (error) {
console.error('Operation failed:', error.message);
}
Offline Support
Your applications automatically work offline without any additional code. TelemetryX handles caching for you:
- Applications are cached locally on devices for offline operation
- Store system works offline - all data reads and writes continue normally, syncing when back online
- External API calls are cached - HTTP requests to external services work offline using cached responses
- No configuration needed - offline support is completely automatic
This means users can interact with your application even when devices lose internet connectivity.
Advanced Features
Worker Scripts
Worker scripts run in the background even when your application isn't currently visible in the playlist rotation. For standard applications, they start automatically when a playlist containing your application is loaded (on devices) or opened for editing (in the administration UI). Define them in your telemetry.config.json
:
{
"name": "my-application",
"version": "1.0.0",
"workers": [
{
"script": "./workers/background-sync.js"
}
]
}
Worker scripts can access the SDK by importing and configuring it just like the main application. They're ideal for:
- Periodic data synchronization.
- Processing background tasks.
- Maintaining real-time connections.
- Updating shared state even when the main app is not in view.
Containers
Containers allow you to run more complex backend services alongside your application. They run in a local Docker instance, with traffic to specific hostnames automatically tunneled to the appropriate container.
Define containers in your telemetry.config.json
:
{
"name": "my-application",
"version": "1.0.0",
"containers": [
{
"name": "my-backend",
"image": "mybackend:latest",
"port": 3000
}
]
}
Access the container from your application (containers only run on devices):
fetch('https://my-backend/api/data')
.then(response => response.json())
.then(data => console.log(data));
telemetry.config.json
Configuration
Your application must include a telemetry.config.json
file at the root level:
{
"name": "my-application",
"version": "1.0.0",
"displayName": "My Application",
"description": "A TelemetryX application that does amazing things",
"mountPoints": {
"render": {
"path": "/render"
},
"settings": {
"path": "/settings"
}
},
"workers": [
{
"name": "background",
"script": "./workers/background.js"
}
],
"containers": []
}
This configuration:
- Defines your application name and metadata
- Specifies mount points for different application contexts
- Configures background workers
- Sets up containers if needed
Best Practices
-
Store Usage
- Use the appropriate store scope for your data
- Always subscribe to changes for real-time updates rather than polling
- Consider data persistence requirements when choosing a scope
-
Application Structure
- Clearly separate your settings UI from your render UI using mount points
- Handle settings changes gracefully in the render view
- Consider using a state management library with the SDK for complex applications
-
Performance
- Optimize your application for performance on TelemetryX
- Use worker scripts for background tasks and to maintain state during playlist transitions
- Implement efficient rendering patterns to minimize resource usage
-
Error Handling
- Implement robust error handling for all SDK operations
- Account for timeout scenarios (30-second default)
- Provide fallback content when network operations fail
-
Responsive Design
- Design your application to adapt to different screen sizes and orientations
- Test your application on different device types
- Consider touch interaction for kiosk deployments
Development Workflow
- Develop and test your application locally
- Package your application with its config file
- Upload to TelemetryX
- Add your application to a playlist
- Assign your playlist to one or more devices
Implementation Patterns and Examples
This section provides structured examples of common implementation patterns to help you build effective TelemetryX applications.
SDK Architecture Overview
- Core Communication: The SDK uses the
postMessage
API for communication with TelemetryX.
- Message Flow: Messages flow between applications and TelemetryX via the parent window.
- Resource APIs: Domain-specific APIs (store, media, applications, etc.) are built on top of the core messaging APIs.
- Configuration Flow: Applications must call
configure()
before using any SDK features.
Common Implementation Patterns
1. Fetching and Displaying Media
import { media } from '@telemetryx/sdk';
async function displayMedia(mediaId) {
const mediaItem = await media().getMediaContentById(mediaId);
const mediaElement = document.createElement('img');
mediaElement.src = mediaItem.publicUrls[0];
document.body.appendChild(mediaElement);
}
2. Settings Communication Between Mount Points
import { store } from '@telemetryx/sdk';
async function saveSettings(city) {
await store().local.set('city', city);
}
function setupSettingsListener() {
store().local.subscribe('city', (city) => {
updateWeatherDisplay(city);
});
store().local.get('city').then(city => {
if (city) updateWeatherDisplay(city);
});
}
3. Embedding Another Application
import { applications } from '@telemetryx/sdk';
async function embedWeatherWidget(containerId) {
const url = await applications().getUrl('weather-app', 'render');
const container = document.getElementById(containerId);
const iframe = document.createElement('iframe');
iframe.src = url;
iframe.style.border = 'none';
iframe.style.width = '100%';
iframe.style.height = '100%';
container.appendChild(iframe);
}
4. Implementing a Background Worker
import { configure, store } from '@telemetryx/sdk';
configure('myApp');
async function syncData() {
try {
const data = await fetchExternalData();
await store().global.set('latestData', data);
} catch (error) {
console.error('Sync failed:', error);
}
setTimeout(syncData, 60000);
}
syncData();
5. Robust Error Handling
Always implement proper error handling for SDK operations:
try {
const result = await media().getFoldersByTag('marketing');
displayFolders(result);
} catch (error) {
if (error.message.includes('timed out')) {
showTimeoutMessage();
} else {
showGenericError();
}
displayCachedContent();
}
Complete Application Examples
Weather Application
import { configure, store } from '@telemetryx/sdk';
configure('weather-app');
document.getElementById('cityForm').addEventListener('submit', async (e) => {
e.preventDefault();
const city = document.getElementById('cityInput').value;
await store().local.set('city', city);
showSuccessMessage('City saved successfully');
});
store().local.get('city').then(city => {
if (city) {
document.getElementById('cityInput').value = city;
}
});
import { configure, store } from '@telemetryx/sdk';
configure('weather-app');
store().local.subscribe('city', (city) => {
if (city) {
fetchAndDisplayWeather(city);
} else {
showConfigurationMessage();
}
});
store().local.get('city').then(city => {
if (city) {
fetchAndDisplayWeather(city);
} else {
showConfigurationMessage();
}
});
async function fetchAndDisplayWeather(city) {
try {
const weather = await fetchWeatherData(city);
renderWeatherUI(weather);
} catch (error) {
showErrorMessage('Could not load weather data');
}
}
Dashboard Container Application
import { configure, applications } from '@telemetryx/sdk';
configure('dashboard-app');
async function initializeDashboard() {
try {
const widgets = await applications().getAllByMountPoint('dashboard-widget');
if (widgets.length === 0) {
showNoWidgetsMessage();
return;
}
const container = document.getElementById('widgetsContainer');
for (const widget of widgets) {
const widgetElement = document.createElement('div');
widgetElement.className = 'widget-container';
const url = await applications().getUrl(widget.name, 'dashboard-widget');
const iframe = document.createElement('iframe');
iframe.src = url;
iframe.title = widget.name;
iframe.frameBorder = '0';
iframe.style.width = '100%';
iframe.style.height = '100%';
widgetElement.appendChild(iframe);
container.appendChild(widgetElement);
}
} catch (error) {
console.error('Failed to initialize dashboard:', error);
showErrorMessage();
}
}
document.addEventListener('DOMContentLoaded', initializeDashboard);
Support and Resources
For more information or support, please visit our documentation or contact our support team.
Happy building!