Skip to content
HTML/CSS to ImageDocs

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.

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.

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.

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

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.

  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.

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

Terminal window
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.

  • 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.

You can also automate configuration through the Storage destinations API or MCP tools.

Need help?

Talk to a human. Email support@htmlcsstoimage.com and we’ll help you get started.