# Understanding CORS in TelemetryOS Applications Critical information about Cross-Origin Resource Sharing (CORS) and how it affects your applications running in browser contexts. # Understanding CORS in TelemetryOS Applications Critical information about Cross-Origin Resource Sharing (CORS) and how it affects your applications. ## What is CORS? **CORS (Cross-Origin Resource Sharing)** is a browser security mechanism that controls which websites can make requests to your application or API. ### The Problem Web browsers enforce the **Same-Origin Policy** for security: ``` Your App Origin: https://your-app.telemetryos.com External API: https://api.weather.com Without CORS approval: ❌ Browser blocks the request With CORS approval: ✅ Browser allows the request ``` **An "origin" consists of:** * Protocol (`https://`) * Domain (`api.weather.com`) * Port (`:443` for HTTPS) Requests to a different origin require CORS permission from the target server. ## Why CORS Matters for TelemetryOS TelemetryOS applications run in **browser contexts**: 1. **On Devices** - Applications run in iframes on TVs, kiosks, displays 2. **In Studio** - Settings mount points run in admin portal iframes 3. **Local Development** - Applications run in your browser during `tos serve` **All of these contexts enforce CORS.** ### Common CORS Error ``` Access to fetch at 'https://api.example.com/data' from origin 'https://your-app.telemetryos.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. ``` This error means: * The external API doesn't allow requests from your application's origin * The browser blocked the request for security * You cannot bypass this in client-side code ## When CORS Blocks Your Requests ### Scenario 1: Public API Without CORS ```typescript // This will likely fail with CORS error const response = await fetch('https://api.publicdata.com/stats'); ``` **Why:** Many public APIs don't enable CORS because they expect server-side usage only. ### Scenario 2: Private API Without CORS ```typescript // This will fail with CORS error const response = await fetch('https://your-company-api.com/data'); ``` **Why:** Your own API might not have CORS configured if it was built for server-to-server communication. ### Scenario 3: API with Restricted CORS ```typescript // API only allows requests from example.com // Your telemetryos.com origin is blocked const response = await fetch('https://partner-api.com/data'); ``` **Why:** API configured CORS to only allow specific domains. ## The TelemetryOS Solution: Proxy API TelemetryOS provides a **Proxy API** that bypasses CORS restrictions by routing requests through the TelemetryOS platform. ### How It Works ``` ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ Your App │ (1) │ TelemetryOS │ (2) │ External │ │ (Browser) │───────▶│ Platform │───────▶│ API │ │ │ │ (Server) │ │ │ └──────────────┘ └──────────────┘ └──────────────┘ │ │ │◀────────────────────────┘ │ (3) │ ▼ ┌──────────────┐ │ Your App │ │ (Response) │ └──────────────┘ ``` **Steps:** 1. Your app calls `proxy().fetch(url)` - Request goes to TelemetryOS platform 2. Platform makes server-to-server request (no CORS restrictions) 3. Platform returns response to your app **Key Point:** Server-to-server requests don't have CORS restrictions. The Proxy API moves the request to the server side. ## Using the Proxy API ### Basic Usage ```typescript import { proxy } from '@telemetryos/sdk'; // Instead of direct fetch // const response = await fetch('https://api.example.com/data'); // Use proxy const response = await proxy().fetch('https://api.example.com/data'); const data = await response.json(); ``` ### With API Keys ```typescript async function fetchWeather(city: string) { const apiKey = 'your-api-key-here'; const url = `https://api.weatherapi.com/v1/current.json?key=${apiKey}&q=${city}`; // Proxy handles CORS const response = await proxy().fetch(url); if (!response.ok) { throw new Error(`HTTP ${response.status}: ${response.statusText}`); } return await response.json(); } ``` ### POST Requests ```typescript async function submitData(data: any) { const response = await proxy().fetch('https://api.example.com/submit', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data) }); return await response.json(); } ``` ### Custom Headers ```typescript const response = await proxy().fetch('https://api.example.com/data', { headers: { 'Authorization': 'Bearer your-token', 'X-Custom-Header': 'value' } }); ``` ## When Proxy API is NOT Needed ### 1. CORS-Enabled APIs Some APIs explicitly enable CORS: ```typescript // This works because API allows all origins const response = await fetch('https://api.coinbase.com/v2/exchange-rates'); ``` **How to Check:** Look for API documentation mentioning CORS support or "browser-friendly" APIs. ### 2. TelemetryOS Resources TelemetryOS-hosted resources already allow your origin: ```typescript // Media API returns publicUrls that work directly const media = await media().getAllByTag('featured'); const imageUrl = media[0].publicUrls[0]; // Direct usage works ``` ### 3. Public CDNs Most CDNs enable CORS for asset delivery: ```typescript // Public CDN resources typically work ``` ## Best Practices ### 1. Default to Proxy for External APIs ```typescript // ✅ Safe - always works const response = await proxy().fetch('https://api.example.com/data'); // ❌ Risky - may work in dev, fail in production const response = await fetch('https://api.example.com/data'); ``` ### 2. Test with Real APIs During Development Local development may not enforce CORS the same way production does: ```bash # Test with actual external APIs tos serve # Make real API calls, don't mock everything ``` ### 3. Handle Proxy Errors ```typescript try { const response = await proxy().fetch(url); if (!response.ok) { throw new Error(`HTTP ${response.status}`); } const data = await response.json(); return data; } catch (error) { console.error('API call failed:', error); // Provide fallback or user-friendly error return null; } ``` ### 4. Cache Responses When Possible The proxy benefits from platform-level caching, but you can add application-level caching: ```typescript async function fetchWithCache(url: string) { // Check device storage cache const cached = await store().device.get(`cache:${url}`); if (cached) return cached; // Fetch through proxy const response = await proxy().fetch(url); const data = await response.json(); // Cache for next time await store().device.set(`cache:${url}`, data); return data; } ``` ## Common CORS Scenarios ### Scenario 1: Weather API Integration ```typescript // ❌ Without proxy - CORS error async function getWeatherBad(city: string) { const response = await fetch( `https://api.weatherapi.com/v1/current.json?key=API_KEY&q=${city}` ); return await response.json(); } // ✅ With proxy - works perfectly async function getWeatherGood(city: string) { const response = await proxy().fetch( `https://api.weatherapi.com/v1/current.json?key=API_KEY&q=${city}` ); return await response.json(); } ``` ### Scenario 2: Your Own Backend API ```typescript // If you have a backend API // ❌ Without CORS configuration or proxy const response = await fetch('https://your-backend.com/api/data'); // ✅ Option 1: Configure CORS on your backend // Allow: https://*.telemetryos.com // ✅ Option 2: Use proxy const response = await proxy().fetch('https://your-backend.com/api/data'); ``` ### Scenario 3: GraphQL APIs ```typescript async function queryGraphQL(query: string) { const response = await proxy().fetch('https://api.example.com/graphql', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ query }) }); return await response.json(); } ``` ## Troubleshooting CORS Issues ### Error: "blocked by CORS policy" **Solution:** Use `proxy().fetch()` instead of `fetch()` ### Error: "Failed to fetch" **Check:** 1. Is the URL correct? 2. Is the API endpoint online? 3. Are you using `proxy().fetch()` for external APIs? 4. Check browser console for specific CORS error ### Local Development Works, Production Fails **Cause:** Local development may not enforce CORS the same way. **Solution:** Always test with `proxy().fetch()` even in local development. ### API Returns 403/401 **Not CORS:** This is an authentication/authorization error. **Solution:** Check API keys, tokens, and authentication headers. ## Additional Proxy Benefits Beyond solving CORS, the Proxy API provides: 1. **Caching** - Platform caches responses, reducing API calls 2. **Bandwidth Optimization** - Shared quota across all devices 3. **Monitoring** - Track API usage and performance 4. **Rate Limiting** - Platform handles rate limits gracefully 5. **Error Recovery** - Automatic retries for transient failures ## Summary **Key Takeaways:** * ✅ TelemetryOS apps run in browser contexts with CORS enforcement * ✅ Use `proxy().fetch()` for all external API calls * ✅ Proxy API solves CORS + adds caching and optimization * ✅ Test with real APIs during development * ❌ Cannot disable CORS in browser environments * ❌ Direct fetch to non-CORS APIs will fail **Quick Decision Guide:** ```typescript // External APIs (weather, news, social media, etc.) await proxy().fetch(url) // ✅ Always use proxy // TelemetryOS resources (media, etc.) await fetch(publicUrl) // ✅ Direct fetch is fine // Your own backend // Either enable CORS on backend OR use proxy await proxy().fetch(url) // ✅ Safest option ``` ## Next Steps * **[Proxy Methods Reference](../sdk-methods/platform-api.md#proxy-api)** - Complete proxy().fetch() documentation * **[Code Examples](./code-examples.md)** - See proxy usage in context * **[Quick Start](../Development/quick-start.md)** - Build your first application