---
updatedAt: 2026-10-27T06:00:07.000Z
agentTools:
  projectIndex: https://docs.recall.ai/llms.txt
---

# Desktop Recording SDK Event Types

Learn which Desktop Recording SDK events fire and what each listener returns so your app can handle recording state changes and errors.

## Event Types

The Desktop Recording SDK monitors for a variety of different events that you'll be able to subscribe to in your application. Below is a comprehensive list of all events that are currently available:

<Table align={["left","left"]}>
  <thead>
    <tr>
      <th>
        EventType
      </th>

      <th>
        Definition
      </th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td>
        `permissions-granted`
      </td>

      <td>
        Triggered when the user has granted all the required permissions to start recording.
      </td>
    </tr>

    <tr>
      <td>
        `meeting-detected`
      </td>

      <td>
        Triggered when a meeting is found, either when a new one starts, or after the SDK initializes and there is a meeting already in progress.
      </td>
    </tr>

    <tr>
      <td>
        `recording-started`
      </td>

      <td>
        Triggered when a recording has started.
      </td>
    </tr>

    <tr>
      <td>
        `recording-ended`
      </td>

      <td>
        Triggered when a recording has stopped, due to the meeting ending, or calling `stopRecording`. This event might be emitted up to 5 minutes after the recording is stopped if there are parts of the recording still queued for upload. This does not mean the upload has finished. The SDK emits it after at most 5 minutes even if uploads are still pending. See [SDK Safe Shutdown and Recovery](https://docs.recall.ai/docs/dsdk-safe-shutdown).
      </td>
    </tr>

    <tr>
      <td>
        `meeting-closed`
      </td>

      <td>
        Triggered when a detected meeting has ended.
      </td>
    </tr>

    <tr>
      <td>
        `media-capture-status`
      </td>

      <td>
        Triggered when media capture has been interrupted or resumed. In some cases, the meeting window can't be captured, so only audio is received (for instance, when the meeting window is on an inactive virtual desktop).
      </td>
    </tr>

    <tr>
      <td>
        `participant-capture-status`
      </td>

      <td>
        Triggered when media capture for a participant has been interrupted or resumed. For example, when a user's video tile becomes no longer visible due to overcrowding in the meeting window, this event will be triggered to notify your code that that participant's video is not captured.
      </td>
    </tr>

    <tr>
      <td>
        `realtime-event`
      </td>

      <td>
        Triggered when real-time data is available, such as transcript information or participant join/leave events. Subscribe to real-time events with `startRecording` to receive these callbacks.
      </td>
    </tr>

    <tr>
      <td>
        `meeting-updated`
      </td>

      <td>
        Triggered when meeting information has updated (usually when `title` or `url` have become known)
      </td>
    </tr>

    <tr>
      <td>
        `error`:
      </td>

      <td>
        Triggered when the Desktop Recording SDK has encountered an error. Right now, the only type is `process`, which indicates that the SDK has exited unexpectedly or failed to start. The SDK automatically tries to restart in case of unexpected shutdown, so it's not necessary to initialize and set up callbacks again.
      </td>
    </tr>

    <tr>
      <td>
        `permission-status`
      </td>

      <td>
        Triggered on startup to indicate the current status of the required permissions. The permission will be one of `accessibility`, `screen-capture`, or `microphone`. Status will be one of:

        - `granted` - Indicates that the permission was successfully granted.
        - `not_requested` - A soft failure; the user has not yet been prompted for permission. The SDK is expected to display the permission dialog shortly.
        - `denied` - A hard failure; the end user has explicitly denied the permission request.
      </td>
    </tr>

    <tr>
      <td>
        `compliance-message-status`
      </td>

      <td>
        Triggered when the compliance message was sent, failed to send the message by the retry policy timeout, or cancelled due to recording being stopped before the message was sent. These three states are reflected in the status field of the event, with values `sent`, `timeout`, and `cancelled`.
      </td>
    </tr>

    <tr>
      <td>
        `network-status`
      </td>

      <td>
        Triggered to indicate the status of a user's network connection. The network status will be one of `disconnected`, `reconnected`.

        - `disconnected` - On macOS, the network has been down for 5 seconds. On Windows, emitted as soon as the network monitor detects connectivity loss.
        - `reconnected` - On macOS, the network has been back up for 5 seconds after a disconnect. On Windows, emitted as soon as the network monitor detects restored connectivity.

        If the network stays down for 2 minutes, active local recordings stop automatically. For [Raw Media](https://docs.recall.ai/docs/desktop-recording-sdk-raw-media) recordings the limit is 60 seconds. The timeout starts when connectivity loss is detected. On macOS, the 5-second `disconnected` notification delay is included in these times. Windows emits network status changes without a 5-second debounce.
      </td>
    </tr>

    <tr>
      <td>
        `shutdown`
      </td>

      <td>
        Triggered when the Desktop Recording SDK shuts down normally. See [SDK Safe Shutdown and Recovery](https://docs.recall.ai/docs/dsdk-safe-shutdown) for when it is safe to call `shutdown()`.
      </td>
    </tr>

    <tr>
      <td>
        `provider-error`
      </td>

      <td>
        Triggered when the Desktop RecordingSDK exhausts its connection attempts to the configured transcription provider. Includes the affected recording’s `window`, provider `class` (currently `transcription`), `provider` identifier, and optional `providerError.message` containing the last provider error.
      </td>
    </tr>

    <tr>
      <td>
        `log`
      </td>

      <td>
        Triggered when the native SDK emits a customer-visible log. Includes `level`, `message`, `subsystem`, `category`, and `window_id`. `window_id` is an empty string for SDK-wide messages.
      </td>
    </tr>
  </tbody>
</Table>

<br />

## Event Listeners

Event listeners give you back different events with different structures, here they are:

```javascript
RecallAiSdk.addEventListener("permissions-granted", async (evt) => {
  // The user has granted all the required permsisions to start recording
});

RecallAiSdk.addEventListener("meeting-detected", async (evt) => {
  const { window } = evt;
});

RecallAiSdk.addEventListener('recording-ended', async (evt) => {
  const { window } = evt;
});

RecallAiSdk.addEventListener('meeting-closed', async (evt) => {
  const { window } = evt;
});

RecallAiSdk.addEventListener('realtime-event', async (evt) => {
  const {window , type, status} = evt;
});

RecallAiSdk.addEventListener('recording-started', async (evt) => {
  const { window } = evt;
});

RecallAiSdk.addEventListener('meeting-updated', async (evt) => {
  const { window } = evt;
});

RecallAiSdk.addEventListener('media-capture-status', async (evt) => {
  const { window, type, capturing } = evt;
  // type is 'video' or 'audio'
  // capturing is a boolean indicating capture status
});

RecallAiSdk.addEventListener('participant-capture-status', async (evt) => {
  const { window, type, participantId, capturing } = evt;
  // type is 'video', 'audio', or 'screenshare'
  // capturing is a boolean indicating capture status
});

RecallAiSdk.addEventListener('error', async (evt) => {
  const { window, type, message } = evt;
  const windowId = window?.id;
});

RecallAiSdk.addEventListener('permission-status', async (evt) => {
  const { permission, status } = evt;
  // Permission type (e.g. 'microphone'), 
  // status ["granted", "not_requested", "denied"] 
  //   (see event listener docs below for more information)
});

RecallAiSdk.addEventListener('compliance-message-status', async (evt) => {
			const { window, status } = evt;
            // status is 'sent' or 'timeout' or "cancelled"
})

RecallAiSdk.addEventListener('network-status', async (evt) => {
    if (evt.status === 'disconnected') {
      // Connectivity loss detected (debounced by 5s on macOS)
    } else if (evt.status === 'reconnected') {
      // Connectivity restored (debounced by 5s on macOS)
    }
  });

RecallAiSdk.addEventListener('shutdown', async (evt) => {
  const { code, signal } = evt;
});

RecallAiSdk.addEventListener('provider-error', (evt) => {
  const { window, class: providerClass, provider, providerError } = evt;
  // providerClass is currently 'transcription'.
  // providerError is optional; its message format varies by provider.
  console.error(
    `Provider ${provider} failed for recording ${window.id}`,
    providerError?.message
  );
});

RecallAiSdk.addEventListener('log', (evt) => {
  const { level, message, subsystem, category, window_id } = evt;
  // level is 'debug', 'info', 'warning', or 'error'.
});
```