Link Search Menu Expand Document

Upload images to Cloudflare R2

Send every rendered image or PDF to a Cloudflare R2 bucket you control.


HTML/CSS to Image connects to Cloudflare R2 through its S3-compatible API. You provide an R2 access key, secret, Cloudflare account ID, and the bucket’s data jurisdiction.

Plan availability

Storage destinations are available on the 10,000 images/month plan or higher. If you’d like to try this on a different plan, email support@htmlcsstoimage.com.

Before you begin

You need:

  • An existing R2 bucket.
  • The Cloudflare account ID that owns it.
  • The bucket’s data jurisdiction, if it was created with one.
  • An optional key prefix, such as hcti-renders.

Create R2 S3 credentials

In the Cloudflare dashboard, open R2 Object Storage, select Manage API Tokens, and create an account or user API token.

  1. Choose Object Read & Write permission.
  2. Scope the token to the destination bucket when possible.
  3. Create the token.
  4. Copy the Access Key ID and Secret Access Key. Cloudflare shows the secret only once.

Read and write access lets HCTI upload renders and reload an original for a later resize, crop, or format conversion when Disable HCTI Storage is selected. HCTI uses delete access only to clean up connection-test objects; it does not delete rendered images from R2.

Add Cloudflare R2 to HCTI

Open the Storage Destinations dashboard, click Add storage destination, and enter:

HCTI field Cloudflare value
Provider Cloudflare R2
Bucket Existing R2 bucket name
Key prefix Optional folder-like prefix, without leading or trailing slashes
Account ID Cloudflare account ID
Access key ID R2 token’s Access Key ID
Secret access key R2 token’s Secret Access Key
Data jurisdiction The jurisdiction used when the bucket was created

Choose the R2 data jurisdiction

The setting determines which R2 endpoint HCTI uses:

Dashboard option Endpoint Use when
Default <account-id>.r2.cloudflarestorage.com The bucket has no jurisdiction restriction. This is also the correct option for a bucket with only a location hint.
European Union <account-id>.eu.r2.cloudflarestorage.com The bucket was created in the European Union jurisdiction.
FedRAMP <account-id>.fedramp.r2.cloudflarestorage.com The bucket was created in the FedRAMP jurisdiction.

The wrong jurisdiction points HCTI at an endpoint that cannot access the bucket. If you change this setting later, run Test connection again before saving.

Test and save the destination

  1. Click Test connection.
  2. Enable and save the destination after the test succeeds.
  3. Copy the destination id.

The test writes a small object under <key-prefix>/.hcti/connection-tests/. Cleanup is best-effort and does not determine whether the connection passes.

Upload an HCTI image to R2

Pass the destination ID as storage_destination_id when you create an image:

curl -X POST https://hcti.io/v1/image \
  -u 'user-id:api-key' \
  -H 'Content-Type: application/json' \
  -d '{
        "url": "https://example.com",
        "storage_destination_id": "your-storage-destination-id"
      }'

Rendering is lazy. With normal HCTI storage enabled, request the returned image URL to render the image and write both copies. With Disable HCTI Storage selected, send an authenticated PUT request to the returned /v1/store/... URL.

The base object is stored as <key-prefix>/<image-id>.png, or .pdf when the request uses pdf_options. R2 bucket access remains under your control; HCTI does not make the object public.

Troubleshooting Cloudflare R2 uploads

  • The connection test cannot find the bucket — Confirm the bucket name, account ID, and data jurisdiction.
  • Authentication fails — Use the S3 Access Key ID and Secret Access Key generated for R2, not a general Cloudflare API token string.
  • The secret is unavailable — Create a new R2 API token; Cloudflare does not show the secret again after creation.
  • A later transformation fails with HCTI Storage disabled — Confirm the token has object read access as well as write access.
  • The connection worked before the jurisdiction changed — Test again; changing the jurisdiction changes the R2 endpoint.

Cloudflare documents creating R2 S3 API credentials and jurisdiction-specific R2 endpoints.

Next: use your storage destination

Continue to the Storage Destinations guide for templates, batches, object storage behavior, and the complete PUT /v1/store response.


Need help?

Talk to a human. Please email us support@htmlcsstoimage.com with any questions and we’ll gladly help you get started.


Back to top

Built with extensive integration tests and serious care for developer happiness.
© 2018-2026 Code Happy, LLC.

Page last modified: Aug 27 2026 at 04:31 PM.

Edit this page on GitHub.