xcap: a Rust screen capture library with an honest support matrix
XCap is a cross-platform screen capture library written in Rust. It supports Linux (X11, Wayland), MacOS, and Windows. XCap supports screenshot and video recording (WIP).
At a glance
- What is it?
- XCap is a cross-platform screen capture library written in Rust, covering Linux on X11, macOS and Windows, for screenshots of monitors and windows, region capture and video recording. Its implementation status table is the most useful thing in the repository, because it marks Wayland capture as not fully supported and window recording everywhere as still to be developed.
- Who is it for?
- xcap suits a Rust developer who needs screenshots or screen recording in a desktop application and wants one API across X11, macOS and Windows rather than three platform-specific crates, since the Monitor and Window types give the same shape on each.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 59 days ago.
- What is it written in?
- Mainly Rust, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The support table is the documentation
The README's implementation status table is more informative than the feature list, and it should be the first thing you read.
| Feature | Linux(X11) | Linux(Wayland) | MacOS | Windows(>=Windows 8.1) | | Screen Capture | available | not fully supported | available | available | | Window Capture | available | not fully supported | available | available | | Screen Recording | available | not fully supported | available | available | | Window Recording | to be developed | to be developed | to be developed | to be developed |
The legend explains the middle state. A mark means the feature is available but not fully supported in some special scenarios, and a tools symbol means to be developed.
So three of the four capabilities work on X11, macOS and Windows, and the fourth, window recording, is marked as to be developed on every platform including macOS and Windows. The README says the same thing in prose: XCap supports screenshot and video recording (WIP).
The Wayland column is the one that will decide this for a Linux user. A mark there does not mean it never works, it means there are special scenarios it does not handle, and those are exactly the scenarios that produce a blank image or a stale frame. The way to know which ones is to read the source or test on the specific compositor.
The Cargo.toml description goes further than the README and adds HarmonyOS, described as OpenHarmony or OHOS, to the supported platforms, and the topic list names monitor, screen-capture, screen-record, windows and screencapture. That is a broader target list than the README's prose, and it is worth noticing that the table does not have a HarmonyOS column.
Monitor and Window are the two entry points
The API is built around two types, and the examples in the repository show how they are used.
Monitor::all() returns the list of attached monitors, and each monitor exposes capture_image(), width(), height(), friendly_name() and is_primary(). Window::all() does the same for windows, with title(), x(), y(), width(), height(), is_minimized() and is_maximized().
The screen capture example is the shortest of them.
use xcap::Monitor;
fn main() {
let start = Instant::now();
let monitors = Monitor::all().unwrap();
dir::create_all("target/monitors", true).unwrap();
for monitor in monitors {
let image = monitor.capture_image().unwrap();
image
.save(format!(
"target/monitors/monitor-{}.png",
normalized(monitor.friendly_name().unwrap())
))
.unwrap();
}
println!("运行耗时: {:?}", start.elapsed());
}The window capture example adds the check that matters most in practice, skipping minimised windows because they cannot be captured. The comment in the example says it in Chinese, 最小化的窗口不能截屏, and the code calls window.is_minimized().unwrap() and continues.
That single guard is the kind of detail that separates a library that works in a real desktop from one that returns a black rectangle for the window the user just minimised. If you are wrapping this library, the equivalent guard belongs in your wrapper too.
Region capture is a method on the monitor, not a separate type
The region capture example is worth looking at because it shows how a partial capture is expressed.
let monitor = monitors
.into_iter()
.find(|m| m.is_primary().unwrap_or(false))
.expect("No primary monitor found");
let region_width = 400u32;
let region_height = 300u32;
let x = ((monitor_width as i32) - (region_width as i32)) / 2;
let y = ((monitor_height as i32) - (region_height as i32)) / 2;
let image = monitor.capture_region(x, y, region_width, region_height)?;The region is defined in monitor coordinates, with the origin at the top left of that monitor, and the example computes a centred rectangle by subtracting the region size from the monitor size and dividing by two. The result is a separate image whose width and height are queried from the returned image object, so the returned type carries its own dimensions.
Notice that is_primary() returns a Result, and the example handles it with unwrap_or(false) inside a find, so a monitor that cannot report its primary status is skipped rather than panicking. That is a slightly different style from the .unwrap() used elsewhere in the same example, and it is the more careful of the two.
The examples/ directory in the repository holds the full set, with focused_window.rs, monitor.rs, monitor_capture.rs, monitor_record.rs, monitor_region_capture.rs, window.rs and window_capture.rs, so each capability has a small runnable file rather than one large demonstration.
Video recording is a recorder plus a frame channel
The screen record example shows an API shape that differs from the screenshot path, and it is the part most likely to change.
let monitor = Monitor::from_point(100, 100).unwrap();
let (video_recorder, sx) = monitor.video_recorder().unwrap();
thread::spawn(move || loop {
match sx.recv() {
Ok(frame) => {
println!("frame: {:?}", frame.width);
}
_ => continue,
}
});
video_recorder.start().unwrap();
thread::sleep(Duration::from_secs(2));
video_recorder.stop().unwrap();Two things are returned from video_recorder(): a video_recorder handle and a receiver, sx, which is a channel of frames. The recorder is started and stopped independently of the consumption of frames, so a caller can record for a period and read frames as they arrive on another thread.
The example starts and stops the recorder twice with sleeps in between, which is a deliberate demonstration that the same recorder can be restarted, and that stop does not end the process.
Monitor::from_point(100, 100) is the other API worth noting. It selects the monitor under a given screen coordinate, which is what you want when the user has clicked something and you want to record the display it is on, rather than always the primary.
The frame struct exposes a width field, and the example prints it. The README does not describe the frame type in detail, and given the WIP marking on recording in the feature list, the shape of that API is the part most likely to move.
System dependencies are the real install cost
There is no crates.io install line in the README, because a screen capture library needs system libraries before it will compile. The Linux requirements section lists the packages per distribution.
On Debian and Ubuntu:
apt-get install pkg-config libclang-dev libxcb1-dev libxrandr-dev libdbus-1-dev libpipewire-0.3-dev libwayland-dev libegl-devOn Alpine:
apk add pkgconf llvm19-dev clang19-dev libxcb-dev libxrandr-dev dbus-dev pipewire-dev wayland-dev mesa-devOn ArchLinux:
pacman -S base-devel clang libxcb libxrandr dbus libpipewireThe packages tell you what the library talks to. libxcb and libxrandr are the X11 client libraries, libwayland-dev and libegl-dev are the Wayland and OpenGL pieces, libpipewire is the screen capture protocol that PipeWire provides on modern Linux desktops, and libdbus is the session bus used to talk to the compositor.
PipeWire is the one to note. On a current GNOME or KDE desktop, the compositor's screen capture goes through PipeWire, and a library that only spoke the older X11 paths would fail on exactly the setups that are now the default. The dependency on libpipewire in the Debian list is the reason Wayland is partially supported rather than absent.
The Arch list is the shortest because it names the libraries without the -dev suffixes in the same way, and base-devel and clang cover the build tooling.
For a distribution build, these are the packages to put in the build image, and the reason a thin Dockerfile is not enough for a Rust screen capture tool.
Cargo features for the image crate and the Windows capture path
The Cargo.toml shows the feature design, and it is a sensible two-part split.
The image feature is declared as image = ["image/default"], and the image crate itself is a dependency with default-features = false and the png feature enabled, at version 0.25.
The wgc feature is the Windows one. It enables a list of windows crate features including Win32_Graphics_Gdi, Win32_Graphics_DirectX_Direct3D11, Win32_Graphics_Dxgi, Win32_Graphics_Direct3D, Win32_System_WinRT_Direct3D11 and Win32_System_WinRT_Graphics_Capture.
Graphics Capture, spelled wgc for Windows Graphics Capture, is the modern Windows screen capture API, and it is what replaced the older bitmap copy approach. The list also pulls in Direct3D 11 and DXGI, which are the graphics stack that API is built on, and the GDI features, which are the older fallback path. Enabling all of them together is what gives the Windows implementation both the modern capture path and the legacy one.
The macOS dependency list is nearly all objc2 crates, plus dispatch2: objc2 and objc2-foundation, objc2-core-foundation, objc2-core-graphics for the graphics APIs, objc2-core-media, objc2-core-video, objc2-av-foundation for the AVFoundation capture and recording stack, and objc2-app-kit for the window and application APIs.
The base dependencies are minimal: image, log at 0.4, scopeguard at 1.2 and thiserror at 2.0. scopeguard is there to release native handles when a capture fails partway, and thiserror is the error type library.
The package is version 0.9.8 on edition 2024, with resolver 3, and the workspace has a single member.
Editorial conclusion
xcap suits a Rust developer who needs screenshots or screen recording in a desktop application and wants one API across X11, macOS and Windows rather than three platform-specific crates, since the Monitor and Window types give the same shape on each. It is the wrong tool for a Wayland-only Linux environment, because the README's own table marks Linux on Wayland as not fully supported in some special scenarios, and it is the wrong choice for window recording, which is marked as to be developed on every platform. Before you build on it, decide whether the image feature flag matters to you, since the image crate is behind a Cargo feature and the Windows capture path is behind a wgc feature that enables the Graphics Capture and Direct3D stack.
Frequently asked questions
Which platforms does xcap support for screen capture?
Linux on X11, macOS and Windows 8.1 or later are marked as available for screen capture, window capture and screen recording. Linux on Wayland is marked as available but not fully supported in some special scenarios, and window recording is marked as to be developed on every platform.
How do I capture a screenshot of a region of the screen with xcap?
Call capture_region(x, y, region_width, region_height) on a Monitor, where the coordinates are relative to that monitor. The README's example centres a 400 by 300 rectangle on the primary monitor and saves the returned image.
What system packages does xcap need on Linux?
On Debian and Ubuntu, pkg-config, libclang-dev, libxcb1-dev, libxrandr-dev, libdbus-1-dev, libpipewire-0.3-dev, libwayland-dev and libegl-dev. The README lists equivalent packages for Alpine and ArchLinux.
How does xcap handle recording video?
monitor.video_recorder() returns a video recorder handle and a frame channel. You call start() and stop() on the recorder and read frames from the channel on another thread. The README marks video recording as work in progress.
What licence is xcap released under?
Apache-2.0, with the licence text in the LICENSE file. The Cargo.toml also lists the documentation at docs.rs/xcap and the homepage at github.com/nashaofu/xcap.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/nashaofu-xcap)Was this useful?