Skip to main content
Developers can configure Daily to store call recordings in an Amazon S3 bucket of their choice. In this configuration, Daily does not store the recording on its own servers at any point — recordings are written directly into the specified bucket.
If you’re new to call recording with Daily, check out the recording guide first.

S3 bucket configuration requirements

The target S3 bucket can be in any AWS region and must have versioning enabled. Select “Enable” under “Bucket Versioning” when creating your S3 bucket. Enabling S3 bucket versioning

Shortcut: automated setup script

Our team has created a GitHub repo with a custom script that configures your S3 bucket for Daily recordings automatically. You’ll need:
  1. Your Daily domain name (the subdomain of your Daily room URLs — e.g. https://your-domain.daily.co/room-name)
  2. The bucket name
  3. The bucket region
Follow the README for instructions. Once complete, skip to configuring your Daily domain or room.

Creating an IAM policy with appropriate permissions

AWS Identity and Access Management (IAM) controls access to AWS resources. To allow Daily to store recordings in your bucket, create an IAM policy with these permissions:
Replace your-bucket-name with the name of your S3 bucket. Create this policy in the IAM dashboard under Policies → Create. Creating an IAM policy

What each permission is for

Everything above s3:GetObject is write-side work: Daily needs it to get the recording into your bucket and to close out uploads cleanly. The two Get permissions are the only ones that let Daily read your recordings.
s3:ListMultipartUploadParts is a read-sounding name, but it is a separate action from s3:GetObject and it is part of the write path. If you add a Deny statement written as s3:Get* plus s3:List*, you will break the step that finishes interrupted uploads. Calls that end abruptly (a crashed tab, a dropped network) leave an open multipart upload, and Daily will not be able to complete it. Those recordings never appear in your bucket. List the actions you want to deny one by one instead of using a wildcard.

Optional: a write-only policy

If your security policy says Daily should never be able to read your recordings, you can drop the read permissions:
Recording uploads keep working with this policy. Here is what stops working:
  • Download and playback links from Daily. The recording access link API and the recording player in the Daily dashboard both hand out a link that is signed with Daily’s role. Without read access, that link fails with a 403 when someone opens it. Set allow_api_access to false so your team does not get handed links that cannot work.
  • The MP4 seek atom. Daily can add a seek atom (also called “faststart”) to finished MP4 files, which is what lets a player jump to the middle of a video without downloading the whole thing. That step reads the file back out of your bucket, so it cannot run.
  • Batch processor jobs. Anything that takes a finished recording and processes it (transcription, summaries, transmuxing) has to read the recording first.
The recording files themselves are complete and valid either way. They are just not always seekable in every player. You can add the seek atom yourself after you download a file:
Two things that often come up when people debug a tightened policy:
  • HeadObject is authorized by s3:GetObject, so calls that only ask for file metadata show up as s3:GetObject denials in CloudTrail. A GetObject denial does not always mean something tried to read your recording.
  • The access link API does not fail loudly. It builds and signs the link without touching your bucket, so it still returns a 200 with a URL. The 403 only shows up when someone opens the link.

Creating an IAM role for Daily

Create an IAM role with the policy attached. If you are already familiar with creating IAM roles, feel free to do so with the following settings. Otherwise, follow the walkthrough below.

Role creation walkthrough

  1. In the IAM dashboard, click Roles → Create Role.
  2. For “Trusted Entity Type”, select AWS Account.
  3. Under “An AWS Account”, select Another AWS account.
  4. Enter 291871421005 as the Account ID (this is Daily’s account).
  5. Enter your Daily domain name as the “Require External ID”. Configuring IAM role trusted entity
Your domain name is the first part of your room URLs: https://[domain-name].daily.co/[room-name]. You can also find it as a query parameter at https://dashboard.daily.co/?domain=[domain-name].
  1. Click Next and attach the IAM policy you created. Attaching IAM policy to the new IAM role
  2. Click Next again to give your role a name and click Create role.
  3. Find the role in your IAM Roles list, click Edit, and set Maximum session duration to 12 hours. Editing IAM role's maximum session duration
  4. Copy the ARN (Amazon Resource Name) from the role page — you’ll need it in the next step. Copying IAM role ARN

Configuring your Daily domain or room to store recordings in S3

S3 storage can be configured at the room or domain level. Which configuration gets used depends on the following priority order (highest to lowest):
  1. Customer S3 bucket at the room level
  2. Customer S3 bucket at the domain level
  3. Daily’s default storage (no configuration needed)
Recordings stored in a customer’s S3 bucket do not incur an additional Daily storage rate. The API will upload a test file (daily-co-test-upload.txt) to verify permissions.

Examples

Set a custom S3 bucket at the room level:
Set a custom S3 bucket at the domain level:
Revert to Daily default storage:
Properties:
  • bucket_name — name of your S3 bucket
  • bucket_region — AWS region of your S3 bucket
  • assume_role_arn — ARN of the IAM role you created above
  • allow_api_access — whether Daily’s recording access link API should allow downloading the recording
  • allow_streaming_from_bucket: whether download links open the recording in the browser (inline) instead of saving it to disk (attachment)
allow_api_access and allow_streaming_from_bucket change how Daily behaves. They do not change what your IAM policy allows. Turning allow_api_access off stops Daily from handing out a link, but it does not remove Daily’s read access to the bucket. If you want to remove read access, do it in the IAM policy: see the write-only policy above.
If you have any questions or run into issues with the setup, contact us.