# When the browser blocks the call.

> Why the browser blocks a try-it call, how ApiGlow diagnoses it, and the ways through: CORS headers on the API, a proxy you host, cookie credentials.
>
> Source: https://apiglow.dev/docs/cors/index.md


Try-it requests are plain `fetch` calls from the reader's browser to your API. Nothing passes through a server of ours, because there isn't one — which also means nothing can work around the browser's same-origin policy. If the docs and the API live on different origins, **the API must allow the docs' origin via CORS**, or the browser blocks the call before it leaves.

When a send fails, ApiGlow diagnoses it in the UI: offline, mixed content, CORS, or an unreachable host. The diagnosis is phrased as "most likely", because the browser hides the details from the page.

## Allow the docs' origin

Answer the preflight with `Access-Control-Allow-Origin` naming the docs' origin — or `*` for a public API without credentials — plus the methods and headers your API uses.

If the docs are served from the API's own origin, there is no cross-origin request and nothing to configure.

## Expose the headers worth reading

Without `Access-Control-Expose-Headers` on the API side, the browser reveals only a short safelist of response headers. Rate-limit, pagination and deprecation headers stay invisible even when the call succeeds, and ApiGlow flags that. Expose them and the [network insights](/docs/try-it/) get their material back.

`Timing-Allow-Origin` does the same job for transfer facts. Without it, a cross-origin response reports sizes of zero, and the compression and cache chips do not render.

## A proxy, if you host one

`tryIt.proxyUrl` declares a CORS proxy as a template, where `{{target}}` is replaced by the encoded target URL:

```json
{ "tryIt": { "proxyUrl": "https://proxy.example.com/?url={{target}}" } }
```

The app ships no proxy and runs none. This is a hook for one you host and trust. When it is configured, the UI suggests it on CORS failures.

## Session-cookie auth

For an API authenticated by an httpOnly session cookie, the browser neither stores nor sends the cookie cross-origin by default. Set `tryIt.requestCredentials: "include"` and meet the three server-side requirements that come with it:

- `Access-Control-Allow-Credentials: true`
- an explicit `Access-Control-Allow-Origin` — `*` is rejected
- a `SameSite=None; Secure` cookie

Note that `"include"` is incompatible with `Access-Control-Allow-Origin: *`: the browser rejects the preflight even when there is no cookie to send. In a [multi-spec](/docs/multi-spec/) installation, set this on the spec entry that needs it rather than at the root.

## OAuth2 adds two requirements

The in-browser flows — Authorization Code + PKCE, and client credentials — need two things from the authorization server:

- The `redirect_uri` sent is the host page's URL without its hash, and must be registered as-is.
- The token endpoint must allow the docs' origin in CORS, like any other try-it call.

## Or avoid CORS entirely

`openapi.spec` carries the schema in the page and removes the schema fetch from the equation. Hosting the docs on the API's own origin removes the rest: same origin, no preflight, and the `"same-origin"` default works as it is.

