---
title: boto3
description: Configure Python boto3 to work with Cloudflare R2 via the S3-compatible API.
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) 

# boto3

**Last reviewed:**  almost 4 years ago 

You must [generate an Access Key](https://developers.cloudflare.com/r2/api/tokens/) before getting started. All examples will utilize `access_key_id` and `access_key_secret` variables which represent the **Access Key ID** and **Secret Access Key** values you generated.

  
You must configure [boto3 ↗](https://boto3.amazonaws.com/v1/documentation/api/latest/index.html) to use a preconstructed `endpoint_url` value. This can be done through any `boto3` usage that accepts connection arguments; for example:

Python

```

import boto3


s3 = boto3.resource('s3',

  # Provide your Cloudflare account ID

  endpoint_url = 'https://<ACCOUNT_ID>.r2.cloudflarestorage.com',

  # Retrieve your S3 API credentials for your R2 bucket via API tokens (see: https://developers.cloudflare.com/r2/api/tokens)

  aws_access_key_id = '<ACCESS_KEY_ID>',

  aws_secret_access_key = '<SECRET_ACCESS_KEY>'

)


```

You may, however, omit the `aws_access_key_id` and `aws_secret_access_key ` arguments and allow `boto3` to rely on the `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` [environment variables ↗](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/configuration.html#using-environment-variables) instead.

An example script may look like the following:

Python

```

import boto3


s3 = boto3.client(

    service_name="s3",

    # Provide your Cloudflare account ID

    endpoint_url='https://<ACCOUNT_ID>.r2.cloudflarestorage.com',

    # Retrieve your S3 API credentials for your R2 bucket via API tokens (see: https://developers.cloudflare.com/r2/api/tokens)

    aws_access_key_id='<ACCESS_KEY_ID>',

    aws_secret_access_key='<SECRET_ACCESS_KEY>',

    region_name="auto", # Required by SDK but not used by R2

)


# Get object information

object_information = s3.head_object(Bucket='my-bucket', Key='dog.png')


# Upload/Update single file

s3.upload_fileobj(io.BytesIO(file_content), 'my-bucket', 'dog.png')


# Delete object

s3.delete_object(Bucket='my-bucket', Key='dog.png')


```

## Generate presigned URLs

You can also generate presigned links that can be used to share public read or write access to a bucket temporarily.

Python

```

import boto3


s3 = boto3.client(

    service_name="s3",

    # Provide your Cloudflare account ID

    endpoint_url='https://<ACCOUNT_ID>.r2.cloudflarestorage.com',

    # Retrieve your S3 API credentials for your R2 bucket via API tokens (see: https://developers.cloudflare.com/r2/api/tokens)

    aws_access_key_id='<ACCESS_KEY_ID>',

    aws_secret_access_key='<SECRET_ACCESS_KEY>',

    region_name="auto", # Required by SDK but not used by R2

)


# Generate presigned URL for reading (GET)

# The ExpiresIn parameter determines how long the presigned link is valid (in seconds)

get_url = s3.generate_presigned_url(

    'get_object',

    Params={'Bucket': 'my-bucket', 'Key': 'dog.png'},

    ExpiresIn=3600  # Valid for 1 hour

)


print(get_url)


# Generate presigned URL for writing (PUT)

# Specify ContentType to restrict uploads to a specific file type

put_url = s3.generate_presigned_url(

    'put_object',

    Params={

        'Bucket': 'my-bucket',

        'Key': 'dog.png',

        'ContentType': 'image/png'

    },

    ExpiresIn=3600

)


print(put_url)


```

```

https://<ACCOUNT_ID>.r2.cloudflarestorage.com/my-bucket/dog.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=...&X-Amz-Date=<timestamp>&X-Amz-Expires=3600&X-Amz-SignedHeaders=host&X-Amz-Signature=<signature>

https://<ACCOUNT_ID>.r2.cloudflarestorage.com/my-bucket/dog.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=...&X-Amz-Date=<timestamp>&X-Amz-Expires=3600&X-Amz-SignedHeaders=content-type%3Bhost&X-Amz-Signature=<signature>


```

You can use the link generated by the `put_object` example to upload to the specified bucket and key, until the presigned link expires. When using a presigned URL with `ContentType`, the client must include a matching `Content-Type` header in the request.

Terminal window

```

curl -X PUT "https://<ACCOUNT_ID>.r2.cloudflarestorage.com/my-bucket/dog.png?X-Amz-Algorithm=..." \

  -H "Content-Type: image/png" \

  --data-binary @dog.png


```

## Restrict uploads with CORS and Content-Type

When generating presigned URLs for uploads, you can limit abuse and misuse by:

1. **Restricting Content-Type**: Specify the allowed content type in the presigned URL parameters. The upload will fail if the client sends a different `Content-Type` header.
2. **Configuring CORS**: Set up [CORS rules](https://developers.cloudflare.com/r2/buckets/cors/#add-cors-policies-from-the-dashboard) on your bucket to control which origins can upload files. Configure CORS via the [Cloudflare dashboard ↗](https://dash.cloudflare.com/?to=/:account/r2/overview) by adding a JSON policy to your bucket settings:

```

[

  {

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

    "AllowedMethods": ["PUT"],

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

    "ExposeHeaders": ["ETag"],

    "MaxAgeSeconds": 3600

  }

]


```

Then generate a presigned URL with a Content-Type restriction:

Python

```

# Generate a presigned URL with Content-Type restriction

# The upload will only succeed if the client sends Content-Type: image/png

put_url = s3.generate_presigned_url(

    'put_object',

    Params={

        'Bucket': 'my-bucket',

        'Key': 'dog.png',

        'ContentType': 'image/png'

    },

    ExpiresIn=3600

)


```

When a client uses this presigned URL, they must:

* Make the request from an allowed origin (enforced by CORS)
* Include the `Content-Type: image/png` header (enforced by the signature)

```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/examples/","name":"Examples"}},{"@type":"ListItem","position":4,"item":{"@id":"/r2/examples/aws/","name":"S3 SDKs"}},{"@type":"ListItem","position":5,"item":{"@id":"/r2/examples/aws/boto3/","name":"boto3"}}]}
```
