Skip to main content
Avala supports bring-your-own-storage (BYOS) so source data stays in your bucket and region. Connect an Amazon S3 or Google Cloud Storage bucket, and Avala reads assets directly from it by reference. You control access, retention, and encryption while Avala handles the annotation layer on top.

Amazon S3

Cross-account IAM roles let Avala access your bucket using temporary credentials — no long-lived keys to rotate or leak. Avala assumes a role in your AWS account using STS AssumeRole with an external ID for confused deputy protection.

1. Get Your Setup Info

Go to Mission Control → Settings → Storage → Add Storage → Amazon S3. Select IAM Role as the authentication method. You will see two values:
  • Avala AWS Account ID — the account that will assume your role
  • External ID — a unique identifier for your organization (used in the trust policy)
Copy both values — you will need them in the next step.
You can also retrieve these values programmatically via the SDK:
If your account belongs to multiple organizations, you must pass the organization parameter (your organization’s slug) to all storage config API calls. Single-organization accounts can omit it.

2. Create an IAM Role

In your AWS account, create an IAM role with the following trust policy. Replace AVALA_ACCOUNT_ID and EXTERNAL_ID with the values from Step 1.

3. Attach a Permissions Policy

Attach an inline or managed policy that grants Avala access to your bucket:
If you want Avala to write exports back to the bucket, also include s3:PutObject. Replace your-bucket-name with your actual bucket name.

4. Connect in Mission Control

  1. Go to Mission Control → Settings → Storage.
  2. Click Add Storage and select Amazon S3.
  3. Select IAM Role as the authentication method.
  4. Enter the Role ARN (e.g., arn:aws:iam::123456789012:role/AvalaStorageAccess).
  5. Enter your Bucket Name and Region.
  6. Click Test Connection to verify access.
  7. Save the configuration.

Access Key (Legacy)

You can also authenticate with long-lived AWS access keys. This method is still supported but not recommended — IAM roles are more secure because credentials are temporary and automatically rotated.
  1. Create an IAM user with programmatic access.
  2. Attach the same permissions policy shown above.
  3. In Mission Control, select Access Key as the authentication method.
  4. Enter the Access Key ID and Secret Access Key.
  5. Click Test Connection and save.
Access keys are long-lived credentials. If compromised, an attacker has access until you revoke them. Prefer IAM roles whenever possible.

CORS Configuration

The browser-based editor loads your objects directly from your bucket, so the bucket must allow cross-origin requests from https://avala.ai. Add this CORS rule:
Why the extra ExposeHeaders? Large files — MCAP recordings especially — are streamed with HTTP range requests rather than downloaded whole. The browser can only read a response header that is explicitly exposed, and the range machinery needs Content-Range, Content-Length and Accept-Ranges. Exposing only ETag is enough for images, but MCAP episodes will fail to open.

Google Cloud Storage

Service Account

Create a service account that Avala can use to access your bucket:
  1. In the Google Cloud Console, navigate to IAM & Admin > Service Accounts.
  2. Create a new service account (e.g., avala-storage-reader).
  3. Grant the following roles on the bucket:
    • roles/storage.objectViewer — read access to objects
    • roles/storage.legacyBucketReader — list objects in the bucket
  4. If Avala should write exports to the bucket, also grant roles/storage.objectCreator.
  5. Download the JSON key file for the service account.
The JSON key file grants access to your GCS bucket. Never commit it to version control. Store it securely, restrict file permissions, and rotate keys regularly.

CORS Configuration

