---
title: Configure CORS
description: Set up Cross-Origin Resource Sharing (CORS) policies on R2 buckets for browser access.
image: https://developers.cloudflare.com/dev-products-preview.png
---

> Documentation Index  
> Fetch the complete documentation index at: https://developers.cloudflare.com/r2/llms.txt  
> Use this file to discover all available pages before exploring further.

[Skip to content](#%5Ftop) 

# Configure CORS

[Cross-Origin Resource Sharing (CORS) ↗](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) is a standardized method that prevents domain X from accessing the resources of domain Y. It does so by using special headers in HTTP responses from domain Y, that allow your browser to verify that domain Y permits domain X to access these resources.

While CORS can help protect your data from malicious websites, CORS is also used to interact with objects in your bucket and configure policies on your bucket.

CORS is used when you interact with a bucket from a web browser, and you have two options:

**[Set a bucket to public:](#use-cors-with-a-public-bucket)** This option makes your bucket accessible on the Internet as read-only, which means anyone can request and load objects from your bucket in their browser or anywhere else. This option is ideal if your bucket contains images used in a public blog.

**[Presigned URLs:](#use-cors-with-a-presigned-url)** Allows anyone with access to the unique URL to perform specific actions on your bucket.

## Prerequisites

Before you configure CORS, you must have:

* An R2 bucket with at least one object. If you need to create a bucket, refer to [Create a public bucket](https://developers.cloudflare.com/r2/buckets/public-buckets/).
* A domain you can use to access the object. This can also be a `localhost`.
* (Optional) Access keys. An access key is only required when creating a presigned URL.

## Use CORS with a public bucket

[To use CORS with a public bucket](https://developers.cloudflare.com/r2/buckets/public-buckets/), ensure your bucket is set to allow public access.

Next, [add a CORS policy](#add-cors-policies-from-the-dashboard) to your bucket to allow the file to be shared.

## Use CORS with a presigned URL

[Presigned URLs](https://developers.cloudflare.com/r2/api/s3/presigned-urls/) allow temporary access to perform specific actions on your bucket without exposing your credentials. While presigned URLs handle authentication, you still need to configure CORS when making requests from a browser.

When a browser makes a request to a presigned URL on a different origin, the browser enforces CORS. Without a CORS policy, browser-based uploads and downloads using presigned URLs will fail, even though the presigned URL itself is valid.

To enable browser-based access with presigned URLs:

1. [Add a CORS policy](#add-cors-policies-from-the-dashboard) to your bucket that allows requests from your application's origin.
2. Set `AllowedMethods` to match the operations your presigned URLs perform, use `GET`, `PUT`, `HEAD`, and/or `DELETE`.
3. Set `AllowedHeaders` to include any headers the client will send when using the presigned URL, such as headers for content type, checksums, caching, or custom metadata.
4. (Optional) Set `ExposeHeaders` to allow your JavaScript to read response headers like `ETag`, which contains the object's hash and is useful for verifying uploads.
5. (Optional) Set `MaxAgeSeconds` to cache the preflight response and reduce the number of preflight requests the browser makes.

The following example allows browser-based uploads from `https://example.com` with a `Content-Type` header:

```

[

  {

    "AllowedOrigins": ["https://example.com"],

    "AllowedMethods": ["PUT"],

    "AllowedHeaders": ["Content-Type"],

    "ExposeHeaders": ["ETag"],

    "MaxAgeSeconds": 3600

  }

]


```

## Use CORS with a custom domain

[Custom domains](https://developers.cloudflare.com/r2/buckets/public-buckets/#custom-domains) connected to an R2 bucket with a CORS policy automatically return CORS response headers for [cross-origin requests ↗](https://fetch.spec.whatwg.org/#http-cors-protocol).

Cross-origin requests must include a valid `Origin` request header, for example, `Origin: https://example.com`. If you are testing directly or using a command-line tool such as `curl`, you will not see CORS `Access-Control-*` response headers unless the `Origin` request header is included in the request.

Caching and CORS headers

If you set a CORS policy on a bucket that is already serving traffic using a custom domain, any existing cached assets will not reflect the CORS response headers until they are refreshed in cache. Use [Cache Purge](https://developers.cloudflare.com/cache/how-to/purge-cache/) to purge the cache for that hostname after making any CORS policy related changes.

## Add CORS policies from the dashboard

1. In the Cloudflare dashboard, go to the **R2 object storage** page.  
[ Go to **Overview** ](https://dash.cloudflare.com/?to=/:account/r2/overview)
2. Locate and select your bucket from the list.
3. Select **Settings**.
4. Under **CORS Policy**, select **Add CORS policy**.
5. From the **JSON** tab, manually enter or copy and paste your policy into the text box.
6. When you are done, select **Save**.

Your policy displays on the **Settings** page for your bucket.

## Add CORS policies via Wrangler CLI

You can configure CORS rules using the [Wrangler CLI](https://developers.cloudflare.com/r2/reference/wrangler-commands/).

1. Create a JSON file with your CORS configuration:

cors.json

```

{

  "rules": [

    {

      "allowed": {

        "origins": ["https://example.com"],

        "methods": ["GET"]

      }

    }

  ]

}


```

1. Apply the CORS policy to your bucket:

Terminal window

```

npx wrangler r2 bucket cors set <BUCKET_NAME> --file cors.json


```

1. Verify the CORS policy was applied:

Terminal window

```

npx wrangler r2 bucket cors list <BUCKET_NAME>


```

## Response headers

The following fields in an R2 CORS policy map to HTTP response headers. These response headers are only returned when the incoming HTTP request is a valid CORS request.

| Field Name     | Description                                                                                                                                                                                                                                                                                                                                                                   | Example                                                                                                                                                                                                                                                       |
| -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| AllowedOrigins | Specifies the value for the Access-Control-Allow-Origin header R2 sets when requesting objects in a bucket from a browser.                                                                                                                                                                                                                                                    | If a website at www.test.com needs to access resources (e.g. fonts, scripts) on a [custom domain](https://developers.cloudflare.com/r2/buckets/public-buckets/#custom-domains) of static.example.com, you would set https://www.test.com as an AllowedOrigin. |
| AllowedMethods | Specifies the value for the Access-Control-Allow-Methods header R2 sets when requesting objects in a bucket from a browser.                                                                                                                                                                                                                                                   | GET, POST, PUT                                                                                                                                                                                                                                                |
| AllowedHeaders | Specifies the value for the Access-Control-Allow-Headers header R2 sets when requesting objects in this bucket from a browser.Cross-origin requests that include custom headers (e.g. x-user-id) should specify these headers as AllowedHeaders.                                                                                                                              | x-requested-by, User-Agent                                                                                                                                                                                                                                    |
| ExposeHeaders  | Specifies the headers that can be exposed back, and accessed by, the JavaScript making the cross-origin request. If you need to access headers beyond the [safelisted response headers ↗](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Access-Control-Expose-Headers#examples), such as Content-Encoding or cf-cache-status, you must specify it here. | Content-Encoding, cf-cache-status, Date                                                                                                                                                                                                                       |
| MaxAgeSeconds  | Specifies the amount of time (in seconds) browsers are allowed to cache CORS preflight responses. Browsers may limit this to 2 hours or less, even if the maximum value (86400) is specified.                                                                                                                                                                                 | 3600                                                                                                                                                                                                                                                          |

## Example

This example shows a CORS policy added for a bucket that contains the `Roboto-Light.ttf` object, which is a font file.

The `AllowedOrigins` specify the web server being used, and `localhost:3000` is the hostname where the web server is running. The `AllowedMethods` specify that only `GET` requests are allowed and can read objects in your bucket.

```

[

  {

    "AllowedOrigins": ["http://localhost:3000"],

    "AllowedMethods": ["GET"]

  }

]


```

In general, a good strategy for making sure you have set the correct CORS rules is to look at the network request that is being blocked by your browser.

* Make sure the rule's `AllowedOrigins` includes the origin where the request is being made from. (like `http://localhost:3000` or `https://yourdomain.com`)
* Make sure the rule's `AllowedMethods` includes the blocked request's method.
* Make sure the rule's `AllowedHeaders` includes the blocked request's headers.

Also note that CORS rule propagation can, in rare cases, take up to 30 seconds.

## Common Issues

* Only a cross-origin request will include CORS response headers.  
   * A cross-origin request is identified by the presence of an `Origin` HTTP request header, with the value of the `Origin` representing a valid, allowed origin as defined by the `AllowedOrigins` field of your CORS policy.  
   * A request without an `Origin` HTTP request header will _not_ return any CORS response headers. Origin values must match exactly.
* The value(s) for `AllowedOrigins` in your CORS policy must be a valid [HTTP Origin header value ↗](https://fetch.spec.whatwg.org/#origin-header). A valid `Origin` header does _not_ include a path component and must only be comprised of a `scheme://host[:port]` (where port is optional).  
   * Valid `AllowedOrigins` value: `https://static.example.com` \- includes the scheme and host. A port is optional and implied by the scheme.  
   * Invalid `AllowedOrigins` value: `https://static.example.com/` or `https://static.example.com/fonts/Calibri.woff2` \- incorrectly includes the path component.
* If you need to access specific header values via JavaScript on the origin page, such as when using a video player, ensure you set `Access-Control-Expose-Headers` correctly and include the headers your JavaScript needs access to, such as `Content-Length`.

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/r2/","name":"R2"}},{"@type":"ListItem","position":3,"item":{"@id":"/r2/buckets/","name":"Buckets"}},{"@type":"ListItem","position":4,"item":{"@id":"/r2/buckets/cors/","name":"Configure CORS"}}]}
```
