Quick Start Guide
Get started building TelemetryOS applications in minutes
Quick Start Guide
Get started building TelemetryOS applications in minutes.
Prerequisites
- Node.js 18+
- npm or pnpm
- Basic knowledge of JavaScript/TypeScript and web development
Installation
Developer App
Download the TelemetryOS Developer App from Studio. The Developer App includes the tos CLI for scaffolding, developing, and publishing applications.
# Create new application
tos init my-weather-app
# Or create an application with web mount point support
tos init my-menu-app --template vite-react-typescript-web
# Navigate to project
cd my-weather-app
# Open in Developer App
tos devManual SDK Installation
The SDK integrates into existing projects through npm installation:
npm install @telemetryos/sdkFirst Application
Project Structure
A TelemetryOS application typically has this structure:
my-weather-app/
├── src/
│ ├── views/
│ │ ├── Render.tsx # Display content (runs on devices)
│ │ └── Settings.tsx # Configuration UI (runs in admin)
│ ├── App.tsx # Routing between views
│ └── index.tsx # Entry point
├── telemetry.config.json # Application configuration
├── package.json
├── vite.config.ts
└── tsconfig.json
Applications with a web mount point (created with --template vite-react-typescript-web) include an additional view:
my-menu-app/
├── src/
│ ├── views/
│ │ ├── Render.tsx # Display content (runs on devices)
│ │ ├── Settings.tsx # Configuration UI (runs in admin)
│ │ └── Web.tsx # Management interface (runs in any browser)
│ ├── App.tsx # Routing between views
│ └── index.tsx # Entry point
├── telemetry.config.json # Application configuration
├── package.json
├── vite.config.ts
└── tsconfig.json
Configuration File
Create telemetry.config.json in the project root:
{
"name": "my-weather-app",
"version": "2026.1.0",
"mountPoints": {
"render": "/render",
"settings": "/settings"
},
"devServer": {
"runCommand": "vite --port $PORT",
"url": "http://localhost:$PORT",
"readyPattern": "VITE.*ready in"
}
}The name field is the application identifier used by the platform. The version field uses CalVer format (YYYY.M.PATCH). The mountPoints object maps view names to URL paths for your render and settings views. The devServer object tells the Developer App how to start your local development server — $PORT is replaced at runtime with an available port, and readyPattern detects when the server is ready from its stdout output.
Settings View
Create the configuration UI that runs in the admin portal:
src/views/Settings.tsx:
import { useEffect, useState } from 'react';
import { configure, store } from '@telemetryos/sdk';
configure();
export function Settings() {
const [city, setCity] = useState('');
// Load current city on mount
useEffect(() => {
store().instance.get<string>('city').then(savedCity => {
if (savedCity) setCity(savedCity);
});
}, []);
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
await store().instance.set('city', city);
alert('Settings saved!');
};
return (
<div className="settings">
<h2>Weather App Settings</h2>
<form onSubmit={handleSubmit}>
<label>
City:
<input
type="text"
value={city}
onChange={(e) => setCity(e.target.value)}
placeholder="Enter city name"
/>
</label>
<button type="submit">Save</button>
</form>
</div>
);
}Render View
Create the display content that runs on devices:
src/views/Render.tsx:
import { useEffect, useState } from 'react';
import { configure, store } from '@telemetryos/sdk';
configure();
export function Render() {
const [city, setCity] = useState<string | null>(null);
const [weather, setWeather] = useState<any>(null);
useEffect(() => {
// Subscribe to city changes
const handler = (newCity: string) => {
setCity(newCity);
fetchWeather(newCity);
};
store().instance.subscribe('city', handler);
// Load initial value
store().instance.get<string>('city').then(savedCity => {
if (savedCity) {
setCity(savedCity);
fetchWeather(savedCity);
}
});
return () => {
store().instance.unsubscribe('city', handler);
};
}, []);
const fetchWeather = async (cityName: string) => {
// Fetch weather data for the city
// Implementation details omitted for brevity
setWeather({ temp: '72°F', condition: 'Sunny' });
};
if (!city) {
return <div className="render">Please configure a city in settings</div>;
}
return (
<div className="render">
<h1>{city}</h1>
{weather && (
<>
<div className="temp">{weather.temp}</div>
<div className="condition">{weather.condition}</div>
</>
)}
</div>
);
}Routing
Set up routing between views based on URL path:
src/App.tsx:
import { Settings } from './views/Settings';
import { Render } from './views/Render';
export function App() {
const path = window.location.pathname;
if (path === '/settings') {
return <Settings />;
}
if (path === '/render') {
return <Render />;
}
return <div>404 - Not Found</div>;
}src/index.tsx:
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import { App } from './App';
createRoot(document.getElementById('root')!).render(
<StrictMode>
<App />
</StrictMode>
);Local Development
Development Server
The tos dev command (alias: tos serve) opens your project in the Developer App:
tos devThe Developer App reads your telemetry.config.json, starts your dev server (typically Vite), and provides a simulated TelemetryOS environment so you can test SDK features without connecting to the live platform.
Mount Point Testing
Mount points are displayed within the Developer App:
- Render: Shown on the main canvas with adjustable aspect ratios and backgrounds
- Settings: Shown in the settings sidebar panel
- Web: Shown in the Web tab (if
mountPoints.webis configured)
The Developer App provides mock SDK responses, enabling testing without TelemetryOS platform connection.
SDK Initialization
Always call configure() early in the application lifecycle:
import { configure } from '@telemetryos/sdk';
configure();Important: Call configure() once before using other SDK features.
Communication Between Views
Settings and render views share the same instance storage scope:
// In Settings - save configuration
await store().instance.set('city', 'New York');
// In Render - subscribe to changes
store().instance.subscribe('city', (newCity) => {
console.log('City changed to:', newCity);
});This pattern enables real-time updates when configuration changes.
Error Handling
All SDK operations can throw errors or timeout (30 seconds):
try {
await store().instance.set('key', 'value');
} catch (error) {
console.error('Failed to save:', error);
// Show user-friendly error message
}Deployment Methods
TelemetryOS supports three deployment methods. GitHub integration provides automated Git-to-Screen deployment and is recommended for production workflows.
GitHub Integration
GitHub integration enables automated deployment through repository connection:
# Initialize git and push to GitHub
git init
git add .
git commit -m "Initial commit"
git remote add origin https://github.com/your-org/weather-widget.git
git push -u origin mainIn Studio, use the Applications interface to connect your GitHub repository. Once connected, the platform establishes secure access to your source code. Select a branch to determine which commits trigger builds, and the platform will automatically build and deploy on every push.
Archive Upload
Archive upload supports manual deployment when Git is unavailable:
# Build the application
npm run build
# Create zip archive
cd dist
zip -r ../my-weather-app.zip .In Studio, use the Applications interface to upload your zip archive. The platform extracts the archive contents, executes your build scripts using the configured parameters, and deploys the application after a successful build. Note that archive uploads require manual updates for code changes; automatic builds are not available.
Generic Git Repository
Generic Git repository support accommodates GitLab, Bitbucket, or self-hosted Git services. Push your code to your hosting service, then use the generic Git repository option in Studio to provide the repository URL. Deploy keys provide secure repository access, and webhook configuration enables automatic builds on push.
Post-Deployment
After successful deployment, your application appears in the Studio Applications list. From there you can add it to playlists as a resizable region, access its settings interface by selecting the application within a playlist, and deploy it to devices by assigning the playlist.
Next Steps
- Mount Points - Understand render, settings, and web components
- Storage Methods - Learn all four storage scopes
- Configuration - Complete telemetry.config.json reference
- Code Examples - See complete working applications
Common Patterns
Loading Initial Data
useEffect(() => {
store().instance.get<string>('setting').then(value => {
if (value) setSettingValue(value);
});
}, []);Real-Time Updates
useEffect(() => {
const handler = (newValue: any) => {
setMyState(newValue);
};
store().instance.subscribe('key', handler);
return () => {
store().instance.unsubscribe('key', handler);
};
}, []);Error Recovery
try {
const data = await media().getAllByTag('marketing');
displayMedia(data);
} catch (error) {
// Provide fallback
displayPlaceholder();
}Troubleshooting
SDK Configuration Errors:
The configure() call must happen before using any other SDK functions.
Timeout Errors: Network connectivity issues cause SDK operation timeouts (30-second default). Implement retry logic to handle transient failures for critical operations, and provide fallback content so displays never show blank states.
Storage Persistence Issues:
The storage scope you choose (application, instance, device, or shared) determines data visibility across components. A successful set() response confirms data persistence, so if data appears missing, check for scope mismatches between the writing and reading components.
Mount Point Loading Issues:
Mount point paths in telemetry.config.json must match your application's routing configuration. If mount points fail to load, check the browser console for specific routing or configuration errors.
Development Best Practices
Call configure() at application startup before using any other SDK features. This ensures the SDK is properly initialized when your components begin rendering.
Use the subscription pattern for real-time updates rather than polling. Subscriptions are efficient and ensure your render views reflect configuration changes immediately, whereas polling wastes resources and introduces unnecessary latency.
Wrap all async SDK operations in error handling. Every call to store(), media(), or proxy() can fail due to network issues or timeouts, so error handling ensures your application degrades gracefully instead of crashing.
Use tos dev for rapid iteration. The Developer App provides a simulated TelemetryOS environment locally, so you can test SDK interactions without deploying to the platform.
Take advantage of TypeScript definitions throughout your application. The SDK ships with full type coverage, which catches configuration mistakes and API usage errors at development time rather than in production.
Updated about 1 hour ago