The browser-based editor loads your objects directly from your bucket, so the bucket must allow cross-origin requests from https://avala.ai. Save the following as cors.json:
Apply it:
Replace your-bucket-name with your actual bucket name. (The older gsutil cors set cors.json gs://your-bucket-name still works.)
Range is required, and it is easy to miss. Large files — MCAP recordings especially — are streamed with HTTP range requests rather than downloaded whole. A request carrying a Range header triggers a CORS preflight, and Google Cloud Storage only permits it if Range appears in responseHeader. Omit it and GCS rejects the preflight with no Access-Control-Allow-Origin header at all, so the browser reports a generic CORS failure and the episode never loads.In GCS, responseHeader populates both Access-Control-Allow-Headers (what the browser may send) and Access-Control-Expose-Headers (what it may read) — which is why Range and the Content-Range / Content-Length / Accept-Ranges trio all belong in that one list.

Connect in Mission Control

  1. Go to Mission Control > Settings > Storage.
  2. Click Add Storage and select Google Cloud Storage.
  3. Enter your Bucket Name.
  4. Upload the Service Account JSON key file.
  5. Click Test Connection to verify access.
  6. Save the configuration.

Cloudflare R2

R2 speaks the S3 API, so Avala reads it through the same client as Amazon S3. Two things differ, and both matter when you connect a bucket:
  • There is no region. R2 is a single global namespace. Avala signs with the region string auto; you will not be asked for one.
  • There is no CloudFront, Transfer Acceleration or IAM role. Those are AWS features with no Cloudflare equivalent, and Avala refuses them on an R2 configuration rather than storing a setting that would silently produce URLs pointing at a host that does not serve your bucket.

Create an R2 API token

  1. In the Cloudflare dashboard, go to R2 > Manage R2 API Tokens.
  2. Create an Account API token with Object Read permission on the bucket Avala should read. Add Object Write only if Avala should write exports back.
  3. Copy the Access Key ID and Secret Access Key. Cloudflare shows the secret once.
  4. Note your Account ID — it is the 32-character hex string in the dashboard URL and on the R2 overview page.
The secret access key grants access to your R2 bucket. Never commit it to version control, and rotate tokens regularly. Avala stores it encrypted and never returns it through the API.

CORS Configuration

The browser-based editor loads objects directly from your bucket, so R2 must allow cross-origin requests from https://avala.ai. In the Cloudflare dashboard, open your bucket, go to Settings > CORS Policy, and add:
Range is required, for the same reason it is on GCS. Large files — MCAP recordings especially — are streamed with HTTP range requests rather than downloaded whole, and a request carrying a Range header triggers a CORS preflight. Omit Range from AllowedHeaders and the preflight fails, so the episode never loads. Content-Range, Content-Length and Accept-Ranges must appear in ExposeHeaders so the browser can read them back.

Public buckets

If your bucket is public, supply the public base URL as well — either the bucket’s r2.dev subdomain or a custom domain you have attached. Avala cannot derive it: unlike S3, an R2 bucket has no predictable public hostname, and the S3-compatible endpoint used for signing does not serve public reads. Leave it blank for private buckets, which are served through presigned URLs.

Connect in Mission Control

  1. Go to Mission Control > Settings > Storage.
  2. Click Add Storage and select Cloudflare R2.
  3. Enter your Cloudflare account ID (32 hex characters).
  4. Enter the Bucket Name, and a Prefix if Avala should only see part of the bucket.
  5. Enter the R2 access key ID and secret access key.
  6. For a public bucket, enter the public base URL.
  7. Click Test Connection to verify access.
  8. Save the configuration.
Egress. Cloudflare does not charge for data transfer out of R2. If you serve large volumes of imagery or recordings to annotators, this is usually the difference that matters between R2 and S3 — not the per-GB storage price.

Storage Configuration Options

Once a bucket is connected, you can configure it in Mission Control:

Uploading Data from Connected Buckets

After connecting a bucket, you can create datasets from its contents:
  1. Create a new dataset in Mission Control.
  2. Select Import from Cloud Storage as the data source.
  3. Browse or search the connected bucket for the files or folder you want.
  4. Select the assets and confirm the import.
Avala will register the assets by reference — it reads them from your bucket on demand rather than copying them.
Your data stays in your bucket at all times. Avala generates short-lived signed URLs to serve assets to the annotation editor and never persists copies of your files.