> For clean Markdown of any page, append .md to the page URL. > For a complete documentation index, see https://docs.meetstream.ai/guides/features/custom-storage-configurations/cloudflare-r2/llms.txt. > For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.meetstream.ai/_mcp/server. # Cloudflare R2 Custom Object Storage > Configure a Cloudflare R2 bucket in the MeetStream dashboard for meeting recordings, transcripts, and metadata. # Cloudflare R2 Custom Object Storage MeetStream can write meeting recordings, transcripts, screenshots, chat logs, and manifests to a Cloudflare R2 bucket through R2's S3-compatible API. Configure the destination in the MeetStream dashboard. Your bot and media fetch API calls continue to work as described in the [custom storage overview](/guides/features/custom-storage-configurations/overview). ## 1) Prerequisites 1. Create an R2 bucket in the location or jurisdiction appropriate for your data. 2. Create an R2 S3 API token with **Object Read & Write** permission restricted to that bucket. 3. Save the token's Access Key ID and Secret Access Key. Cloudflare shows the secret only once. 4. Copy the 32-character Cloudflare account ID for the bucket. R2 tokens can be scoped to a bucket, but not to an object-key prefix. Use a dedicated bucket when you need stronger isolation for MeetStream media. ## 2) Configure R2 in the dashboard Open **Custom Storage** in the [MeetStream dashboard](https://app.meetstream.ai), add a Cloudflare R2 destination, and enter the bucket name, account ID, and S3 access key pair. Choose a base object-key prefix or separate prefixes for audio, video, transcripts, and metadata, then save the destination. | Setting | Value | |---|---| | Provider | Cloudflare R2 (`cloudflare_r2`) | | Bucket name | Your R2 bucket name | | Account ID | Your 32-character hexadecimal Cloudflare account ID | | Region | `auto`, if the dashboard asks for a region; no other value is accepted | | Access Key ID and Secret Access Key | The R2 S3 API token's key pair | | Access mode | `read_write` only | | Base prefix | Optional; defaults to `meetstream` | | Category prefixes | Optional overrides for `audio`, `video`, `transcript`, and `metadata` | MeetStream derives the R2 S3 endpoint from the account ID: ```text https://.r2.cloudflarestorage.com ``` R2 does not accept an endpoint URL override. MeetStream-generated presigned URLs use the account-scoped S3 endpoint. Keep the access keys in the dashboard; do not put them in client-side code. You can save multiple destinations, including multiple R2 buckets. Manage the default in the [MeetStream dashboard](https://app.meetstream.ai), and use `storage_config_id` to [select a saved destination for a bot](/guides/features/custom-storage-configurations/overview#3-choose-a-saved-destination-for-a-bot). ## 3) Permissions and validation The R2 token needs **Object Read & Write** permission for the selected bucket. MeetStream treats `HeadBucket` as diagnostic and validates write, read, and delete access with temporary objects under the configured prefixes before saving the destination. Cleanup of R2 validation objects must succeed. Cloudflare R2 supports only `read_write` access in MeetStream. A `write_only` configuration is not available. ## 4) Fetch media MeetStream writes artifacts below the resolved category prefix and bot ID: ```text // ``` Existing artifacts stay in their original bucket and prefix if you change a destination later. Keep credentials for earlier buckets available when you need to retrieve older media. Your MeetStream media fetch calls do not change. They return R2 presigned URLs for recordings or read JSON artifacts from the bucket. Presigned URL lifetimes vary by artifact; see [Usage & Retention](/guides/features/usage-and-retention#presigned-url-lifetimes). Call the fetch endpoint again for a fresh URL. ## 5) Troubleshooting **The dashboard rejects the R2 destination** - Check that the account ID is a 32-character hexadecimal value and matches the bucket. - Use `auto` as the region if prompted; geographic region values are not valid for R2's S3 API. - Use an R2 S3 Access Key ID and Secret Access Key from an **Object Read & Write** token scoped to the bucket. - Do not enter an endpoint URL override. **A presigned URL returns `403`** Fetch a new URL if it has expired. Check that the configured credentials still have object read access and that the account ID and bucket name are correct. **Browser requests to R2 fail** If your application fetches presigned URLs from a browser, configure the bucket's CORS policy for your application's exact origins and methods. MeetStream does not change your R2 bucket's CORS settings. Do not use an R2 custom domain for MeetStream presigned URLs. **Files are not in a newly selected bucket** Only artifacts processed after the destination change use the new bucket. Earlier artifacts remain in their original bucket. ## Provider references - [Cloudflare R2 S3 API compatibility](https://developers.cloudflare.com/r2/api/s3/api/) - [Cloudflare R2 API token permissions](https://developers.cloudflare.com/r2/api/tokens/) - [Cloudflare R2 presigned URLs](https://developers.cloudflare.com/r2/api/s3/presigned-urls/) > Meeting bot API documentation for Zoom, Google Meet and Microsoft Teams: create bots, stream real-time audio, transcribe, and run in-meeting voice agents.