---
description: Learn how to create a recording app using RealtimeKit's SDKs. Follow our guide for effective app creation and integration.
title: Create Custom Recording App Using Recording SDKs
image: https://developers.cloudflare.com/og-docs.png
---

[Skip to content](#main-content)

> Documentation Index  
> Fetch the complete documentation index at: https://developers.cloudflare.com/realtime/llms.txt  
> Use this file to discover all available pages before exploring further.

# Create Custom Recording App Using Recording SDKs

Last updated Aug 24, 2026|Copy as Markdown|[View as Markdown](https://docs-durable-objects-instance-replaced-errors.previews.developers.cloudflare.com/realtime/realtimekit/recording-guide/create-record-app-using-sdks/index.md)|[Agent setup](https://docs-durable-objects-instance-replaced-errors.previews.developers.cloudflare.com/agent-setup/)

When you join a RealtimeKit meeting, the meeting layout is automatically designed to optimize your experience. This includes focusing on shared content and highlighting active speakers, while participants are shown in small thumbnail views. When you start recording the meeting, it is recorded with the same layout using the default UI kit component called [RtkGrid ↗](https://docs.realtime.cloudflare.com/react-ui-kit/components/rtk-grid).

If you wish to have a customized layout for your recording application, RealtimeKit's custom recording SDKs provide the flexibility to tailor the appearance of your recordings according to your preferences. You can choose from options like:

* Show only active speaker view
* Shared screen with thumbnail gallery view
* Shared screen with large active speaker thumbnail
* Shared screen without active speaker or gallery view
* Customized background for your recording
* Portrait layout, and so on and so forth

## How the recorder works

When you call [Start Recording](https://docs-durable-objects-instance-replaced-errors.previews.developers.cloudflare.com/api/resources/realtime%5Fkit/subresources/recordings/methods/start%5Frecordings/), RealtimeKit launches a Cloudflare container, opens a Chrome browser inside it, and loads the recording app URL. If you do not provide a custom URL in the [url parameter](https://docs-durable-objects-instance-replaced-errors.previews.developers.cloudflare.com/api/resources/realtime%5Fkit/subresources/recordings/methods/start%5Frecordings/), RealtimeKit's internal recording app is used.

### URL parameters

Before loading your custom recording app in the Chrome browser, RealtimeKit appends the `authToken` and `config` query parameters to the URL. For example, if you provide this URL in the [Start Recording](https://docs-durable-objects-instance-replaced-errors.previews.developers.cloudflare.com/api/resources/realtime%5Fkit/subresources/recordings/methods/start%5Frecordings/) API:

```txt
https://example.com/my-custom-recorder
```

RealtimeKit loads the app with the following parameters:

```txt
https://example.com/my-custom-recorder?authToken=AUTH_TOKEN_CREATED_BY_REALTIMEKIT&config=CONFIG_CREATED_BY_REALTIMEKIT
```

The placeholder values represent parameters supplied by RealtimeKit. Do not add `authToken` or `config` yourself to the URL submitted to the Start Recording API. Your app must read both parameters from the URL.

### Auth token

RealtimeKit generates the `authToken` automatically for the meeting whose recording you start. It generates this token with the `recorder_preset_v2` preset. If you have not created a `recorder_preset_v2` preset, RealtimeKit uses a global preset with the same name that is managed by RealtimeKit and is not visible in your account.

Your custom recording app **must** accept this `authToken` and use it to initialize the RealtimeKit SDK to get `meeting` object.

### Config parameter

Any configuration that you provide in the Start Recording API, such as watermark settings, is passed to the recording app through the `config` query parameter. The default recording app reads and applies this configuration automatically.

If you use a custom recording app, you are responsible for reading and applying `config`. Whatever your app produces in the browser is recorded as-is. RealtimeKit does not apply any additional layout, watermark, or other processing to the output of a custom recording app.

### Recording preset flags

The `hidden_participant` flag controls only the recorder's visibility. When enabled, it hides the recorder from other participants in the meeting.

The `is_recorder` flag identifies the participant as a recorder and ensures that recording works correctly. If you create a custom `recorder_preset_v2` preset to customize colors or the look and feel of the recording, you must keep `is_recorder` enabled. Removing `is_recorder` can cause the recording to fail. Removing `hidden_participant` can cause the recorder to be visible to other participants.

### Local testing

Local testing lets you view the recording app UI. Opening the recording app URL directly on your local machine does not start a recording.

For local testing only, create any preset with `hidden_participant: true`, then pass an auth token created with that preset in the `authToken` query parameter when you open the local recording app URL. This lets you see the look and feel of the recorder UI. Do not include a local testing token as the `authToken` in the URL submitted to the Start Recording API. In an actual recording, RealtimeKit generates and passes the recorder token automatically.

To speed up development, use a [Cloudflare Tunnel](https://docs-durable-objects-instance-replaced-errors.previews.developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/do-more-with-tunnels/trycloudflare/) to expose your local recording app. For example, if your app is running on port `1111`, start a [Quick Tunnel](https://docs-durable-objects-instance-replaced-errors.previews.developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/do-more-with-tunnels/trycloudflare/) with:

```sh
cloudflared tunnel --url http://localhost:1111
```

Replace `1111` with the port used by your local app. `cloudflared` prints a public `trycloudflare.com` URL. You can use this URL as the custom recording app URL when starting a recording, so the Cloudflare container can load your local app.

You might see a WebSocket error in the browser console while testing locally because your browser cannot connect to `localhost:8080`. You can ignore this error during local testing. The recorder runs with this port inside the hosting Cloudflare container, and the WebSocket connection is how the recording app tells the container to record the rendered webpage.

### Examples

Refer to the [recording SDK app examples ↗](https://github.com/cloudflare/realtimekit-web-examples/tree/main/recording-sdk-app-examples) for sample implementations, including a [recording with watermark example ↗](https://github.com/cloudflare/realtimekit-web-examples/tree/main/recording-sdk-app-examples/react-examples/recording-with-watermark).

## Recording SDK reference

The custom recording SDKs are used on top of the [UI Kit](https://docs-durable-objects-instance-replaced-errors.previews.developers.cloudflare.com/realtime/realtimekit/ui-kit/) or [Core SDK](https://docs-durable-objects-instance-replaced-errors.previews.developers.cloudflare.com/realtime/realtimekit/core/). The [@cloudflare/realtimekit-recording-sdk package ↗](https://www.npmjs.com/package/@cloudflare/realtimekit-recording-sdk) provides the `RealtimeKitRecording` class for managing recording functionality.

### Constructor

`constructor(options)`

Creates an instance of the `RealtimeKitRecording` class.

#### Constructor parameters

`options (object)`: The options object. All constructor options are optional. If you omit an option, RealtimeKit uses its default value.

| **options (object)**          | **Description**                                                                                                                                                                                                                                                                                                                      |
| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| options.waitTimeMs (number)   | The time (in milliseconds) to wait after all peers have left before stopping the recording. This option applies when autoStop is set to true.                                                                                                                                                                                        |
| options.autoStart (boolean)   | Defaults to true, so recording starts automatically when init() is called. Set it to false only when you want to start recording manually with startRecording(). When set to false, you must call startRecording() within 2 minutes of the WebSocket connection being established, or the recording process will encounter an error. |
| options.autoStop (boolean)    | Defaults to true, so recording stops automatically after all peers have left. Set it to false only when you want to stop recording manually with stopRecording().                                                                                                                                                                    |
| options.scanInterval (number) | The interval (in milliseconds) between scans for automatic peer leave.                                                                                                                                                                                                                                                               |
| options.devMode (boolean)     | Set to true to enable development mode, which enables logs and disables certain functionality. Also you must ensure that this is set this to true when testing your recording-app locally.                                                                                                                                           |

### Methods

```js
init(client: RealtimeKitClient)
```

Initiates the SDK by providing a `RealtimeKitClient` object. Call this after creating the meeting object and before calling `meeting.joinRoom()`.

```js
startRecording();
```

In most cases, leave `autoStart` set to `true` (the default) so the recording starts automatically. To start the recording manually, set `autoStart` to `false` in the constructor options before calling this method.

```js
stopRecording();
```

You usually do not need to call this method because `autoStop` defaults to `true`. To stop the recording manually, set `autoStop` to `false` in the constructor options before calling this method.

```js
cleanup();
```

Performs cleanup tasks after leaving the meeting, such as clearing added listeners and closing WebSocket connections.

## Create a custom recording app

Perform the following steps to create the recording app for your RealtimeKit meetings.

### Step 1: Install the SDK

```js
npm i @cloudflare/realtimekit-recording-sdk
```

### Step 2: Import the `RealtimeKitRecording` object

```js
import { RealtimeKitRecording } from "@cloudflare/realtimekit-recording-sdk";
```

### Step 3: Create the `RealtimeKitRecording` object

```js
const recordingSdk = new RealtimeKitRecording(options);
```

### Step 4: Initialize the recording SDK

Call `init` after creating the meeting object and before `joinRoom` is called.

```js
// Call this after you have initialized the RealtimeKit SDK and have the meeting object
await recordingSdk.init(meeting);
```

### (Optional) Step 5: Manually start the recording

To manually start the recording, set `autoStart` to `false` in the `RealtimeKitRecording` constructor options. Then call `startRecording()` after you have loaded your UI content and are ready to begin recording.

```js
await recordingSdk.startRecording();
```

### (Optional) Step 6: Manually stop the recording

To manually stop the recording, set `autoStop` to `false` in the `RealtimeKitRecording` constructor options. Then call `stopRecording()` when you are ready to stop recording.

```js
await recordingSdk.stopRecording();
```

Once `stopRecording` is called, the recorder in your recording app will exit after a few seconds. After this point, you won't be able to perform any further actions within your recording app.

### Step 7: Deploy the recording app

Once you've created the app, deploy it using a platform like [Cloudflare Workers ↗](https://cloudflare.com/workers). Make sure to note the URL where you have deployed the app, as you will have to enter this URL in RealtimeKit's recording API.

### Step 8: Specify the custom URL

In the [Start Recording a Meeting](https://docs-durable-objects-instance-replaced-errors.previews.developers.cloudflare.com/api/resources/realtime%5Fkit/subresources/recordings/methods/start%5Frecordings/) API, provide the custom URL (obtained from the previous step) to indicate the location of your deployed app. Do not append an `authToken` to this URL. RealtimeKit adds the generated `authToken` and `config` parameters when it loads the app.

Was this helpful?

YesNo

## On this page

[![](https://docs-durable-objects-instance-replaced-errors.previews.developers.cloudflare.com/_astro/logo.te5VL_aD.svg)Docs](https://docs-durable-objects-instance-replaced-errors.previews.developers.cloudflare.com/)

```json
{"@context":"https://schema.org","@type":"TechArticle","@id":"https://developers.cloudflare.com/realtime/realtimekit/recording-guide/create-record-app-using-sdks/#page","headline":"Create Custom Recording App Using Recording SDKs · Cloudflare Realtime docs","description":"Learn how to create a recording app using RealtimeKit's SDKs. Follow our guide for effective app creation and integration.","url":"https://developers.cloudflare.com/realtime/realtimekit/recording-guide/create-record-app-using-sdks/","inLanguage":"en","image":"https://developers.cloudflare.com/og-docs.png","dateModified":"2026-08-24","publisher":{"@type":"Organization","name":"Cloudflare","description":"One platform for your apps, agents, and workforce. Build, secure, and scale without managing infrastructure","url":"https://www.cloudflare.com/","sameAs":["https://github.com/cloudflare","https://www.linkedin.com/company/cloudflare","https://x.com/cloudflare"],"logo":{"@type":"ImageObject","url":"https://developers.cloudflare.com/logo.svg"},"address":{"@type":"PostalAddress","streetAddress":"101 Townsend St","addressLocality":"San Francisco","addressRegion":"CA","postalCode":"94107","addressCountry":"US"},"contactPoint":[{"@type":"ContactPoint","contactType":"Customer Support","url":"https://support.cloudflare.com/","availableLanguage":["English"]},{"@type":"ContactPoint","contactType":"Sales","url":"https://www.cloudflare.com/contact/","availableLanguage":["English"]}]},"isPartOf":{"@type":"WebSite","@id":"https://developers.cloudflare.com/#website","name":"Cloudflare Docs","url":"https://developers.cloudflare.com/"}}
```
