Our API gives you the option to add video call recording to your meetings. For many of our API customers, recording is critical to their use case. You can read more about recording in our developer docs.

For developers and product teams with more advanced recording needs, we’ve released a new option. That is: server-side recording that allows developers to manage individual media tracks.

  • If you are using this new server-side recording feature, Chrome is no longer required. Recording is supported on Chrome, Safari, iOS Safari and Android Chrome.
  • If you are not using rtp-tracks, Chrome is still required for recording.

We wrote the first section below for both developers and non-technical readers. If you’re a developer looking for sample code, jump to the implementation section.

Which recording feature should your team use?

We now offer a couple options: (1) our drop-in recording feature and (2) server-side recording.

Please keep in mind any kind of recording, with the API, requires you to upgrade your API plan. See our API pricing.

Option 1

Because our goal is to make integrating video calls as easy as possible, the Daily API has a quick option to turn on recording.

Once you’ve upgraded, simply enable recording using the enable_recording configuration property, with a meeting token. Please see our docs for more details.

  • Recording is part of the video chat widget UI
  • With this simple approach, users do have to use Chrome to record
  • You can save recordings locally or to the cloud

Option 2

We now have added the second option of server-side recording. This means a local client is not involved in compositing the recording:

  • Developers can manage individual media tracks
  • Chrome is not required if you are using rtp-tracks as described below. Sessions can be recorded from Chrome, Safari, iOS Safari and Android Chrome.
  • Compositing is currently in beta

Server-side recording is great for use cases like:

  • High-quality audio transcription
  • Media production (podcasts and video blogs)
  • Recording meetings that include mobile devices — mobile devices often aren't powerful enough to record and composite locally

The rest of this post is rather detailed, and geared towards engineers. If you have any questions about our recording offering, just reach out.

Developers: how to implement server-side recording

Note: Please note compositing is currently in beta.

  1. Create a room with enable_recording property set to rtp-tracks
  2. Start a recording using the front-end library's startRecording() method
  3. Stop the recording using the front-end library's stopRecording() method
  4. Get info for the recording, from the REST API /recordings endpoint
  5. Create a compositing "recipe" using the track ids from the recording info struct, and POST the recipe to /recordings/:recording_id/composites REST API endpoint
  6. Get info for the new composited video from the REST API /recordings/:recording_id/composites
  7. Download the recording via the download_url in the composited video's info struct

1. Create a room set to record

To get started you will want to create a room set to record, using the new rtp-tracks recording type. Here's an example:

curl -H "Content-Type: application/json" -H "Authorization: Bearer $API_KEY" -d '{"properties":{"enable_recording":"rtp-tracks"}}' 'https://api.daily.co/v1/rooms)'

You can also set the enable_recording property to rtp-tracks on an existing room.

2. Use the daily-js front-end library to start and stop recording

To start and stop a recording you'll want to use the following instance methods: startRecording() and stopRecording(). Check out our front-end docs for more details.

3. Get the recording's track info

Here's how you can get the info struct for the latest recording from a specific room:

curl -H "Content-Type: application/json" -H "Authorization: Bearer $API_KEY" 'https://api.daily.co/v1/recordings/?room_name=qz2gz0IkrwPUtGjwx41h&limit=1'

Please note that the info struct will be available a few seconds after the recording starts, but status will be set to in-progress and the tracks array will be empty. The tracks array will be populated about 30 seconds after the recording is stopped.

