# 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