

# IVS Recording \$1 Real-Time Streaming
<a name="rt-recording"></a>

There are two recording options for IVS real-time streaming:
+ With individual participant recording, each publisher’s media is recorded in separate files.
+ In contrast, composite recording combines media from all publishers into a single view and records it in one file.

Individual participant recording incurs no additional Amazon IVS charges, while composite recording incurs charges for the hourly rate for the video encoded. Both recording options incur standard S3 storage and request costs. For more details, see [Amazon IVS pricing](https://aws.amazon.com/ivs/pricing/).

For a more customizable solution, consider using the open-source [IVSStageSaver](https://github.com/aws-samples/amazon-ivs-stage-recorder)r project as the foundation for your own self-hosted recording service.

## Individual Participant Recording
<a name="ind-par-rec"></a>

This option is ideal for live streams with a single publisher or when separate recordings of each publisher are needed, especially for moderation purposes. For more details, see [Individual Participant Recording](rt-individual-participant-recording.md).

![\[Recording each publisher's media in a separate file using individual particpant recording.\]](http://docs.aws.amazon.com/ivs/latest/RealTimeUserGuide/images/Individual_Participant_Recording.png)


## Composite Recording
<a name="comp-rec"></a>

This option combines media from multiple publishers into a single view and records it in one file, ideal for a video-on-demand experience. For more details, see [Composite Recording](rt-composite-recording.md).

![\[Recording a stage to an S3 bucket using server-side composition.\]](http://docs.aws.amazon.com/ivs/latest/RealTimeUserGuide/images/Composite_Recording.png)


## Thumbnails
<a name="thumbnails"></a>

Thumbnail recording for IVS real-time streaming can be set up for both individual participant recordings and composite (multi-participant) recordings. To enable or disable thumbnail recording and adjust the interval at which thumbnails are generated:
+ For individual participant recordings, use the `thumbnailConfiguration` property.
+ For composite recordings, use the `thumbnailConfigurations` property.

Thumbnail intervals range from 1 to 86400 seconds (24 hours); by default, thumbnail recording is disabled. For details, see the [Amazon IVS Real-Time Streaming API Reference](https://docs.aws.amazon.com//ivs/latest/RealTimeAPIReference/Welcome.html).

A thumbnail configuration includes a `storage` field, which can be set to `SEQUENTIAL` and/or `LATEST`. The `storage` field determines the S3 storage behavior for the thumbnails:
+ `SEQUENTIAL` saves all thumbnails in a serial manner. This is the default.
+ `LATEST` saves only the most recent thumbnail, overwriting the previous one.

If you specify both `SEQUENTIAL` and `LATEST`, thumbnails are written to two separate S3 paths, one for the sequential archive and one for the latest thumbnail.

# IVS Individual Participant Recording \$1 Real-Time Streaming
<a name="rt-individual-participant-recording"></a>

This document explains how to use individual participant recording with IVS real-time streaming.

Standard S3 storage and request costs apply. Thumbnails incur no additional IVS charges. For details, see [Amazon IVS Pricing](https://aws.amazon.com/ivs/pricing/).

## Introduction
<a name="ind-part-rec-introduction"></a>

Individual participant recording allows IVS real-time streaming customers to record IVS stage publishers individually into S3 buckets. When individual participant recording is enabled for a stage, publisher content is recorded once they start publishing to the stage.

**Note:** If you need to have all stage participants mixed in a single video, the composite recording feature is a better fit. See [Recording](rt-recording.md) for a summary of recording IVS real-time-streaming content.

![\[Recording each publisher's media in a separate file using individual particpant recording.\]](http://docs.aws.amazon.com/ivs/latest/RealTimeUserGuide/images/Individual_Participant_Recording.png)


## Workflow
<a name="ind-part-rec-workflow"></a>

![\[Workflow for recording each publisher's media in a separate file using individual particpant recording.\]](http://docs.aws.amazon.com/ivs/latest/RealTimeUserGuide/images/Workflow_Participant_Recording.png)


### 1. Create an S3 Bucket
<a name="ind-part-rec-create-s3-bucket"></a>

You will need an S3 bucket to write VODs. For details, see the S3 documentation on [how to create buckets](https://docs.aws.amazon.com/AmazonS3/latest/userguide/creating-bucket.html). Note that for individual participant recording, the S3 buckets must be created in the same AWS region as the IVS stage.

**Important**: If you use an existing S3 bucket:
+ The **Object Ownership** setting must be **Bucket owner enforced** or **Bucket owner preferred**.
+ The **Default Encryption** setting must be **Server-side encryption with Amazon S3 managed keys (SSE-S3)**.

For details, see the S3 documentation on [controlling ownership of objects](https://docs.aws.amazon.com/AmazonS3/latest/userguide/about-object-ownership.html) and [protecting data with encryption](https://docs.aws.amazon.com/AmazonS3/latest/userguide/UsingEncryption.html).

### 2. Create a StorageConfiguration Object
<a name="ind-part-rec-create-storageconfig-object"></a>

After creating a bucket, call the IVS real-time streaming API to [create a StorageConfiguration](https://docs.aws.amazon.com//ivs/latest/RealTimeAPIReference/API_CreateStorageConfiguration.html) object. Once the storage configuration is successfully created, IVS will have permission to write to the provided S3 bucket. You can re-use this StorageConfiguration object on multiple stages.

### 3. Create a Stage with Participant Tokens
<a name="ind-part-rec-create-stage-with-part-tokens"></a>

Now you need to [create an IVS stage](https://docs.aws.amazon.com//ivs/latest/RealTimeAPIReference/API_CreateStage.html) with individual participant recording enabled (by setting the AutoParticipantRecordingConfiguration object), as well as participant tokens for each publisher.

The request below creates a stage with two participant tokens and individual participant recording enabled.

```
POST /CreateStage HTTP/1.1
Content-type: application/json

{
   "autoParticipantRecordingConfiguration": { 
      "mediaTypes": ["AUDIO_VIDEO"],
      "storageConfigurationArn": "arn:aws:ivs:us-west-2:123456789012:storage-configuration/AbCdef1G2hij",
      "thumbnailConfiguration": {
         "recordingMode": "INTERVAL",
         "storage": ["LATEST", "SEQUENTIAL"],
         "targetIntervalSeconds": 60
      }
   },
   "name": "TestStage",
   "participantTokenConfigurations": [ 
      { 
         "capabilities": ["PUBLISH", "SUBSCRIBE"],
         "duration": 20160,
         "userId": "1"
      },
      { 
         "capabilities": ["PUBLISH", "SUBSCRIBE"],
         "duration": 20160,
         "userId": "2"
      }
   ]
}
```

### 4. Join the Stage as an Active Publisher
<a name="ind-part-rec-join-stage-as-active-pub"></a>

Distribute the participant tokens to your publishers, and have them join the stage and start [publishing to it](https://docs.aws.amazon.com//ivs/latest/RealTimeUserGuide/getting-started-pub-sub.html).

When they join the stage and start publishing to it using one of [IVS real-time streaming broadcast SDKs](https://docs.aws.amazon.com//ivs/latest/RealTimeUserGuide/broadcast.html), the participant-recording process starts automatically and sends you an [EventBridge event](eventbridge.md) indicating that the recording started. (The event is IVS Participant Recording State Change - Recording Start.) Concurrently, the participant-recording process starts writing the VOD and metadata files to the configured S3 bucket. Note: Participants connected for extremely short durations (less than 5s) are not guaranteed to be recorded.

There are two ways to get the S3 prefix for each recording:
+ Listen to the EventBridge event:

  ```
  {
     "version": "0",
     "id": "12345678-1a23-4567-a1bc-1a2b34567890",
     "detail-type": "IVS Participant Recording State Change",
     "source": "aws.ivs",
     "account": "123456789012",
     "time": "2024-03-13T22:19:04Z",
     "region": "us-east-1",
     "resources": ["arn:aws:ivs:us-west-2:123456789012:stage/AbCdef1G2hij"],
     "detail": {
        "session_id": "st-ZyXwvu1T2s",
        "event_name": "Recording Start",
        "participant_id": "xYz1c2d3e4f",
        "recording_s3_bucket_name": "ivs-recordings",
        "recording_s3_key_prefix": "<stage_id>/<session_id>/<participant_id>/2024-01-01T12-00-55Z"
     }
  }
  ```
+ Use the [GetParticipant](https://docs.aws.amazon.com//ivs/latest/RealTimeAPIReference/API_GetParticipant.html) API operation — The response includes the S3 bucket and prefix to where a participant is being recorded. Here is the request:

  ```
  POST /GetParticipant HTTP/1.1
  Content-type: application/json
  {
     "participantID": "xYz1c2d3e4f",
     "sessionId": "st-ZyXwvu1T2s",
     "stageArn": "arn:aws:ivs:us-west-2:123456789012:stage/AbCdef1G2hij"
  }
  ```

  And here is the response:

  ```
  Content-type: application/json
  {
     "participant": {
        ...
        "recordingS3BucketName": "ivs-recordings",
        "recordingS3Prefix": "<stage_id>/<session_id>/<participant_id>",
        "recordingState": "ACTIVE",
        ...
     }
  }
  ```

### 5. Play Back the VOD
<a name="ind-part-rec-play-back-vod"></a>

After the recording is finalized, you can watch it using the [IVS player](https://debug.ivsdemos.com/?p=ivs). See [Playback of Recorded Content from Private Buckets](https://docs.aws.amazon.com//ivs/latest/RealTimeUserGuide/rt-composite-recording.html#comp-rec-playback) for instructions on setting up CloudFront distributions for VOD playback.

## Audio-Only Recording
<a name="ind-part-rec-audio-only-recordings"></a>

When setting up individual participant recording, you can choose to have only audio HLS segments written to your S3 bucket. To use this feature, choose the `AUDIO_ONLY mediaType` when creating the stage:

```
POST /CreateStage HTTP/1.1
Content-type: application/json

{
   "autoParticipantRecordingConfiguration": { 
      "storageConfigurationArn": "arn:aws:ivs:us-west-2:123456789012:storage-configuration/AbCdef1G2hij",
      "mediaTypes": ["AUDIO_ONLY"],
      "thumbnailConfiguration": {
         "recordingMode": "DISABLED"
      }
   },
   "name": "TestStage",
   "participantTokenConfigurations": [ 
      { 
         "capabilities": ["PUBLISH", "SUBSCRIBE"],
         "duration": 20160,
         "userId": "1"
      },
      { 
         "capabilities": ["PUBLISH", "SUBSCRIBE"],
         "duration": 20160,
         "userId": "2"
      }
   ]
}
```

## Thumbnail-Only Recording
<a name="ind-part-rec-recording-thumbnail-only"></a>

When setting up individual participant recording, you can choose to have only thumbnails written to your S3 bucket. To use this feature, set `mediaType` to `NONE` when creating the stage. This ensures that no HLS segments are generated; thumbnails are still created and written to your S3 bucket.

```
POST /CreateStage HTTP/1.1
Content-type: application/json
{
   "autoParticipantRecordingConfiguration": { 
      "storageConfigurationArn": "arn:aws:ivs:us-west-2:123456789012:storage-configuration/AbCdef1G2hij",
      "mediaTypes": ["NONE"],
      "thumbnailConfiguration": {
         "recordingMode": "INTERVAL",
         "storage": ["LATEST", "SEQUENTIAL"],
         "targetIntervalSeconds": 60
      }
   },
   "name": "TestStage",
   "participantTokenConfigurations": [ 
      { 
         "capabilities": ["PUBLISH", "SUBSCRIBE"],
         "duration": 20160,
         "userId": "1"
      },
      { 
         "capabilities": ["PUBLISH", "SUBSCRIBE"],
         "duration": 20160,
         "userId": "2"
      }
   ]
}
```

## Recording Contents
<a name="ind-part-rec-recording-contents"></a>

When individual participant recording is active, HLS video segments, metadata files, and thumbnails will start being written to the S3 bucket provided when the stage was created. This content is available for post-processing or playback as on-demand video.

Note that after a recording is finalized, an IVS Participant Recording State Change - Recording End event is sent through EventBridge. We recommend that you play back or process recorded streams only after this event is received. For details, see [Using EventBridge with IVS Real-Time Streaming](eventbridge.md).

The following is a sample directory structure and contents of a recording of a live IVS session:

```
s3://mybucket/stageId/stageSessionId/participantId/timestamp
   events
      recording-started.json
      recording-ended.json
   media
      hls
	 multivariant.m3u8
         high
            playlist.m3u8
            1.mp4
      thumbnails
         high
            1.jpg
            2.jpg
      latest_thumbnail
         high
            thumb.jpg
```

The `events` folder contains the metadata files corresponding to the recording event. JSON metadata files are generated when recording starts, ends successfully, or ends with failures:
+ `events/recording-started.json`
+ `events/recording-ended.json`
+ `events/recording-failed.json`

A given `events` folder contains `recording-started.json` and either `recording-ended.json` or `recording-failed.json`. These contain metadata related to the recorded session and its output formats. JSON details are given below.

The `media` folder contains the supported media contents. The `hls` subfolder contains all media and the manifest files generated during the recording session and is playable with the IVS player. If configured, the `thumbnails` and `latest_thumbnail` subfolders contain JPEG thumbnail media files generated during the recording session.

## Merge Fragmented Individual Participant Recordings
<a name="ind-part-rec-merge-frag"></a>

The `recordingReconnectWindowSeconds` property on a recording configuration allows you to specify a window of time (in seconds) during which, if a stage publisher disconnects from a stage and then reconnects, IVS tries to record to the same S3 prefix as the previous session. In other words, if a publisher disconnects and then reconnects within the specified interval, the multiple recordings are considered a single recording and merged together.

If thumbnail recording is enabled in `SEQUENTIAL` mode, then thumbnails are also merged under the same `recordingS3Prefix`. When the recordings are merged, the thumbnail counter restarts from the previous thumbnail value that was written for the previous recording.

**IVS Recording State Change events in Amazon EventBridge:** Recording End events and recording-ended JSON metadata files are delayed by at least `recordingReconnectWindowSeconds`, as IVS waits to ensure a new stream is not started.

For instructions on setting up the merge-streams functionality, see [Step 2: Create a Stage with Optional Participant Recording](getting-started-create-stage.md) in *Getting Started with Amazon IVS Real-Time Streaming*.

### Eligibility
<a name="ind-part-rec-merge-frag-eligibility"></a>

For multiple recordings to be merged using the same S3 prefix, certain conditions must be met for all the recordings:
+ The value of the `recordingReconnectWindowSeconds` property of the AutoParticipantRecordingConfiguration for the stage is set greater than 0.
+ The `StorageConfigurationArn` used to write the VOD artifacts is the same for each recording.
+ The time difference in seconds between when the participant leaves and rejoins the stage is less than or equal to `recordingReconnectWindowSeconds`.

Note that the default value of `recordingReconnectWindowSeconds` is 0, which disables merging.

## Synchronize Multiple Participant Recordings
<a name="ind-part-rec-sync-multiple"></a>

Individual participant recordings include `EXT-X-PROGRAM-DATE-TIME` tags in HLS playlists, which provide precise UTC timestamps with millisecond accuracy for synchronizing recordings from multiple participants during post-processing.

When you record multiple participants individually and want to create a synchronized composition (such as a side-by-side or picture-in-picture layout), you can use these timestamps to align the recordings accurately, even if participants joined the stage at different times or experienced discontinuities potentially caused by network interruptions.

Each participant's HLS playlist includes `EXT-X-PROGRAM-DATE-TIME` tags that mark:
+ The start of the recording (first segment).
+ Any discontinuity points during the recording; e.g., when stitching occurs.

These timestamps use millisecond precision and are synchronized across all participants using the same time reference.

### Example HLS Playlist
<a name="ind-part-rec-sync-multiple-hls-playlist"></a>

```
#EXTM3U
#EXT-X-VERSION:7
#EXT-X-TARGETDURATION:12
#EXT-X-PLAYLIST-TYPE:VOD
#EXT-X-MAP:URI="init-0.mp4"
#EXT-X-PROGRAM-DATE-TIME:2024-01-01T12:00:00.000Z
#EXTINF:3.30091,
0.mp4
#EXTINF:5.63794,
1.mp4
#EXTINF:2.74290,
2.mp4
#EXT-X-DISCONTINUITY
#EXT-X-MAP:URI="init-1.mp4"
#EXT-X-PROGRAM-DATE-TIME:2024-01-01T12:00:52.772Z
#EXTINF:2.54412,
3.mp4
#EXTINF:5.63649,
4.mp4
```

The `EXT-X-PROGRAM-DATE-TIME` tags provide the exact UTC time for the first segment and at each discontinuity point, enabling precise synchronization with other participants' recordings.

### Synchronization Workflow
<a name="ind-part-rec-sync-multiple-workflow"></a>

To synchronize multiple participant recordings, extract the `EXT-X-PROGRAM-DATE-TIME` timestamps from each participant's HLS playlist and use them to calculate time offsets. These offsets can then be applied during post-processing composition using video processing tools like FFmpeg. When discontinuities are present in the recordings, timestamps at those points provide the necessary timing references to maintain accurate synchronization throughout the entire recording.

Note: For real-time synchronized output without post-processing, consider using server-side composition instead of individual participant recording.

## JSON Metadata Files
<a name="ind-part-rec-json-metadata-files"></a>

This metadata is in JSON format. It comprises the following information: 


| Field | Type | Required | Description | 
| --- | --- | --- | --- | 
| `stage_arn` | string | Yes | ARN of the stage being used as the source of the recording. | 
| `session_id` | string | Yes | String representing the stage's `session_id` where the participant is recorded. | 
| `participant_id` | string | Yes | String representing the identifier of the recorded participant. | 
| `recording_started_at` | string | Conditional | RFC 3339 UTC timestamp when the recording started. This is unavailable when `recording_status` is `RECORDING_START_FAILED`. Also, see the note below for `recording_ended_at`. | 
| `recording_ended_at` | string | Conditional | RFC 3339 UTC timestamp when the recording ended. This is available only when `recording_status` is `"RECORDING_ENDED"` or `"RECORDING_ENDED_WITH_FAILURE"`. **Note:** `recording_started_at` and `recording_ended_at` are timestamps when these events are generated and may not exactly match the HLS video-segment timestamps. To accurately determine the duration of a recording, use the `duration_ms` field. | 
| `recording_status` | string | Yes | Status of the recording. Valid values: `"RECORDING_STARTED"`, `"RECORDING_ENDED"`, `"RECORDING_START_FAILED"`, `"RECORDING_ENDED_WITH_FAILURE"`. | 
| `recording_status_message` | string | Conditional | Descriptive information on the status. This is available only when `recording_status` is `"RECORDING_ENDED"` or `"RECORDING_ENDED_WITH_FAILURE"`. | 
| `media` | object | Yes | Object that contains the enumerated objects of media content available for this recording. Valid value: `"hls"`. | 
|  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ivs/latest/RealTimeUserGuide/rt-individual-participant-recording.html)  | object | Yes | Enumerated field that describes the Apple HLS format output. | 
|  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ivs/latest/RealTimeUserGuide/rt-individual-participant-recording.html)  | integer | Conditional | Duration of the recorded HLS content in milliseconds. This is available only when `recording_status` is `"RECORDING_ENDED"` or `"RECORDING_ENDED_WITH_FAILURE"`. If a failure occurred before any recording was done, this is 0. | 
|  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ivs/latest/RealTimeUserGuide/rt-individual-participant-recording.html)  | string | Yes | Relative path from the S3 prefix where HLS content is stored. | 
|  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ivs/latest/RealTimeUserGuide/rt-individual-participant-recording.html)  | string | Yes | Name of the HLS master playlist file. | 
|  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ivs/latest/RealTimeUserGuide/rt-individual-participant-recording.html)  | object | Yes | Array of renditions (HLS variants) of metadata objects. There always is at least one rendition. | 
|  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ivs/latest/RealTimeUserGuide/rt-individual-participant-recording.html)  | string | Yes | Relative path from the S3 prefix where HLS content is stored for this rendition. | 
|  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ivs/latest/RealTimeUserGuide/rt-individual-participant-recording.html)  | string | Yes | Name of the media playlist file for this rendition. | 
|  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ivs/latest/RealTimeUserGuide/rt-individual-participant-recording.html)  | object | Conditional | Enumerated field that describes thumbnails output. This is available only when the thumbnail configuration’s `storage` field includes `SEQUENTIAL` | 
|  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ivs/latest/RealTimeUserGuide/rt-individual-participant-recording.html)  | string | Yes | Relative path from the S3 prefix where sequential thumbnail content is stored. | 
|  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ivs/latest/RealTimeUserGuide/rt-individual-participant-recording.html)  | object | Yes | Array of renditions (thumbnail variants) of metadata objects. There always is at least one rendition. | 
|  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ivs/latest/RealTimeUserGuide/rt-individual-participant-recording.html)  | string | Yes | Relative path from the S3 prefix where thumbnail content is stored for this rendition. | 
|  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ivs/latest/RealTimeUserGuide/rt-individual-participant-recording.html)  | object | Conditional | Enumerated field that describes thumbnails output. This is available only when the thumbnail configuration’s `storage` field includes `LATEST`. | 
|  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ivs/latest/RealTimeUserGuide/rt-individual-participant-recording.html)  | string | Yes | Relative path from the S3 prefix where `latest_thumbnail` is stored. | 
|  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ivs/latest/RealTimeUserGuide/rt-individual-participant-recording.html)  | object | Yes | Array of renditions (thumbnail variants) of metadata objects. There always is at least one rendition. | 
|  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ivs/latest/RealTimeUserGuide/rt-individual-participant-recording.html)  | string | Yes | Relative path from the S3 prefix where the latest thumbnail is stored for this rendition. | 
| `version` | string | Yes | The version of the metadata schema. | 

### Example: recording-started.json
<a name="ind-part-rec-json-ex-rec-start"></a>

```
{
   "version": "v1",
   "stage_arn": "arn:aws:ivs:us-west-2:aws_account_id:stage/AbCdef1G2hij",
   "session_id": "st-ZyXwvu1T2s",
   "participant_id": "xYz1c2d3e4f",
   "recording_started_at": "2024-03-13T13:17:17Z",
   "recording_status": "RECORDING_STARTED",
   "media": {
      "hls": {
         "path": "media/hls",
         "playlist": "multivariant.m3u8",
         "renditions": [
            {
               "path": "high",
               "playlist": "playlist.m3u8"
            }
         ]
      },
      "thumbnails": {
         "path": "media/thumbnails",
         "renditions": [
            {
               "path": "high"
            }
         ]
      },
      "latest_thumbnail": {
         "path": "media/latest_thumbnail",
         "renditions": [
            {
               "path": "high"
            }
         ]
      }
   }
}
```

### Example: recording-ended.json
<a name="ind-part-rec-json-ex-rec-end"></a>

```
{
   "version": "v1",
   "stage_arn": "arn:aws:ivs:us-west-2:aws_account_id:stage/AbCdef1G2hij",
   "session_id": "st-ZyXwvu1T2s",
   "participant_id": "xYz1c2d3e4f",
   "recording_started_at": "2024-03-13T19:44:19Z",
   "recording_ended_at": "2024-03-13T19:55:04Z",
   "recording_status": "RECORDING_ENDED",
   "media": {
      "hls": {
         "duration_ms": 645237,
         "path": "media/hls",
         "playlist": "multivariant.m3u8",
         "renditions": [
            {
               "path": "high",
               "playlist": "playlist.m3u8"
            }
         ]
      },
      "thumbnails": {
         "path": "media/thumbnails",
         "renditions": [
            {
               "path": "high"
            }
         ]
      },
      "latest_thumbnail": {
         "path": "media/latest_thumbnail",
         "renditions": [
            {
               "path": "high"
            }
         ]
      }
   }
}
```

### Example: recording-failed.json
<a name="ind-part-rec-json-ex-rec-failed"></a>

```
{
   "version": "v1",
   "stage_arn": "arn:aws:ivs:us-west-2:aws_account_id:stage/AbCdef1G2hij",
   "session_id": "st-ZyXwvu1T2s",
   "participant_id": "xYz1c2d3e4f",
   "recording_started_at": "2024-03-13T19:44:19Z",
   "recording_ended_at": "2024-03-13T19:55:04Z",
   "recording_status": "RECORDING_ENDED_WITH_FAILURE",
   "media": {
      "hls": {
         "duration_ms": 645237,
         "path": "media/hls",
         "playlist": "multivariant.m3u8",
         "renditions": [
            {
               "path": "high",
               "playlist": "playlist.m3u8"
            }
         ]
      },
      "thumbnails": {
         "path": "media/thumbnails",
         "renditions": [
            {
               "path": "high"
            }
         ]
      },
      "latest_thumbnail": {
         "path": "media/latest_thumbnail",
         "renditions": [
            {
               "path": "high"
            }
         ]
      }
   }
}
```

## Converting Recordings to MP4
<a name="ind-part-rec-convert-rec-mp4"></a>

Individual participant recordings are stored in the HLS format, consisting of playlists and fragmented MP4 (fMP4) segments. To convert an HLS recording into a single MP4 file, install FFmpeg and run the following command:

```
ffmpeg -i /path/to/playlist.m3u8 -i /path/to/playlist.m3u8 -map 0:v -map 1:a -c copy output.mp4
```

# IVS Composite Recording \$1 Real-Time Streaming
<a name="rt-composite-recording"></a>

This document explains how to use the composite-recording feature within [server-side composition](server-side-composition.md). Composite recording allows you to generate HLS recordings of an IVS stage by effectively combining all stage publishers into one view using an IVS server, and then saving the resulting video to an S3 bucket.

Standard S3 storage and request costs apply. Thumbnails incur no additional IVS charges. For details, see [Amazon IVS Pricing](https://aws.amazon.com/ivs/pricing/).

## Prerequisites
<a name="comp-rec-prerequisites"></a>

To use composite recording, you must have a stage with active publishers and an S3 bucket to use as the recording destination. Below, we describe one possible workflow that uses EventBridge events to record a composition to an S3 bucket. Alternatively, you can start and stop compositions based on your own app logic.

1. Create [an IVS stage](getting-started-create-stage.md) and participant tokens for each publisher.

1. Create an [EncoderConfiguration](https://docs.aws.amazon.com/ivs/latest/RealTimeAPIReference/API_CreateEncoderConfiguration.html) (an object representing how the recorded video should be rendered).

1. Create an [S3 bucket](https://docs.aws.amazon.com/AmazonS3/latest/userguide/creating-bucket.html) and a [StorageConfiguration](https://docs.aws.amazon.com//ivs/latest/RealTimeAPIReference/API_CreateStorageConfiguration.html) (where the recording contents will be stored).

   **Important**: If you use an existing S3 bucket, the **Object Ownership** setting must be **Bucket owner enforced** or **Bucket owner preferred**. For details, see the S3 documentation on [controlling ownership of objects](https://docs.aws.amazon.com/AmazonS3/latest/userguide/about-object-ownership.html).

1. [Join the stage and publish to it](getting-started-pub-sub.md).

1. When you receive a Participant Published [EventBridge event](eventbridge.md), call [StartComposition](https://docs.aws.amazon.com//ivs/latest/RealTimeAPIReference/API_StartComposition.html) with an S3 DestinationConfiguration object as the destination

1. After a few seconds, you should be able to see the HLS segments being persisted to your S3 buckets.

![\[Recording a stage to an S3 bucket using server-side composition.\]](http://docs.aws.amazon.com/ivs/latest/RealTimeUserGuide/images/Composite_Recording_Workflow.png)


**Note:** A composition performs auto-shutdown after 60 seconds of inactivity from publisher participants on the stage. At that point, the composition is terminated and transitions to a `STOPPED` state. A composition is automatically deleted after a few minutes in the `STOPPED` state. For details, see [Composition Lifecycle](ssc-overview.md#ssc-composition-endpoint) in *Server-Side Composition*.

## Composite Recording Example: StartComposition with an S3 Bucket Destination
<a name="comp-rec-example"></a>

The example below shows a typical call to the [StartComposition](https://docs.aws.amazon.com//ivs/latest/RealTimeAPIReference/API_StartComposition.html) operation, specifying S3 as the only destination for the composition. Once the composition transitions to an `ACTIVE` state, video segments and metadata will start to be written to the S3 bucket specified by the `storageConfiguration` object. To create compositions with different layouts, see “Layouts” in [Server-Side Composition](ssc-overview.md#ssc-api-layouts) and the [IVS Real-Time Streaming API Reference](https://docs.aws.amazon.com//ivs/latest/RealTimeAPIReference/API_LayoutConfiguration.html).

### Request
<a name="comp-rec-example-request"></a>

```
POST /StartComposition HTTP/1.1
Content-type: application/json

{
   "destinations": [
      {
         "s3": {
            "encoderConfigurationArns": [
              "arn:aws:ivs:ap-northeast-1:927810967299:encoder-configuration/PAAwglkRtjge"
            ],
            "storageConfigurationArn": "arn:aws:ivs:ap-northeast-1:927810967299:storage-configuration/ZBcEbgbE24Cq",
	    "thumbnailConfigurations": [
	       {
		  "storage": ["LATEST", "SEQUENTIAL"],
		  "targetIntervalSeconds": 30
               }
	    ]
	 }
      }
   ],
   "idempotencyToken": "db1i782f1g9",
   "stageArn": "arn:aws:ivs:ap-northeast-1:927810967299:stage/WyGkzNFGwiwr"
}
```

### Response
<a name="comp-rec-example-response"></a>

```
{
    "composition": {
        "arn": "arn:aws:ivs:ap-northeast-1:927810967299:composition/s2AdaGUbvQgp",
        "destinations": [
            {
                "configuration": {
                    "name": "",
                    "s3": {
                        "encoderConfigurationArns": [
                            "arn:aws:ivs:ap-northeast-1:927810967299:encoder-configuration/PAAwglkRtjge"
                        ],
                        "recordingConfiguration": {
                            "format": "HLS"
                        },
                        "storageConfigurationArn": "arn:aws:ivs:ap-northeast-1:927810967299:storage-configuration/ZBcEbgbE24Cq",
	                "thumbnailConfigurations": [
	                   {
		              "storage": ["LATEST", "SEQUENTIAL"],
		              "targetIntervalSeconds": 30
                           }
	                ]
                    }
                },
                "detail": {
                    "s3": {
                        "recordingPrefix": "MNALAcH9j2EJ/s2AdaGUbvQgp/2pBRKrNgX1ff/composite"
                    }
                },
                "id": "2pBRKrNgX1ff",
                "state": "STARTING"
            }
        ],
        "layout": null,
        "stageArn": "arn:aws:ivs:ap-northeast-1:927810967299:stage/WyGkzNFGwiwr",
        "startTime": "2023-11-01T06:25:37Z",
        "state": "STARTING",
        "tags": {}
    }
}
```

The `recordingPrefix` field, present in the StartComposition response can be used to determine where the recording contents will be stored. 

## Recording Contents
<a name="comp-rec-contents"></a>

When the composition transitions to an `ACTIVE` state, HLS video segments, metadata files, and thumbnails (if configured) will start being written to the S3 bucket specified during the StartComposition call. This content is available for post-processing or playback as on-demand video.

Note that after a composition becomes live, an “IVS Composition State Change” event is emitted, and it may take a little time before the manifest files, video segments, and thumbnails are written. We recommend that you play back or process recorded streams only after the “IVS Composition State Change (Session End)” event is received. For details, see [Using EventBridge with IVS Real-Time Streaming](eventbridge.md) .

The following is a sample directory structure and contents of a recording of a live IVS session:

```
MNALAcH9j2EJ/s2AdaGUbvQgp/2pBRKrNgX1ff/composite
   events
      recording-started.json
      recording-ended.json
   media
      hls
      thumbnails
      latest_thumbnail
```

The `events` folder contains the metadata files corresponding to the recording event. JSON metadata files are generated when recording starts, ends successfully, or ends with failures:
+ `events/recording-started.json`
+ `events/recording-ended.json`
+ `events/recording-failed.json`

A given `events` folder will contain `recording-started.json` and either `recording-ended.json` or `recording-failed.json`.

These contain metadata related to the recorded session and its output formats. JSON details are given below.

The `media` folder contains the supported media contents. The `hls` subfolder contains all media and the manifest files generated during the composition session and is playable with the IVS player. The HLS manifest is located in the `multivariant.m3u8` folder. If configured, the `thumbnails` and `latest_thumbnail` subfolders contain JPEG thumbnail media files generated during the composition session.

## Bucket Policy for StorageConfiguration
<a name="comp-rec-bucket-policy"></a>

When a StorageConfiguration object is created, IVS will get access to write content to the specified S3 bucket. This access is granted by making modifications to the S3 bucket's policy. *If the policy for the bucket is altered in a way that removes IVS's access, ongoing and new recordings will fail.*

The example below shows an S3 bucket policy that allows IVS to write to the S3 bucket:

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Sid": "CompositeWrite-y1d212y",
            "Effect": "Allow",
            "Principal": {
                "Service": "ivs-composite.ap-northeast-1.amazonaws.com"
            },
            "Action": [
                "s3:PutObject",
                "s3:PutObjectAcl"
            ],
            "Resource": "arn:aws:s3:::my-s3-bucket/*",
            "Condition": {
                "StringEquals": {
                    "s3:x-amz-acl": "bucket-owner-full-control"
                },
                "Bool": {
                    "aws:SecureTransport": "true"
                }
            }
        }
    ]
}
```

------

## JSON Metadata Files
<a name="comp-rec-json"></a>

This metadata is in JSON format. It comprises the following information: 


| Field | Type | Required | Description | 
| --- | --- | --- | --- | 
| `stage_arn` | string | Yes | ARN of the stage being used as the source of the composition. | 
| `media` | object | Yes | Object that contains the enumerated objects of media content available for this recording. Valid values: `"hls"`.  | 
| [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ivs/latest/RealTimeUserGuide/rt-composite-recording.html) | object | Yes | Enumerated field that describes the Apple HLS format output. | 
|  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ivs/latest/RealTimeUserGuide/rt-composite-recording.html)  | integer | Conditional | Duration of the recorded HLS content in milliseconds. This is available only when `recording_status` is `"RECORDING_ENDED"` or `"RECORDING_ENDED_WITH_FAILURE"`. If a failure occurred before any recording was done, this is 0. | 
|  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ivs/latest/RealTimeUserGuide/rt-composite-recording.html)  | string | Yes | Relative path from the S3 prefix where HLS content is stored. | 
|  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ivs/latest/RealTimeUserGuide/rt-composite-recording.html)  | string | Yes |  Name of the HLS master playlist file.  | 
|  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ivs/latest/RealTimeUserGuide/rt-composite-recording.html)  | object | Yes | Array of renditions (HLS variant) of metadata objects. There always is at least one rendition. | 
|  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ivs/latest/RealTimeUserGuide/rt-composite-recording.html)  | string | Yes | Relative path from the S3 prefix where HLS content is stored for this rendition. | 
|  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ivs/latest/RealTimeUserGuide/rt-composite-recording.html)  | string | Yes | Name of the media playlist file for this rendition. | 
|  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ivs/latest/RealTimeUserGuide/rt-composite-recording.html)  | int | Conditional | Pixel resolution height of the encoded video. This is available only when the rendition contains a video track. | 
|  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ivs/latest/RealTimeUserGuide/rt-composite-recording.html)  | int | Conditional | Pixel resolution width of the encoded video. This is available only when the rendition contains a video track. | 
|  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ivs/latest/RealTimeUserGuide/rt-composite-recording.html)  | object | Conditional | Enumerated field that describes thumbnails output. This is available only when the thumbnail configuration’s `storage` field includes `SEQUENTIAL` | 
|  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ivs/latest/RealTimeUserGuide/rt-composite-recording.html)  | string | Yes | Relative path from the S3 prefix where sequential thumbnail content is stored. | 
|  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ivs/latest/RealTimeUserGuide/rt-composite-recording.html)  | object | Yes | Array of resolutions (thumbnail variants) of metadata objects. There always is at least one resolution. | 
|  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ivs/latest/RealTimeUserGuide/rt-composite-recording.html)  | string | Yes | Relative path from the S3 prefix where thumbnail content is stored for this resolution. | 
|  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ivs/latest/RealTimeUserGuide/rt-composite-recording.html)  | int | Yes | Pixel resolution height of the thumbnails. | 
|  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ivs/latest/RealTimeUserGuide/rt-composite-recording.html)  | int | Yes | Pixel resolution width of the thumbnails. | 
|  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ivs/latest/RealTimeUserGuide/rt-composite-recording.html)  | object | Conditional | Enumerated field that describes thumbnails output. This is available only when the thumbnail configuration’s `storage` field includes `LATEST`. | 
|  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ivs/latest/RealTimeUserGuide/rt-composite-recording.html)  | string | Yes | Relative path from the S3 prefix where `latest_thumbnail` is stored. | 
|  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ivs/latest/RealTimeUserGuide/rt-composite-recording.html)  | object | Yes | Array of resolutions (thumbnail variants) of metadata objects. There always is at least one resolution. | 
|  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ivs/latest/RealTimeUserGuide/rt-composite-recording.html)  | string | Yes | Relative path from the S3 prefix where the latest thumbnail is stored for this resolution. | 
|  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ivs/latest/RealTimeUserGuide/rt-composite-recording.html)  | int | Yes | Pixel resolution height of the latest thumbnail. | 
|  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ivs/latest/RealTimeUserGuide/rt-composite-recording.html)  | int | Yes | Pixel resolution width of the latest thumbnail. | 
| `recording_ended_at` | string | Conditional | RFC 3339 UTC timestamp when the recording ended. This is available only when `recording_status` is `"RECORDING_ENDED"` or `"RECORDING_ENDED_WITH_FAILURE"`. `recording_started_at` and `recording_ended_at` are timestamps when these events are generated and may not exactly match the HLS video-segment timestamps. To accurately determine the duration of a recording, use the `duration_ms` field.  | 
| `recording_started_at` | string | Conditional | RFC 3339 UTC timestamp when the recording started. This is unavailable when `recording_status` is `RECORDING_START_FAILED`. See the note above for `recording_ended_at`.  | 
| `recording_status` | string | Yes | Status of the recording. Valid values: `"RECORDING_STARTED"`, `"RECORDING_ENDED"`, `"RECORDING_START_FAILED"`, `"RECORDING_ENDED_WITH_FAILURE"`. | 
| `recording_status_message` | string | Conditional | Descriptive information on the status. This is available only when `recording_status` is `"RECORDING_ENDED"` or `"RECORDING_ENDED_WITH_FAILURE"`. | 
| `version` | string | Yes | The version of the metadata schema. | 

### Example: recording-started.json
<a name="comp-rec-json-ex-rec-start"></a>

```
{
  "version": "v1",
  "stage_arn": "arn:aws:ivs:ap-northeast-1:123456789012:stage/aAbBcCdDeE12",
  "recording_started_at": "2023-11-01T06:01:36Z",
  "recording_status": "RECORDING_STARTED",
  "media": {
    "hls": {
      "path": "media/hls",
      "playlist": "multivariant.m3u8",
      "renditions": [
        {
          "path": "720p30-abcdeABCDE12",
          "playlist": "playlist.m3u8",
          "resolution_width": 1280,
          "resolution_height": 720
        }
      ]
    },
    "thumbnails": {
      "path": "media/thumbnails",
      "resolutions": [
        {
          "path": "1280x720",
          "resolution_width": 1280,
          "resolution_height": 720
        }
      ]
    },
    "latest_thumbnail": {
      "path": "media/latest_thumbnail",
      "resolutions": [
        {
          "path": "1280x720",
          "resolution_width": 1280,
          "resolution_height": 720
        }
      ]
    }
  }
}
```

### Example: recording-ended.json
<a name="comp-rec-json-ex-rec-end"></a>

```
{
  "version": "v1",
  "stage_arn": "arn:aws:ivs:ap-northeast-1:123456789012:stage/aAbBcCdDeE12",
  "recording_started_at": "2023-10-27T17:00:44Z",
  "recording_ended_at": "2023-10-27T17:08:24Z",
  "recording_status": "RECORDING_ENDED",
  "media": {
    "hls": {
      "duration_ms": 460315,
      "path": "media/hls",
      "playlist": "multivariant.m3u8",
      "renditions": [
        {
          "path": "720p30-abcdeABCDE12",
          "playlist": "playlist.m3u8",
          "resolution_width": 1280,
          "resolution_height": 720
        }
      ]
    },
    "thumbnails": {
      "path": "media/thumbnails",
      "resolutions": [
        {
          "path": "1280x720",
          "resolution_width": 1280,
          "resolution_height": 720
        }
      ]
    },
    "latest_thumbnail": {
      "path": "media/latest_thumbnail",
      "resolutions": [
        {
          "path": "1280x720",
          "resolution_width": 1280,
          "resolution_height": 720
        }
      ]
    }
  }
}
```

### Example: recording-failed.json
<a name="comp-rec-json-ex-rec-fail"></a>

```
{
  "version": "v1",
  "stage_arn": "arn:aws:ivs:ap-northeast-1:123456789012:stage/aAbBcCdDeE12",
  "recording_started_at": "2023-10-27T17:00:44Z",
  "recording_ended_at": "2023-10-27T17:08:24Z",
  "recording_status": "RECORDING_ENDED_WITH_FAILURE",
  "media": {
    "hls": {
      "duration_ms": 460315,
      "path": "media/hls",
      "playlist": "multivariant.m3u8",
      "renditions": [
        {
          "path": "720p30-abcdeABCDE12",
          "playlist": "playlist.m3u8",
          "resolution_width": 1280,
          "resolution_height": 720
        }
      ]
    },
    "thumbnails": {
      "path": "media/thumbnails",
      "resolutions": [
        {
          "path": "1280x720",
          "resolution_width": 1280,
          "resolution_height": 720
        }
      ]
    },
    "latest_thumbnail": {
      "path": "media/latest_thumbnail",
      "resolutions": [
        {
          "path": "1280x720",
          "resolution_width": 1280,
          "resolution_height": 720
        }
      ]
    }
  }
}
```

## Playback of Recorded Content from Private Buckets
<a name="comp-rec-playback"></a>

By default, the recorded content is private; hence, these objects are inaccessible for playback using the direct S3 URL. If you try to open the HLS multivariate playlist (m3u8 file) for playback using the IVS player or another player, you will get an error (e.g., “You do not have permission to access the requested resource”). Instead, you can play back these files with the Amazon CloudFront CDN (Content Delivery Network).

CloudFront distributions can be configured to serve content from private buckets. Typically this is preferable to having openly accessible buckets where reads bypass the controls offered by CloudFront. You can set up your distribution to be served from a private bucket by creating an origin access control (OAC), which is a special CloudFront user that has read permissions on the private origin bucket. You can create the OAC after you create your distribution, through the CloudFront console or API. See [Creating a new origin access control](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-restricting-access-to-s3.html#create-oac-overview-s3) in the *Amazon CloudFront Developer Guide*.

### Setting Up Playback using CloudFront with CORS Enabled
<a name="comp-rec-playback-setup"></a>

This example covers how a developer can set up a CloudFront distribution with CORS enabled, enabling playback of their recordings from any domain. This is especially useful during the development phase, but you can modify the example below to match your production needs.

#### Step 1: Create an S3 Bucket
<a name="comp-rec-playback-setup-step1"></a>

Create an S3 bucket that will be used to store the recordings. Note that the bucket needs to be in the same region that you use for your IVS workflow.

Add a permissive CORS policy to the bucket:

1. In the AWS console, go to the **S3 Bucket Permissions** tab.

1. Copy the CORS policy below and paste it under **Cross-origin resource sharing (CORS)**. This will enable CORS access on the S3 bucket.

   ```
   [
       {
           "AllowedHeaders": [
               "*"
           ],
           "AllowedMethods": [
               "PUT",
               "POST",
               "DELETE",
               "GET"
           ],
           "AllowedOrigins": [
               "*"
           ],
           "ExposeHeaders": [
               "x-amz-server-side-encryption",
               "x-amz-request-id",
               "x-amz-id-2"
           ]
       }
   ]
   ```

#### Step 2: Create a CloudFront Distribution
<a name="comp-rec-playback-setup-step2"></a>

See [ Creating a CloudFront distribution](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/distribution-web-creating-console.html) in the *CloudFront Developer Guide*.

Using the AWS console, enter the following information:


| For this field … | Choose this … | 
| --- | --- | 
| Origin Domain | The S3 bucket created in the previous step | 
| Origin Access | Origin access control settings (recommended), using default parameters | 
| Default cache behavior: Viewer Protocol Policy | Redirect HTTP to HTTPS | 
| Default cache behavior: Allowed HTTP methods | GET, HEAD and OPTIONS | 
| Default cache behavior: Cache key and origin requests | CachingDisabled policy | 
| Default cache behavior: Origin request policy | CORS-S3Origin | 
| Default cache behavior: Response headers policy | SimpleCORS | 
| Web Application Firewall | Enable security protections | 

Then save the CloudFront distribution.

#### Step 3: Set Up the S3 Bucket Policy
<a name="comp-rec-playback-setup-step3"></a>

1. Delete any StorageConfiguration that you have set up for the S3 bucket. This will remove any bucket policies that were automatically added when creating the policy for that bucket.

1. Go to your CloudFront Distribution, make sure all distribution fields are in the states defined in the previous step, and **Copy the Bucket Policy** (use the **Copy policy** button). 

1. Go to your S3 bucket. On the **Permissions** tab, select **Edit Bucket Policy** and paste the bucket policy that you copied in the previous step. After this step, the bucket policy should have the CloudFront policy exclusively. 

1. Create a StorageConfiguration, specifying the S3 bucket.

After the StorageConfiguration is created, you will see two items in the S3 bucket policy, one allowing CloudFront to read contents and another one allowing IVS to write contents. An example of a final bucket policy, with CloudFront and IVS access, is shown in [Example: S3 Bucket Policy with CloudFront and IVS Access](#comp-rec-playback-example).

#### Step 4: Play Back Recordings
<a name="comp-rec-playback-setup-step4"></a>

After you successfully set up the CloudFront distribution and update the bucket policy, you should be able to play back recordings using the IVS player:

1. Successfully start a Composition and make sure you have a recording stored on the S3 bucket.

1. After following the Step 1 through Step 3 in this example, the video files should be available for consumption through the CloudFront URL. Your CloudFront URL is the **Distribution domain name** on the **Details** tab in the Amazon CloudFront console. It should be something like this: 

   `a1b23cdef4ghij.cloudfront.net`

1. To play the recorded video through the CloudFront distribution, find the object key for your `multivariant.m3u8` file under the s3 bucket. It should be something like this:

   `FDew6Szq5iTt/9NIpWJHj0wPT/fjFKbylPb3k4/composite/media/hls/multivariant.m3u8`

1. Append the object key to the end of your CloudFront URL. Your final URL will be something like this:

   `https://a1b23cdef4ghij.cloudfront.net/FDew6Szq5iTt/9NIpWJHj0wPT/fjFKbylPb3k4/composite/media/hls/multivariant.m3u8`

1. You can now add the final URL to the source attribute of an IVS player to watch the full recording. To watch the recorded video, you can use the demo in [ Getting Started](https://docs.aws.amazon.com//ivs/latest/LowLatencyUserGuide/web-getting-started.html) in the *IVS Player SDK: Web Guide*.

### Example: S3 Bucket Policy with CloudFront and IVS Access
<a name="comp-rec-playback-example"></a>

The snippet below illustrates an S3 bucket policy that allows CloudFront to read content to the private bucket and IVS to write content to the bucket. **Note: Do not copy and paste the snippet below to your own bucket. Your policy should contain the IDs that are relevant to your CloudFront distribution and StorageConfiguration.**

------
#### [ JSON ]

****  

```
{
  "Version":"2012-10-17",		 	 	 
  "Statement": [
    {
      "Sid": "CompositeWrite-7eiKaIGkC9DO",
      "Effect": "Allow",
      "Principal": {
        "Service": "ivs-composite.ap-northeast-1.amazonaws.com"
      },
      "Action": [
        "s3:PutObject",
        "s3:PutObjectAcl"
      ],
      "Resource": "arn:aws:s3:::eicheane-test-1026-2-ivs-recordings/*",
      "Condition": {
        "StringEquals": {
          "s3:x-amz-acl": "bucket-owner-full-control"
        },
        "Bool": {
          "aws:SecureTransport": "true"
        }
      }
    },
    {
      "Sid": "AllowCloudFrontServicePrincipal",
      "Effect": "Allow",
      "Principal": {
        "Service": "cloudfront.amazonaws.com"
      },
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::eicheane-test-1026-2-ivs-recordings/*",
      "Condition": {
        "StringEquals": {
          "AWS:SourceArn": "arn:aws:cloudfront::844311324168:distribution/E1NG4YMW5MN25A"
        }
      }
    }
  ]
}
```

------

## Troubleshooting
<a name="comp-rec-troubleshooting"></a>
+ **The composition is not written to the S3 bucket —** Ensure that the S3 bucket and StorageConfiguration objects are created and in the same region. Also ensure that IVS has access to the bucket by checking your bucket policy; see [Bucket Policy for StorageConfiguration](#comp-rec-bucket-policy).
+ **I can’t find a composition when performing *ListCompositions* —** Compositions are ephemeral resources. Once they transition to a final state, they are deleted automatically after a few minutes.
+ **My composition stops automatically —** A composition will stop automatically if there is no publisher on the stage for more than 60 seconds.

## Known Issue
<a name="comp-rec-issues"></a>

The media playlist written by composite recording has the tag `#EXT-X-PLAYLIST-TYPE:EVENT` while the composition is ongoing. When composition is done, the tag is updated to `#EXT-X-PLAYLIST-TYPE:VOD`. For a smooth playback experience, we recommend that you use this playlist only after the composition finalizes successfully.