# Fetch External APIs (CORS workaround)

Wallpapers run in an isolated `fluxlay://` origin, so outbound HTTP requests pass two gates:

1. **CSP `connect-src`** — only origins declared under `network:` in `fluxlay.yaml` are reachable.
2. **CORS** — even after CSP allows the origin, the browser blocks the response unless the upstream returns `Access-Control-Allow-Origin`.

Most REST APIs return CORS headers, so plain `fetch` works fine. But a lot of useful endpoints don't — ICS calendar feeds, public RSS, static file hosts. For those, use `proxiedFetch`.

## Normal case: direct `fetch`

If the API returns CORS headers, declare its origin and use `fetch` as usual.

```yaml
# fluxlay.yaml
network:
  - origin: https://api.github.com
    reason: Fetch open and review-requested PRs.
```

```tsx
const res = await fetch("https://api.github.com/search/issues?q=is:open+is:pr+author:@me", {
  headers: { Authorization: `Bearer ${token}` }
});
```

## When you hit a CORS error: `proxiedFetch`

If the browser logs `Origin ... is not allowed by Access-Control-Allow-Origin`, the upstream isn't returning CORS headers. Replace `fetch` with `proxiedFetch` — the rest stays the same.

```yaml
# fluxlay.yaml
network:
  - origin: https://calendar.google.com
    reason: Fetch the user's public ICS calendar feed.
```

```tsx
import { proxiedFetch } from "@fluxlay/react";

const res = await proxiedFetch("https://calendar.google.com/calendar/ical/.../basic.ics");
const ics = await res.text();
```

Internally `proxiedFetch` sends the request description to `POST /v1/network-proxy`, and the Rust host performs the actual fetch. CORS is a browser-side rule, so it doesn't apply to the host. The host still validates that the target URL's origin is declared in `network:`, so the security model is identical to direct `fetch`.

## Which one should I use?

Try `fetch` first. If you get a CORS error, switch to `proxiedFetch`. `proxiedFetch` has a few limitations (no streaming, 10 MiB body cap), so prefer the direct path when it works.

| Situation                                      | Recommended                  |
| ---------------------------------------------- | ---------------------------- |
| Upstream returns CORS headers (most REST APIs) | `fetch`                      |
| ICS / RSS / static files without CORS          | `proxiedFetch`               |
| Streaming responses / Server-Sent Events       | `fetch` (proxy can't stream) |

## Common pitfalls

- **Forgot to declare `network:`** — CSP `connect-src` blocks the request and you get `Failed to fetch` with no clear hint. Always check the manifest first.
- **GitHub returns 403 "User-Agent required"** — `proxiedFetch` sets `Fluxlay-Wallpaper-Proxy/<version>` automatically. No action needed.
- **Cookies aren't sent** — `proxiedFetch` deliberately strips the `Cookie` header. Pass auth via `Authorization` instead.

See the [proxiedFetch reference](/en/studio/developer/reference/sdk/proxied-fetch.md) for full details.
