[Support Guide] Handling CORS on Netlify

CORS stands for Cross Origin Resource Sharing. It is a HTTP header that tells the browsers how to handle a request from a certain origin to for an asset on your website. You can read more about it on Cross-Origin Resource Sharing (CORS) - HTTP | MDN (mozilla.org).

By definition, an origin consists of scheme, domain and port. For example:

https://www.example.com/
  • https:// is the scheme
  • www.example.com is the domain
  • 443 is the port (HTTPS is served on port 443 by default).

Any difference in the above 3 between the site that’s requesting an asset and the site that’s serving that asset would be blocked by CORS errors by default. You can read more about origin on MDN as well Origin - MDN Web Docs Glossary: Definitions of Web-related terms | MDN (mozilla.org).

Here’s how to handle CORS errors on Netlify:

1. Make sure it’s a CORS error

If some of your site’s assets aren’t loading and you see an error like this (the URLs would be different than the ones in the screenshot) in your devtools:

image

Then yes, you’re affected by CORS errors. Different browsers could show a slightly different error, but in the end, they would say something about being blocked by CORS policy.

2. Where to fix it?

Often times you’d think this is a Netlify issue because the error appears on your Netlify site. But, in a lot of cases, the issue is not on Netlify’s end. It’s important to understand that CORS needs to be configured on the server that’s serving the request. So if Netlify is not the server that’s serving the address you’re requesting, this is something you need to fix on the server serving the request. However, you can still fix this from Netlify’s end, as discussed further in this guide.

3. How to fix it?

There are various ways to fix this depending on the setup. The following document contains a list of most common setups that we’ve seen along with their solutions.

3.1: Assets not hosted on Netlify:

Continuing the discussion from point 2 above, where you have assets and APIs hosted on a different server than your Netlify-hosted frontend, you can solve such issues by using Netlify Rewrites. Please note, this method should only be used when you don’t control the other server or cannot add CORS headers there. If you can, the real solution would be to add the correct headers there.

Consider this situation:

  • You have a Netlify-hosted site.
  • That site is trying to connect to an API or an asset hosted on https://www.example.com/ which is not hosted by Netlify.

If this situation matches yours, you can add a netlify.toml in your project with the following data:

[[redirects]]
  force = true
  from = "/scripts/x.js"
  status = 200
  to = "https://www.example.com/scripts/x.js"

Now, in your frontend, you can make a request like: /scripts/x.js and Netlify will proxy that to https://www.example.com/scripts/x.js and return the response. Note that, the exact redirect that you’d need to setup would differ based on your requirement. Please refer to Netlify Rewrites documentation on various options and ways you can send such a request.

The reason this works to handle CORS is because, when you make a request like /external/api/, browsers treat it as a same-origin request and allow it.

3.2: Assets hosted on Netlify:

Consider this situation:

  • You have a site on Netlify (Site A)
  • You have another site (could be on Netlify or hosted externally) (Site B)
  • You’re trying to access assets and APIs from Site A on Site B.

It this matches your setup, there are mainly 3 ways to resolve the CORS errors depending on your setup.

3.2.1: For static assets:

Netlify Headers can be used on any static asset of your site. If you’re having troubles loading CSS / JS / images from your Netlify site on the other site, this is most likely what you’re looking for. Note that, for this to work, the asset must be static - by static we mean, it must exist in your publish directory at the time of deployment. If this matches your setup, you can add a netlify.toml to your project with the following data:

[[headers]]
  for = "/*" # you can configure the correct paths here
  [headers.values]
    access-control-allow-origin = "*" # see a list of allowed values here: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin

Note that, Netlify Headers won’t allow you to dynamically set. So if you wish to allow multiple origins based on the origin that made the request, you’d have to use one of the following ways.

3.2.2: For dynamic assets and Netlify Functions:

A variety of frameworks utilize Netlify Functions and Edge Functions to achieve some functionality like Server Side Rendering, Incremental Static Regeneration, API routes, etc. If you’re not using any framework, you could still be using Netlify Functions or Edge Functions directly. In such a situation, Netlify Headers won’t help. Instead, you’d have to set the correct headers from within the Function or the Edge Function. Depending on your setup, the correct way to do this would differ. Some frameworks would offer a built-in way to set custom headers on responses. If you’re writing Functions or Edge Functions yourself, you’d have to include the correct headers accordingly in your code.

Note that, Netlify Background Functions cannot send a respose to the client. This includes being unable to respond with any headers. Thus, in situations where you need to make a request to Netlify Background Functions while adding CORS headers, you can:

  1. Create a regular Netlify Function and send your request to that
  2. From within this Function, make a request to the Background Function
  3. From within the same Function, return headers back to the client

OR you can simply use brute-force using Netlify Edge Functions as described below.

3.2.3 Brute-force using Netlify Edge Functions

If none of these methods work, there’s a way to force adding the correct CORS headers using Netlify Edge Functions. Edge Functions will run on all the paths you configure them to, and can add the required headers regardless of the asset at that URL being static or dynamic. So something like the following could work:

import type {Config, Context} from '@netlify/edge-functions'
export default async (request : Request, context : Context) => {
  const response = await context.next()
  return new Response(response.body, {
    headers: {
       'access-control-allow-origin': '*'
    }
  })
}
export const config : Config = {
  path: '/*'
}

We hope this guide helps you understand how to solve CORS issues on Netlify. If after going through all this, you have any further questions, feel free to create a new thread and include relevant details and reproduction steps.