🏠 back to Observable

Sudden CORS errors

Recently, I’m getting CORS errors on r = d3.json("https://data.rivm.nl/covid-19/COVID-19_reproductiegetal.json"). I haven’t changed the notebook and I can access the data by just browsing the URL.

Any clues? Is it Observable runtime? Safari? macOS? iPadOS? Firefox? Chrome? Me?

Notebooks in question:

On macOS macOS 11.6 (20G165):

  • Firefox 94.0.1: RuntimeError: NetworkError when attempting to fetch resource.
  • Chrome 95.0.4638.69: RuntimeError: Failed to fetch
  • Safari 15.0: RuntimeError: Load failed
    On iPadOS 15.0.2:
  • Safari: RuntimeError: Origin https://martien.static.observableusercontent.com is not allowed by Access-Control-Allow-Origin.

Ha! It disappears when I Safari » Develop » Disable Cross-Origin Restrictions.

Also, the retrieved header says: Referrer-Policy: strict-origin-when-cross-origin.

New CORS security on the server and/or browser? Being able to reach it directly would be a single-origin request, I think. Solutions = your own proxy or sneaking a ride:

This ain’t over yet.

RIVM replied: “probably destination has a lower security level than that being used for RIVM’s open data”.

Will investigate further Thu/Fri. Had no time on Wed/Thu.

You get work around it using a CORS proxy COVID-19 Netherlands Reproduction Number Tutorial / Tom Larkworthy / Observable

The issue is you have to manually allow-list API access to browsers through headers. If they do not do that the browser will not connect. So either 1. they add the headers, or 2. you access the data through a proxy that does have the right headers

1 Like

Yes, I understand and think similar. I just asked RIVM to add Access-Control-Allow-Origin: * to their headers.

Thanks Aaron! Will be my fallback scenario if RIVM keeps sending unusable headers.


An easy and free way to get a proxy, is using Cloudflare Workers and their example here: https://developers.cloudflare.com/workers/examples/cors-header-proxy.

In the example script, they have a line like this:
response.headers.set("Access-Control-Allow-Origin", url.origin)

To make it work regardless of how how requests are sent, change it to:
response.headers.set("Access-Control-Allow-Origin", “*”)

You then get a URL for the worker, and need to add your desired API endpoint as URL encoded apiurl query param: https://cloudflare-worker-url.dev?apiurl=${escape(‘https://your-api.com’)}

1 Like

Thanks Martin! I’m still waiting on a response from RIVM. Will pursue the proxy solution if RIVM takes too long.

Have a nice weekend.