💼 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 NSScreenCaptureUsageDescription to Info.plist and the
appropriate entitlements:
com.apple.security.app-sandbox
com.apple.security.screen-capture
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 | Add the screen-capture entitlement (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.