Skip to main content

CORS

CORS (Cross-Origin Resource Sharing) is how a server tells the browser that another website is allowed to read its responses. By default a browser lets a page from https://app.example.com request https://cdn.example.com/data.json, but it will not let the page read what came back unless the response says so.

Paradarum ships CORS off. That is the standard behaviour of the web — the same-origin policy — and it is the right default: opening your responses to other sites should be a deliberate decision, not something that happens to you.

You need CORS when a browser on another domain has to read your content. The usual cases:

  • Web fonts served from your CDN domain and used on your main site.
  • fetch() / XMLHttpRequest calls to a JSON or API endpoint behind the property.
  • <canvas> reading images, or JavaScript reading a script's contents.

You do not need it for plain pages, images in <img>, stylesheets, or scripts loaded with <script> — those already work cross-origin without CORS.

Enabling CORS

  1. Open your property and go to the General tab.
  2. In the CORS card, toggle it on.
  3. Choose who may read the responses:
    • Any origin (*) — any website can read them.
    • Only these origins — an explicit list you control.
  4. Adjust the allowed methods and headers if your requests need more than the defaults.
  5. Click Save.

The configuration is stored in the property's general-settings JSON under cors:

{
"cors": {
"enabled": true,
"allowed_origins": ["https://app.example.com"],
"allowed_methods": "GET, HEAD, OPTIONS",
"allowed_headers": "Content-Type",
"expose_headers": null,
"max_age": 3600,
"allow_credentials": false
}
}
FieldTypeDefaultMeaning
enabledbooleanfalseWhether any CORS header is sent at all.
allowed_originsstring[][]["*"] for any origin, or an explicit list. Enabling with an empty list sends nothing.
allowed_methodsstringGET, HEAD, OPTIONSSent as Access-Control-Allow-Methods.
allowed_headersstringContent-TypeRequest headers the browser may send.
expose_headersstring | nullnullResponse headers the page is allowed to read, beyond the safelisted ones.
max_ageint3600How long (seconds) the browser may cache the preflight result.
allow_credentialsbooleanfalseAllow cookies and auth headers. Only valid with an explicit origin list.

Any origin vs. an explicit list

Any origin (*)Explicit list
Header sentAccess-Control-Allow-Origin: *The requesting origin, reflected back
CredentialsNever — browsers refuse them with *Optional
Sent when there is no Origin headerYesNo
Best forPublic assets: fonts, open data, public mediaAnything tied to a session or a known set of sites

With an explicit list the edge compares the browser's Origin header against your entries and reflects it back only on a match. A request from an origin that is not listed simply gets no CORS header, and the browser blocks the read — which is exactly the intended outcome.

Write origins the way the browser sends them

An origin is scheme + host + optional port, and nothing else: https://app.example.com or http://localhost:3000. No trailing slash, no path. The browser never sends one, and the edge compares the value literally — https://app.example.com/ would never match. The panel normalises what you type and the API rejects malformed entries when you save.

Credentials cannot be combined with *

If your requests carry cookies or Authorization headers (credentials: 'include'), you must list the origins explicitly. Browsers reject Access-Control-Allow-Credentials whenever Access-Control-Allow-Origin is * — the combination is refused when you save it, because it would silently fail in every browser.

* also cannot be mixed with specific origins in the same list. Use either one or the other.

Preflight requests

Before a "non-simple" cross-origin request — a PUT, a DELETE, or anything with a custom header — the browser first sends an OPTIONS request to ask permission.

Paradarum adds your CORS headers to that response, but it does not answer the preflight itself: the OPTIONS request is forwarded to your origin like any other. If your origin replies to OPTIONS with 405 Method Not Allowed, the preflight fails and the browser blocks the real request, no matter how CORS is configured here.

Make sure your origin answers OPTIONS (a 204 with no body is enough), or keep to simple requests — GET, HEAD, and POST with a standard content type — which need no preflight.

Interaction with header rules

CORS on the General tab is a property-wide default, and it never overwrites a more specific decision:

  • If your origin already sends Access-Control-Allow-Origin, that value is passed through untouched.
  • If a header rule sets the header for a path, the rule wins.

That ordering is what makes Paradarum Live work without any of this: a live stream's backing property gets a system header rule that sets Access-Control-Allow-Origin: * for the HLS manifest and segments, so browser players work out of the box whether or not the CORS card is on. See playback and caching.

This default changed in August 2026

Properties used to be served with Access-Control-Allow-Origin: * on every response, regardless of configuration and with no way to turn it off. That blanket default is gone — CORS is now off unless you enable it.

If a font stopped loading or a fetch() started failing after that change, this page is where you switch it back on. For fonts, Any origin is normally what you want.

Troubleshooting

SymptomLikely cause
No 'Access-Control-Allow-Origin' header is presentCORS is off, or the requesting origin is not in your list.
Works in curl, fails in the browserExpected — curl ignores CORS. Check the response headers, not the status code.
Origin listed but still blockedA trailing slash, a missing https://, or a port mismatch. The match is literal.
Credentials ignored, cookies not sentYou are using *. Switch to an explicit list and enable Allow credentials.
Preflight OPTIONS returns 405Your origin does not answer OPTIONS. See Preflight requests.
Fonts fail only on some pagesThe font is loaded cross-origin from those pages. Enable CORS, or serve the font from the same host.

Remember that edge configuration is refreshed on a short interval, so give a change a couple of minutes before testing — and test with a hard reload, since the browser caches preflight results for max_age seconds.