Transcode video into your own R2 bucket
Connect your Cloudflare R2 bucket once. After that, every FFmpeg job writes its outputs straight into it — your keys, your access rules, your CDN.
The extra copy step
Most media APIs keep your outputs in their own storage. Your app then downloads each file and uploads it again to the bucket your product actually serves from. That is one more step to write, retry and monitor for every job.
It also means your media lives on a third party until you move it, under their retention rules.
- Source video
- Media API
- Their storage
- your copy job
- Your bucket
How Xora BYOB works
You set the destination once. Jobs need no storage fields at all.
-
Connect R2
Create an R2 API token with Object Read & Write on one bucket. Add it in the dashboard or with
POST /v1/settings/storage-providers. Xora runs a write test before you use it. -
Submit jobs as usual
Send recipes or raw FFmpeg args to
POST /v1/jobs. With a default provider set, outputs go to your bucket. UseoutputPathto pick the object key. -
Serve from your bucket
When the job reaches
completed, the files are already under your prefix. Serve them from your own CDN or custom domain.
Managed storage or your bucket
Both work with every recipe and with raw FFmpeg jobs. Pick per account.
| Xora managed storage | BYOB (Cloudflare R2) | |
|---|---|---|
| Where outputs live | Xora storage, behind signed URLs that expire | Your R2 bucket, under your prefix |
| Who controls access | Signed URLs; list and delete with the Files API | You — your bucket policy, your keys |
| Counts toward plan storage | Yes | No |
| Output billing | 10 credits per GB of output | 10 credits per GB of output — the same |
| Plans | All plans | Paid plans |
Setup in two calls
Register the bucket once with makeDefault: true. Every job after that delivers to it — the job body stays the same as with managed storage.
Inputs can still come from any HTTPS URL, including S3 or R2 presigned URLs. To set the object key for one job, add outputPath, for example "processed/2026/october/final.mp4". Full steps are in the storage providers guide.
Running on Cloudflare already? See FFmpeg on Cloudflare Workers for how a Worker can send the job and serve the result from the same bucket.
POST /v1/settings/storage-providers{ "name": "Production R2", "provider": "r2", "accountId": "your-cloudflare-account-id", "bucket": "my-media-bucket", "prefix": "processed/", "accessKeyId": "your-r2-access-key", "secretAccessKey": "your-r2-secret-key", "makeDefault": true}POST /v1/jobs{ "mode": "ffmpeg", "input_files": { "in_1": "https://example.com/raw-video.mp4" }, "output_files": { "out_1": "optimized.mp4" }, "ffmpeg": { "args": ["-i", "{{in_1}}", "-c:v", "libx264", "-crf", "23", "{{out_1}}"] }}Frequently asked questions
Can Xora write transcoded video to my Cloudflare R2 bucket?
Yes. Register the bucket with POST /v1/settings/storage-providers and set it as the default. After that, every job writes its outputs to your bucket, under the prefix you set. The job body does not change.
Which storage providers are supported?
Cloudflare R2 only, at the moment. Inputs can still come from any HTTPS URL, including S3 and R2 presigned URLs.
What permissions does the R2 token need?
Object Read & Write, scoped to the one bucket. Xora encrypts the secret key at rest, never returns it in API responses, and runs a write test before you use the bucket.
Can I choose the object key for each output?
Yes. Set outputPath on the job, for example processed/2026/october/final.mp4. The extension must match the output format. outputPath is not supported for jobs that use input_files and output_files. Without outputPath, the key is outputs/jobId/result with the format's extension, under your prefix.
Does BYOB cost extra?
No. Output is billed at the same credits per GB as with managed storage, and files in your bucket do not count toward your plan's storage. BYOB is on the paid plans.
Put your outputs where your product already reads them.
Start free with managed storage. Connect your R2 bucket when you move to a paid plan.