๐ผ Looking for a hosted desktop recording API? Check out Recall.ai โ an API for recording Zoom, Google Meet, Microsoft Teams, in-person meetings, and more.
https://github.com/user-attachments/assets/8a272c48-7ec3-4132-9111-4602b4fa991d
Highlights
- ๐ฅ Screen, window, and app capture with a clean builder-pattern API
- ๐ System audio + microphone capture (macOS 13.0+ / 15.0+)
- โก Real-time, zero-copy frame delivery via
IOSurface/ Metal - ๐ Async support that works with any executor (Tokio, async-std, smol, โฆ)
- ๐ธ Screenshots + direct-to-file recording (macOS 14.0+ / 15.0+)
- ๐ฑ๏ธ System content picker UI (macOS 14.0+)
- ๐ก๏ธ Memory safe โ proper retain/release, leak-tested
- ๐ฆ Zero runtime dependencies
Table of Contents
- Install ยท Quick Start ยท Recipes
- Feature Flags ยท Examples ยท Documentation
- Requirements & Permissions ยท Performance
- Troubleshooting ยท Migration ยท Contributing
Install
[]
= "2"
Opt-in features (additive):
| Feature | Enables |
|---|---|
async |
Runtime-agnostic async API (Tokio / async-std / smol / โฆ) |
macos_13_0 |
Audio capture, sync clock |
macos_14_0 |
Screenshots, content picker, content info |
macos_14_2 |
Menu bar capture, child windows, presenter overlay |
macos_14_4 |
Current-process shareable content |
macos_15_0 |
Recording output, HDR capture, microphone |
macos_15_2 |
Screenshot in rect, stream active/inactive delegates |
macos_26_0 |
Advanced screenshot config, HDR screenshot output |
macos_* features are cumulative โ enabling macos_15_0 automatically enables every earlier version. Pick the highest version your minimum-supported macOS will satisfy:
= { = "2", = ["async", "macos_15_0"] }
Upgrading from 1.x? See
docs/MIGRATION.mdโ the headline 2.0 changes are aSend + Syncbound on output / delegate traits,#[non_exhaustive]onPixelFormatandSCStreamErrorCode, and a newPixelFormat::Unknown(FourCharCode)variant.
Quick Start
A minimal screen capture in ~25 lines. Everything else builds on these four steps: (1) list shareable content, (2) build a content filter, (3) configure the stream, (4) add an output handler and start.
use *;
;
Output / delegate handlers must be
Send + Syncโ Apple's dispatch queues may invoke them concurrently from arbitrary threads.
Permission required โ see Requirements & Permissions.
Run it: cargo run --example 01_basic_capture.
Recipes
Short snippets for the most common follow-on tasks. Every recipe is a runnable
example in examples/ โ see the Examples table.
use *;
#
# use *;
#
Closures must be Fn + Send + Sync + 'static.
use ;
use *;
async
Requires the async feature. Works with Tokio, async-std, smol, or any
custom executor โ the binding does not spawn its own runtime.
#
#
use *;
use *;
let config = new;
show;
For async contexts, use AsyncSCContentSharingPicker::show.
See examples/10_recording_output.rs โ it
covers SCRecordingOutput, SCRecordingOutputConfiguration, and the
delegate callbacks for start / finish / error.
use *;
use ;
#
QoS levels: Background, Utility, Default, UserInitiated, UserInteractive (Quality of Service).
use *;
;
Built-in Metal helpers live in screencapturekit::metal and ship a small
shader library (SHADER_SOURCE) covering BGRA, YCbCr, and UI overlay
rendering. See examples/16_full_metal_app/
for a complete app and examples/18_wgpu_integration.rs
for the wgpu equivalent.
Examples
23 runnable examples cover every API surface. The full table with feature
requirements lives in examples/README.md. A few
favourites to start with:
| Example | What it shows |
|---|---|
01_basic_capture |
Minimal screen capture โ start here |
08_async |
Async API, picker, runtime-agnostic patterns |
09_closure_handlers |
Closures + delegate callbacks |
10_recording_output |
Direct-to-file recording (macOS 15.0+) |
11_content_picker |
System picker UI (macOS 14.0+) |
16_full_metal_app/ |
Full Metal viewer app (macOS 14.0+) |
18_wgpu_integration |
Zero-copy wgpu integration |
19_ffmpeg_encoding |
Real-time H.264 via ffmpeg |
24_batched_apis_showcase |
Batched FFI vs per-element (perf) |
Feature Flags
See the full feature table under Install. One small example of gating version-specific options:
let mut config = new.with_width.with_height;
Documentation
| Where | What |
|---|---|
| docs.rs | Full API reference |
docs/MIGRATION.md |
Upgrading between major versions |
docs/BENCHMARKS.md |
Benchmark methodology + results |
examples/README.md |
All 23 examples + feature requirements |
CHANGELOG.md |
Release notes |
Requirements & Permissions
- macOS 12.3+ (Monterey) โ base
ScreenCaptureKit - macOS 13.0+ โ audio capture ยท 14.0+ โ picker / screenshots ยท 15.0+ โ recording / HDR / mic ยท 26.0+ โ advanced screenshots
- Xcode Command Line Tools at build time (
xcode-select --install)
Screen capture always requires user permission. To grant it:
- System Settings โ Privacy & Security โ Screen Recording
- Enable your binary (during development this is usually your terminal or IDE)
- Restart the app
For distribution, add a purpose string to Info.plist โ the user-facing
TCC prompt requires it and the app will be terminated without one:
NSScreenCaptureUsageDescription
Capture your screen so the app can โฆ
ScreenCaptureKit is purely TCC-gated: there is no code-signing
entitlement that grants screen capture access. Capture is allowed solely
when the user enables your binary under System Settings โ Privacy &
Security โ Screen & System Audio Recording.
| App type | What you need |
|---|---|
| Any signed macOS app (sandboxed or not) | NSScreenCaptureUsageDescription in Info.plist + user TCC grant |
| Sandboxed app | Additionally com.apple.security.app-sandbox = true in Entitlements.plist โ this only turns the sandbox on; it does not grant capture |
| Sandboxed app capturing system audio (macOS 13+) | Optionally com.apple.security.device.audio-input = true |
There is no
com.apple.security.screen-captureentitlement. That key isn't part of Apple's security-entitlements reference; the onlycom.apple.security.device.*keys arecamera,microphone,audio-input,usb, andbluetooth. The two real screen-capture entitlements (com.apple.developer.screen-capture.include-passthroughandcom.apple.developer.protected-content) are Enterprise / visionOS managed entitlements and don't apply toScreenCaptureKiton macOS.
Performance
Full capture (60 fps + 48 kHz stereo) costs ~1.9% of one core end-to-end
on Apple Silicon โ the binding itself is below the noise floor of a 4 kHz
sampling profiler; nearly all CPU lives in Apple's SkyLight /
libdispatch / libxpc pipeline.
| Resolution | Expected FPS | First-frame latency |
|---|---|---|
| 1080p | 30โ60 | 30โ100 ms |
| 4K | 15โ30 | 50โ150 ms |
Hot-path tips:
- Prefer
BGRAto skip the per-pixel RโB swap when uploading to Metal / wgpu / ffmpeg (SCScreenshotManager::bgra_datais ~5% faster thanrgba_data). - Reuse a
Vec<u8>across screenshots with the*_data_intovariants (saves a ~33 MB allocation per 4K frame โ new in 2.1). - When iterating many windows / displays / apps, use the batched
SCShareableContent::snapshot()API โ collapses1 + N + 6NFFI calls into one round-trip per category (~2ร faster on a typical desktop). - Read every
SCStreamFrameInfoattachment in one cast viaCMSampleBuffer::frame_info().
use *;
use ContentSnapshot;
#
Run benchmarks on your hardware:
See docs/BENCHMARKS.md for methodology, throughput
numbers at various resolutions, and tuning guidance.
Troubleshooting
| Symptom | Likely cause / fix |
|---|---|
SCShareableContent::get() returns empty / errors |
Missing Screen Recording permission โ grant it in System Settings, then restart |
| Black / empty frames | Captured window minimized; pixel format mismatch; filter doesn't include the right display/window |
| No audio samples | Did you set .with_captures_audio(true) and add a handler for SCStreamOutputType::Audio? |
| Build fails with Swift bridge errors | xcode-select --install; then cargo clean && cargo build |
| App crashes after notarization | Missing NSScreenCaptureUsageDescription in Info.plist โ the system terminates apps that trigger the Screen Recording TCC prompt without one (see Requirements) |
match on PixelFormat / SCStreamErrorCode no longer compiles |
Both are #[non_exhaustive] in 2.0 โ add a wildcard _ => โฆ arm |
Migration
Upgrading? See docs/MIGRATION.md for the full guide.
The 2.0 highlights:
SCStreamOutputTrait/SCStreamDelegateTrait(and closure overloads) now requireSend + SyncPixelFormatis#[non_exhaustive]and gainedUnknown(FourCharCode)for forward-compat with future Apple pixel formatsSCStreamErrorCodeis#[non_exhaustive]PixelFormat'sPartialEq/Hashare normalised throughFourCharCode- Every
macos_*Cargo feature now propagates to the Swift bridge build (the build fails loudly on SDK detection failure rather than silently dropping symbols)
2.1 added the bgra_data_into / rgba_data_into buffer-reuse APIs and a
native-BGRA fast path on SCScreenshotManager โ both are non-breaking.
Contributing
Contributions welcome! Please:
- Follow existing patterns โ builder pattern with
::new()and.with_*() - Add tests for new functionality
cargo fmt && cargo clippy --all-features -- -D warnings && cargo test- Update docs and
CHANGELOG.md
See CLAUDE.md / AGENTS.md for the project conventions agents follow.
Used By
Powering 50+ open-source projects across screen recording, AI agents, meeting transcription, and remote desktop. A few highlights:
- AFFiNE โ knowledge base, Notion / Miro alternative (68k+ โญ)
- voicebox โ open-source AI voice studio (25k+ โญ)
- Cap โ open-source Loom alternative (19k+ โญ)
- Observer โ local AI screen observer (1.4k+ โญ)
- my-translator โ real-time speech translation (1k+ โญ)
- hylarana โ cross-platform screen casting in Rust
- gst-screencapturekit โ
GStreamerplugin - open-agent, watson.ai, harana/search, agent-native by Builder.io
fl_caption, Lycoris, Hindsight, kivio, Drift, Phantom, ruhear, Tab5-Screen-Streamer, macloop, beer, phantom-ear, Logia, VibeTube, silly-ai, aresampler, xos, scriberr-desktop, echonote, zest-wallpaper, mira, overlay-ai, open-rec, omnirec, oxiremote, LocalWhisper, Hush, cocuyo, openhush, tucknotes, domino, bridge, screen-recorder, orbit, audio-capture, AFFiNE-teto, loom.
Using screencapturekit-rs? Open an issue and we'll add you.
Contributors
Thanks to everyone who has contributed!
Per Johansson (maintainer) ยท Iason Paraskevopoulos ยท Kris Krolak ยท Tokuhiro Matsuno ยท Pranav Joglekar ยท Alex Jiao ยท Charles ยท bigduu ยท Andrew N
License
Licensed under either of Apache-2.0 or MIT at your option.