Skip to content
Cloudflare Docs

boto3

You must generate an Access Key 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 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 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 on your bucket to control which origins can upload files. Configure CORS via the Cloudflare dashboard 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)