Example struct:

  "total_count": 3,
  "data": [
      "id": "cb4f904e-9a4c-4603-8b87-1489b84e6d6f",
      "room_name": "qz2gz0IkrwPUtGjwx41h",
      "start_ts": 1574041799,
      "status": "finished",
      "max_participants": 1,
      "duration": 26,
      "share_token": "gBhvoLgc0nsn",
      "tracks": [
          "id": "254829fb-9031-4ed5-d5db-536013e49581",
          "download_url": "/v1/recordings/cb4f904e-9a4c-4603-8b87-1489b84e6d6f/track/254829fb-9031-4ed5-d5db-536013e49581.webm",
          "size": 104262,
          "track_start_ts": "1574041800.133000",
          "track_end_ts": "1574041824.573000",
          "duration": 24.44000005722046,
          "resolution": "",
          "session_id": "e6269475-0058-4aeb-f984-a12f44537d03",
          "media_tag": "cam-audio",
          "type": "audio",
          "user_name": "Test User Name",
          "user_id": ""
          "id": "cbd4e7fa-eecd-4297-d676-6ce379afafa2",
          "download_url": "/v1/recordings/cb4f904e-9a4c-4603-8b87-1489b84e6d6f/track/cbd4e7fa-eecd-4297-d676-6ce379afafa2.webm",
          "size": 1897322,
          "track_start_ts": "1574041800.144000",
          "track_end_ts": "1574041824.463000",
          "duration": 24.319000005722046,
          "resolution": "1280x720",
          "session_id": "e6269475-0058-4aeb-f984-a12f44537d03",
          "media_tag": "cam-video",
          "type": "video",
          "user_name": "Test User Name",
          "user_id": ""

5. Create a "recipe" for a composited video (beta)

Using the information about the recording's tracks, you can create a json data structure that describes which tracks to include in the composited video and how to size and position the video tracks.

Here's an example recipe:

  "composite_mode": "tracks-layout",
  "size": "1280x720",
  "tracks": [
    { "id": "df12a81d-2be5-49d5-97d5-c7d5de00d794" },
      "id": "1b0956df-67c6-4f37-ee59-fe3ad7cc7909",
      "size": "1280x720",
      "position": "0x0"

Required fields

  • composite_mode must be set to tracks-layout
  • size is the size (resolution) of the video you are creating. It must be a string in the format "WIDTHxHEIGHT"
  • tracks is a list of tracks to include in the video. Audio tracks are easy — just give the track id. Video tracks require an id, size, and position.
    • size is the size, in pixels, to scale this video track to. Note that you'll need to make sure you give a size that doesn't distort the video's aspect ratio (which means you'll need to use the resolution values from the track info).
    • position is where to place the video track within the overall video canvas. Specify this as the top, left corner of this track, relative to the top/left of the of the canvas.

Optional fields

  • title the new video's "title" metadata
  • duration create a new video this many seconds long. This is useful for doing quick trial-runs of recipes.
  • background_color set the background color to something other than black. See here for color options: https://ffmpeg.org/ffmpeg-utils.html#Color

Example POSTing of a recipe

This curl command POSTs a json recipe from the file comp-recipe.json in the current directory.

curl -H "Content-Type: application/json" -H "Authorization: Bearer $API_KEY" --data "@comp-recipe.json"  .     'https://api.daily.co/v1/recordings/3ab6318e-bd2d-4d9d-837a-a3a36ae7b58b/composites'

The API endpoint returns a composite video id:

  "status": "in-progress",
  "id": "500856c9-5d52-427f-cdf9-56fc0fd2d483"

One composite allowed per room

Please note that you are allowed to have only one compositing process happening at a time for each room.

If you try to start another compositing process for room, without letting the previous one finish, you'll get an API response that looks like this:

  "error": "invalid-request-error",
  "info": "another compositing process is already running"

The compositing happens faster than real-time, but can still take several minutes per video.

Also, we only save one composited video per room. If you run the compositing process again, your new video will overwrite the previous one.

6. Getting results and errors of the most recent compositor run

When the compositing process is finished, information about the most recent video is available from the /recordings/:recording_id/composites API endpoint.

Running this curl command …

curl -H "Content-Type: application/json" -H "Authorization: Bearer $API_KEY" 'https://api.daily.co/v1/recordings/3ab6318e-bd2d-4d9d-837a-a3a36ae7b58b/composites'

… gives this output:

  "newest_composite": {
  "id": "500856c9-5d52-427f-cdf9-56fc0fd2d483",
  "upload_ts": "2019-11-18T02:21:24.000Z",
  "download_url": "/v1/recordings/3ab6318e-bd2d-4d9d-837a-a3a36ae7b58b/composites/500856c9-5d52-427f-cdf9-56fc0fd2d483.mp4"
  "current_error": null

If an error had happened during the most recent compositor run, the current_error field will include as much information as we have about the error (in the form of a multi-line string of text).

7. Download the recording

Use the download_url to fetch the video file:

curl -L -H "Authorization: Bearer $API_KEY" 'https://api.daily.co/v1/recordings/3ab6318e-bd2d-4d9d-837a-a3a36ae7b58b/composites/00856c9-5d52-427f-cdf9-56fc0fd2d483.mp4' > video.mp4

As mentioned at the top of the post, Compositing is currently in beta. We are eager to learn from developers using our API. If you encounter any bugs, or simply have some questions, just contact us. We do our best to respond as swiftly as possible! Thanks for reading.

Photo by Florian Krumm on Unsplash