# Process files from Cloudflare R2

Connect Ittybit to your R2 bucket and process media files directly

Your media files are in Cloudflare R2. Rather than downloading them and re-uploading to Ittybit, connect your R2 bucket and pass `s3://` URLs directly as task input. Ittybit reads from R2 natively -- R2 is S3-compatible, so no special adapter is needed.

## Create an R2 API token

In the Cloudflare dashboard, go to **R2 > Manage R2 API Tokens** and create a token with **Object Read** permission scoped to your bucket. Save the Access Key ID and Secret Access Key.

Your R2 S3-compatible endpoint follows this format:

```
https://<account-id>.r2.cloudflarestorage.com
```

You can find your account ID on the R2 overview page in the Cloudflare dashboard.

## Create a connection in Ittybit

Register your R2 credentials as a named connection. R2 always uses `auto` as the region.

<CodeGroup labels={["CLI", "TypeScript", "Python", "curl"]}>
```bash
ittybit connections add s3 \
  --name my-r2 \
  --endpoint https://<account-id>.r2.cloudflarestorage.com \
  --region auto \
  --access-key-id $R2_ACCESS_KEY_ID \
  --secret-access-key $R2_SECRET_ACCESS_KEY
```

```typescript
const res = await fetch('https://api.ittybit.com/connections', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.ITTYBIT_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    kind: 's3',
    name: 'my-r2',
    endpoint: `https://${CLOUDFLARE_ACCOUNT_ID}.r2.cloudflarestorage.com`,
    region: 'auto',
    access_key_id: process.env.R2_ACCESS_KEY_ID,
    secret_access_key: process.env.R2_SECRET_ACCESS_KEY,
  }),
});
const { data: connection } = await res.json();
// connection.id => "conn_abc123"
```

```python

res = requests.post(
    "https://api.ittybit.com/connections",
    headers={"Authorization": f"Bearer {os.environ['ITTYBIT_API_KEY']}"},
    json={
        "kind": "s3",
        "name": "my-r2",
        "endpoint": f"https://{os.environ['CLOUDFLARE_ACCOUNT_ID']}.r2.cloudflarestorage.com",
        "region": "auto",
        "access_key_id": os.environ["R2_ACCESS_KEY_ID"],
        "secret_access_key": os.environ["R2_SECRET_ACCESS_KEY"],
    },
)
connection = res.json()["data"]
# connection["id"] => "conn_abc123"
```

```bash
curl -X POST https://api.ittybit.com/connections \
  -H "Authorization: Bearer $ITTYBIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "kind": "s3",
    "name": "my-r2",
    "endpoint": "https://<account-id>.r2.cloudflarestorage.com",
    "region": "auto",
    "access_key_id": "'$R2_ACCESS_KEY_ID'",
    "secret_access_key": "'$R2_SECRET_ACCESS_KEY'"
  }'
```

</CodeGroup>

The response includes a `connection_id` (e.g. `conn_abc123`). You will pass this in your task requests so Ittybit knows which credentials to use when reading from R2.

## Process a file from R2

Use the `s3://` URL scheme with your R2 bucket name and object key. Include `connection_id` in options to tell Ittybit which connection to authenticate with.

<CodeGroup labels={["CLI", "TypeScript", "Python", "curl"]}>
```bash
ittybit video \
  -i s3://my-r2-bucket/uploads/video.mov \
  --connection my-r2 \
  --width 1280 \
  --format mp4
```

```typescript
const task = {
  input: 's3://my-r2-bucket/uploads/video.mov',
  kind: 'video',
  options: {
    connection_id: 'conn_abc123',
    width: 1280,
    format: 'mp4',
  },
};

const res = await fetch('https://api.ittybit.com/jobs', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.ITTYBIT_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify(task),
});
const data = await res.json();
```

```python

task = {
    "input": "s3://my-r2-bucket/uploads/video.mov",
    "kind": "video",
    "options": {
        "connection_id": "conn_abc123",
        "width": 1280,
        "format": "mp4",
    },
}

res = requests.post(
    "https://api.ittybit.com/jobs",
    headers={"Authorization": f"Bearer {api_key}"},
    json=task,
)
data = res.json()
```

```bash
TASK='{
  "input": "s3://my-r2-bucket/uploads/video.mov",
  "kind": "video",
  "options": {
    "connection_id": "conn_abc123",
    "width": 1280,
    "format": "mp4"
  }
}'

curl -X POST https://api.ittybit.com/jobs \
  -H "Authorization: Bearer $ITTYBIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d "$TASK"
```

</CodeGroup>

Ittybit uses your R2 credentials to fetch the file, processes it, and delivers the output to the Ittybit CDN by default. To write output back to R2 instead, add an `output` field with an `s3://` URL pointing to your destination bucket.

## See also

- [Process files from S3](/guides/process-files-from-s3) -- general S3-compatible storage setup
- [Write output to S3](/guides/write-output-to-s3) -- deliver processed files back to R2 or S3
- [Media processing with Cloudflare Workers, R2, and Ittybit](/guides/media-processing-with-cloudflare-workers-and-r2) -- full pipeline with Workers and D1
- [Replace Cloudflare Stream with Ittybit and R2](/guides/replace-cloudflare-stream-with-r2) -- migrate from Stream to Ittybit + R2