Skip to main content
When a browser frontend on one origin calls a Blaxel preview URL, the browser enforces CORS. This page explains which CORS headers Blaxel returns, how to change them, and how to check the result.

How Blaxel handles CORS

Blaxel handles CORS differently for preflight requests and normal responses on a preview URL.
  • Preflight (OPTIONS) requests are answered by Blaxel directly. They never reach your application, and they do not require authentication, even on a private preview.
  • Normal responses come from your application. Blaxel adds CORS headers only when your application does not set them.
By default, a preflight response contains:
These defaults work for requests without credentials that only send the listed headers. You need to configure the preview when:
  • your frontend sends other request headers
  • your frontend sends credentials (fetch(..., { credentials: "include" })), because browsers reject Access-Control-Allow-Origin: * on credentialed requests

Configure CORS headers on a preview

Set CORS headers in the preview’s responseHeaders. Blaxel applies them in the following order: When you set CORS headers:
  • Set Access-Control-Allow-Origin to your frontend’s exact origin (scheme, host and port, without a trailing slash).
  • List every request header your frontend sends in Access-Control-Allow-Headers. Your value replaces the default list, so add X-Blaxel-Preview-Token back if your frontend sends it.
  • Omit Access-Control-Allow-Credentials, because Blaxel already adds Access-Control-Allow-Credentials: true.

Handle CORS in your application

Your application can set its own CORS headers on normal responses, for example to echo the request Origin from a list of allowed origins. Blaxel keeps the values set by your application. Your application cannot handle preflights, because Blaxel answers them. Set the preflight headers in the preview’s responseHeaders.

Send credentials to a private preview

Browsers send credentials to a private preview when you call it with credentials: "include". Open <PREVIEW_URL>/?bl_preview_token=<token> once in the browser: Blaxel sets a bl_preview_token cookie (SameSite=None; Secure) that the browser sends with later credentialed requests. You can also send the token in the X-Blaxel-Preview-Token header. For details on tokens, see private preview URLs. For credentialed requests, set Access-Control-Allow-Origin to your frontend’s origin, as described in Configure CORS headers on a preview.
When a request to a private preview fails authentication, Blaxel returns a 401 with Access-Control-Allow-Origin: *. On a credentialed request, the browser reports a CORS error instead of the 401. If the preflight passes but the request fails with a CORS error, check your token first.

Check your CORS configuration

Send a preflight with curl:
The output contains your origin and your header list. If you see access-control-allow-origin: *, the preview does not have your headers. Check preview.spec.responseHeaders. To check a normal response, send a regular request. For a private preview, pass a preview token:
To check in the browser, open your frontend at $ORIGIN and run the following in the devtools console:
The call returns a status code, with no CORS error. In the Network tab, the OPTIONS request shows your origin in access-control-allow-origin.

Limitations

  • One origin per preview. Preflight headers are static, so a preview allows a single origin for credentialed requests. To allow several origins (for example staging and production), create one preview per origin.
  • Static header list. Every request header your frontend sends must be listed in Access-Control-Allow-Headers.
  • Preflight cache. Browsers cache preflights for up to 24 hours (Access-Control-Max-Age: 86400). After changing the headers, hard-reload the page or test in a new private window.

Real-time previews

Create public and private preview URLs for a sandbox.

Custom domains

Serve a preview on your own domain.
Last modified on October 1, 2026