R2 Storage

Instead of receiving the screenshot as binary data, you can upload it directly to your Cloudflare R2 bucket. The API returns a JSON response with the public URL of the uploaded file.

Setup

  1. Create a Cloudflare R2 bucket in your Cloudflare dashboard
  2. Generate an R2 API token with read/write permissions for the bucket
  3. Go to Storage Settings in the ShotOne dashboard
  4. Click Add Credential and enter your R2 details:
    • Account ID — Your Cloudflare account ID
    • Access Key ID — From your R2 API token
    • Secret Access Key — From your R2 API token
    • Bucket Name — Your R2 bucket name
    • Public URL — Your bucket's public domain (optional, for custom URLs)
  5. Click Test Connection to verify it works

Your credentials are encrypted with AES-256-GCM before storage. Only the ShotOne API can decrypt them to upload screenshots.

Self-hosting note: If you run your own gateway instance, R2 storage requires DASHBOARD_INTERNAL_URL and INTERNAL_API_KEY to be configured in the gateway environment so it can fetch your encrypted R2 credentials from the dashboard API.

Usage

Add storage: "r2" to your request. If you have multiple R2 credentials, specify which one to use with r2CredentialId.

Using Default Credential

curl -X POST "https://api.shotone.io/screenshot" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com",
    "storage": "r2"
  }'

Using a Specific Credential

curl -X POST "https://api.shotone.io/screenshot" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com",
    "format": "webp",
    "quality": 90,
    "storage": "r2",
    "r2CredentialId": "clxxx..."
  }'

Response

When storage: "r2" is set, the response is JSON instead of binary:

{
  "success": true,
  "storage": "r2",
  "url": "https://your-bucket.r2.dev/screenshots/20250130-143022-a1b2c3d4.webp",
  "bucket": "your-bucket",
  "key": "screenshots/20250130-143022-a1b2c3d4.webp"
}
Field Type Description
success boolean Always true on success
storage string Always "r2"
url string Public URL to access the screenshot
bucket string R2 bucket name
key string Object key in the bucket

Code Examples

Node.js

const response = await fetch('https://api.shotone.io/screenshot', {
  method: 'POST',
  headers: {
    'X-API-Key': process.env.SHOTONE_API_KEY,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    url: 'https://example.com',
    storage: 'r2',
    r2CredentialId: 'clxxx...',
  }),
});

const data = await response.json();
console.log(data.url); // Public URL of the screenshot

Python

import requests
import os

response = requests.post(
    'https://api.shotone.io/screenshot',
    headers={
        'X-API-Key': os.environ['SHOTONE_API_KEY'],
        'Content-Type': 'application/json',
    },
    json={
        'url': 'https://example.com',
        'storage': 'r2',
        'r2CredentialId': 'clxxx...',
    },
)

data = response.json()
print(data['url'])  # Public URL of the screenshot

File Naming

Screenshots are stored with auto-generated keys in the format:

screenshots/{YYYYMMDD-HHMMSS}-{random-hex}.{format}

For example: screenshots/20250130-143022-a1b2c3d4e5f6g7h8.png

Errors

Status Error Cause
400 R2 storage is not configured on this gateway R2 support is not enabled on the server
400 failed to get R2 credentials Credential not found, not active, or doesn't belong to the user
502 failed to upload to R2 Upload to R2 failed (check credentials and bucket permissions)