GuidesARCHITECTURE

How to bypass CORS

You cannot turn CORS off from page code because the browser enforces it, so you bypass it by sending the request through something that returns Access-Control-Allow-Origin. For public data read with GET, put https://proxy.cors.dev/ in front of the URL with no signup and no API key. Keys, cookies and private data belong on your own backend.

Every way around CORS

The options differ in what they can reach and whether they work for your visitors or only on your own machine. The table compares them.

Ways around a CORS error
OptionWhere it worksUse it forCost
CORS headers on your APIEvery browser, in development and productionAPIs you runA configuration change
Your own backend or serverless functionEvery browser, in development and productionAPIs that need a key, cookies or private dataA service you deploy and run
Dev-server proxyOnly while the dev server runsCalling your API during developmentNone
Browser flag or CORS extensionOnly in your own browserQuick tests on your machineNone
cors.dev free tierEvery browser, in development and productionPublic data with GET and HEADFree, no signup
cors.dev ProEvery browser, in development and productionWrite methods and custom headers on hosts you enable$5 per month for 500,000 requests

Public APIs: use a CORS proxy

When the data is public and the API sends no CORS headers, put https://proxy.cors.dev/ in front of the URL. For example, the Steam news API on api.steampowered.com sends no CORS headers. The proxy fetches the URL server-side and returns the response with Access-Control-Allow-Origin set to your page's origin. The free tier supports GET and HEAD for any public HTTPS host, returning JSON, XML, HTML, CSV and other text responses up to 1 MiB with a 10-second deadline, fair-use rate limits, no signup and no API key.

Bypass CORS for a public API with a proxy prefix
const target = 'https://api.steampowered.com/ISteamNews/GetNewsForApp/v2/?appid=440&count=3';

const response = await fetch(`https://proxy.cors.dev/${target}`, { credentials: 'omit' });
if (!response.ok) {
  throw new Error(`HTTP ${response.status}: ${response.headers.get('X-Cors-Error') ?? 'upstream error'}`);
}

const { appnews } = await response.json();
console.log(appnews.newsitems.map((item) => item.title));

Managed access on Pro adds POST, PUT, PATCH and DELETE on hosts you enable on your Connection, custom headers and explicit Authorization, 1 MiB request bodies and 6 MiB responses. Pro costs $5/month for 500,000 requests. The trial includes 1,000 requests over 7 days with no card: pricing.

APIs with a secret key: your own backend

If the API needs a secret key, any key in browser code is visible to every visitor. Put a small backend or serverless function in between to hold the key, call the API and return the data with your own CORS header. The Cloudflare Worker below reads the key from env.API_TOKEN and allows only https://app.example.com. For more detail, see Cloudflare Workers CORS and CORS proxy vs your own backend.

Your own backend: a Cloudflare Worker that keeps the token server-side
export default {
  async fetch(request, env) {
    const upstream = await fetch('https://api.example.com/v1/reports', {
      headers: { Authorization: `Bearer ${env.API_TOKEN}` },
    });

    const response = new Response(upstream.body, upstream);
    response.headers.set('Access-Control-Allow-Origin', 'https://app.example.com');
    return response;
  },
};

Your own API: send the headers

If you run the API, CORS is a configuration change rather than something to bypass. Return Access-Control-Allow-Origin with your site's origin. Answer preflight OPTIONS requests with Access-Control-Allow-Methods and Access-Control-Allow-Headers. Step by step: fix CORS errors, Access-Control-Allow-Origin, preflight requests.

Works only on your machine

  • A dev-server proxy (Vite server.proxy, Angular proxyConfig) forwards /api to your API while you develop, and production builds do not include it: CORS error on localhost.
  • Chrome started with web security turned off, or a CORS extension, only changes your own browser: disable CORS in Chrome, CORS Chrome extensions.
  • Postman, curl and server code never enforce CORS, so a call that works there says nothing about the browser: Postman vs the browser.

What does not work

  • mode: 'no-cors' sends the request but returns an opaque response with status 0 and an empty body: no-cors and opaque responses.
  • Setting Access-Control-Allow-Origin in your request headers does not work: the browser checks that header on the response, and the extra request header also triggers a preflight.
  • JSONP loads the response as a <script>: it only works when the API supports a callback parameter, only for GET, and it runs whatever code the API returns.

Keep private data off public proxies

A public CORS proxy sees every request and response that passes through it, so use it for public data only. The cors.dev free tier omits credentials: requests with Authorization, cookies or custom headers are rejected, and so are query parameters with credential names such as key, token or api_key. Private data and secret keys belong on your own backend.

Good questions.

Can you bypass CORS with JavaScript alone?

No: the browser enforces CORS and page code cannot switch it off. Route the request through a server or proxy that sends Access-Control-Allow-Origin.

Is it safe to use a CORS proxy?

For public data, yes. The proxy operator can see all traffic, so never send secret keys, cookies or private data through a public proxy.

Does a CORS proxy work for POST requests?

The cors.dev free tier supports GET and HEAD only; a POST returns HTTP 405 with X-Cors-Error: method_not_allowed. Managed access on Pro supports POST, PUT, PATCH and DELETE.

Why doesn't adding Access-Control-Allow-Origin to my fetch request work?

It is a response header: the browser only trusts it when the server sends it. As a request header it does nothing except trigger a preflight.

How do I bypass CORS in Chrome for testing?

Start Chrome with web security turned off in a separate profile, or use a CORS extension. Both affect only your browser, never your visitors: disable CORS in Chrome.