Skip to content

System Audio Recording

System audio recording lets you capture exactly what users hear, which is useful for apps like meeting recorders.

RecordKit supports two ways to record system audio: Core Audio and ScreenCaptureKit. By default, the most appropriate backend is selected, which works well for most setups, but you can also explicitly choose the backend when needed.

Record All System Audio

Recording all system audio is the simplest setup:

swift
let recorder = RKRecorder([
    .systemAudio()
])
try await recorder.start()
ts
const recorder = await recordkit.createRecorder({
  items: [
    {
      type: 'systemAudio'
    }
  ]
})
await recorder.start()

Prerequisite

Add NSAudioCaptureUsageDescription to your app's Info.plist. Without it, Core Audio system-audio recordings will be silent.

Choose a Backend

  • OS support: all macOS versions supported by RecordKit (macOS 13+)
  • Best fit: maximum compatibility with automatic fallback

This setting will use Core Audio on macOS 14.2+ and ScreenCaptureKit on older macOS versions.

swift
let recorder = RKRecorder([
    .systemAudio(backend: .default) // You can also omit the backend to use default
])
ts
// Omit backend to use RecordKit's default backend selection
const recorder = await recordkit.createRecorder({
  items: [
    {
      type: 'systemAudio'
    }
  ]
})

Core Audio

Core Audio has a friendlier flow where the user can grant system audio recording permissions with one click. This also ensures the user the app can't also capture the screen. It is supported on macOS 14.2+.

swift
let recorder = RKRecorder([
    .systemAudio(backend: .coreAudio)
])
ts
const recorder = await recordkit.createRecorder({
  items: [
    {
      type: 'systemAudio',
      backend: 'coreAudio'
    }
  ]
})

ScreenCaptureKit

ScreenCaptureKit is available from macOS 12.3+. It needs full screen recording permissions, those need to be granted manually by the user through the Settings app.

swift
let recorder = RKRecorder([
    .systemAudio(backend: .screenCaptureKit)
])
ts
const recorder = await recordkit.createRecorder({
  items: [
    {
      type: 'systemAudio',
      mode: 'exclude',
      backend: 'screenCaptureKit',
      excludeOptions: ['currentProcess']
    }
  ]
})

TIP

Apps that do both screen and system audio only recordings can consider using the ScreenCaptureKit backend to make sure the audio capturing behaviour is always consistent.

Permissions

Permissions differ by backend:

  • Core Audio backend: requires system audio capture permission and NSAudioCaptureUsageDescription in your app's Info.plist.
  • ScreenCaptureKit backend: requires Screen Recording permission.

Use backend-aware permission helpers so your app checks and requests the correct permission path. If you use .systemAudio() with the default backend, include NSAudioCaptureUsageDescription so fallback/backend selection stays safe.

swift
let backend: RKRecorder.SystemAudioBackend = .default

if !RKAuthorization.systemAudioRecording(backend: backend) {
    RKAuthorization.requestSystemAudioRecording(backend: backend)
}
ts
const backend = 'default' // 'default' | '_beta_coreAudio' | 'screenCaptureKit'

if (!(await recordkit.getSystemAudioRecordingAccess({ backend }))) {
  await recordkit.requestSystemAudioRecordingAccess({ backend })
}

Recording Modes

Record Everything

Use systemAudio() to record all system audio.

swift
let recorder = RKRecorder([
    .systemAudio()
])
ts
const recorder = await recordkit.createRecorder({
  items: [
    {
      type: 'systemAudio',
      mode: 'exclude',
      excludeOptions: ['currentProcess']
    }
  ]
})

Excluding Specific Apps

Use exclude mode to remove apps you do not want in the mix, for example Apple Music or Spotify.

swift
let apps = RKRunningApplication.applications()
let excluded = apps
    .filter { $0.bundleIdentifier == "com.apple.Music" || $0.bundleIdentifier == "com.spotify.client" }
    .map(\.id)

var options: Set<RKRecorder.SystemAudioExcludeOptions> = [.currentProcess]
options.formUnion(excluded.map { .processID($0) })

let recorder = RKRecorder([
    .systemAudio(excluding: options)
])
ts
const apps = await recordkit.getRunningApplications()
const excludedProcessIDs = apps
  .filter((app) => app.bundle_identifier === 'com.apple.Music' || app.bundle_identifier === 'com.spotify.client')
  .map((app) => app.id)

const recorder = await recordkit.createRecorder({
  items: [
    {
      type: 'systemAudio',
      mode: 'exclude',
      excludeOptions: ['currentProcess'],
      excludedProcessIDs
    }
  ]
})

Record Specific Apps

Use include mode when you want audio from selected apps only, for example Zoom.

swift
let apps = RKRunningApplication.applications()
let zoomIDs = apps
    .filter { $0.bundleIdentifier == "us.zoom.xos" }
    .map(\.id)

let recorder = RKRecorder([
    .systemAudio(includedApplicationIDs: zoomIDs)
])
ts
const apps = await recordkit.getRunningApplications()
const zoomIDs = apps
  .filter((app) => app.bundle_identifier === 'us.zoom.xos')
  .map((app) => app.id)

const recorder = await recordkit.createRecorder({
  items: [
    {
      type: 'systemAudio',
      mode: 'include',
      includedApplicationIDs: zoomIDs
    }
  ]
})

TIP

Some apps output audio from background processes. For supported browsers such as Safari and Chrome, RecordKit handles this process routing automatically.

Questions? Feel free to contact us at [email protected]