Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.
wlr-shot
Screen capture for wlroots and derivatives, built on the shared
wlr-capture engine (ext-image-copy-capture-v1, correct
strides, occlusion-independent).
It captures an output, the whole layout, a region (interactive -s or -g/slurp),
or a window — as a screenshot (PNG, JPEG, PPM or PAM) or a recording: H.264 video,
timelapse, or an animated GIF/WebP.
Install
Want the whole suite? Install the bundle instead —
cargo install wlr-utilsgets every tool (wlr-chooser,wlr-switcher,wlr-overlayd,wlr-peek,wlr-shot,wlr-draw) in one go. The single-tool install below is the lighter, à-la-carte option.
Building needs the Rust the main README names, and on
Debian/Ubuntu build-essential pkg-config clang libwayland-dev libxkbcommon-dev libgbm-dev libavcodec-dev libavformat-dev libavutil-dev libavfilter-dev libavdevice-dev libswscale-dev libswresample-dev libva-dev libpipewire-0.3-dev (Arch: base-devel clang wayland libxkbcommon mesa ffmpeg libva libpipewire).
Or build just this binary from the wlr-utils workspace:
The FFmpeg and PipeWire packages are for record. A screenshots-only binary needs none of
them: cargo build -p wlr-shot --no-default-features --features i18n. Recording without
sound drops PipeWire alone: --no-default-features --features i18n,video,gpu.
Requirements
Works on — screens and regions on every compositor that captures screens (sway,
Hyprland, niri, labwc, Wayfire, river, dwl, cosmic-comp); windows (-w, --app-id,
--title, --pick-window) where windows can be captured (Sway ≥ 1.12, Hyprland ≥ 0.54,
river ≥ 0.4, cosmic-comp, and partly labwc ≥ 0.20 and dwl ≥ 0.9). Not on GNOME or KDE.
Details in COMPATIBILITY.md.
- Screens and regions —
ext-image-copy-capture-v1with the output source (Sway ≥ 1.11 / wlroots ≥ 0.19), orzwlr_screencopy_manager_v1. - Windows —
ext-foreign-toplevel-list-v1and the foreign-toplevel capture source (Sway ≥ 1.12 / wlroots ≥ 0.20), whichwlr-screencopydoes not stand in for. - The clipboard (
-c) —zwlr_data_control_manager_v1.xdg-outputgives exact logical geometry where the compositor has it. - At run time — a working GL stack (
libegl1): the region selector (-s) renders a frozen overlay through EGL/GLES, on a layer namedwlr-shotfor compositor rules.libfontconfig1looks up the UI font when it is there (the embedded fonts otherwise), andlibgbmserves the zero-copy dma-buf pathrecorduses; screenshots go through shared memory.--no-gpu(orWLR_NO_GPU=1) forces shared memory everywhere. - Hardware encoding — NVIDIA's
libnvidia-encodefor NVENC, or a VAAPI driver for your GPU; without either,recordencodes in software.
wlr-shot doctor says what your compositor exposes, and whether the dma-buf path works
here.
Quick start
With a single screen, a command with no source captures it. With several, name one with
-o (wlr-shot screenshot --list-outputs lists them), or use --all, -s or
--current-output.
Usage
| | | | | |
| | |
|
| | | | |
| | |
|
Source (pick one; with a single screen, that screen by default):
-s, --select— interactively drag a region on a frozen overlay (spans all outputs; releasing the button takes it,EscorCtrl+[cancels). No external tool needed.-o, --output NAME— a whole output (e.g.DP-4).--all— the whole layout: every output combined into one image.-g, --geometry "X,Y WxH"— a logical region (the format slurp prints), stitched across every output it covers. Pairs with slurp:wlr-shot screenshot -g "$(slurp)" shot.png.-w, --window ID— a window, by itsext-foreign-toplevelidentifier (as printed bywlr-chooseror--list-windows).--app-id APP_IDand/or--title TEXT— a window, by application id (exact, case-insensitive) and/or a substring of its title (case-insensitive). The two combine, and unlike the other sources they are not mutually exclusive with each other. If more than one window matches, the command fails and lists the candidates rather than picking one arbitrarily — narrow it down, or use the-w IDit prints.--pick-window— launchwlr-chooserto choose the window interactively; it must be onPATH, which acargo install wlr-shoton its own does not provide.-a, --active-window— the screen area the focused window covers (a region, not the window itself).--current-output— the focused output.
The last two need the compositor's focus info. Wayland exposes no portable way to
query focus, so these go through a per-compositor backend: Sway ($SWAYSOCK),
Hyprland (hyprctl), niri (niri msg, --current-output only: it gives no
window position) and cosmic-comp (zcosmic_toplevel_info_v1, a Wayland protocol —
COSMIC has no IPC socket).
Elsewhere they error with a hint (use --pick-window / -o NAME instead).
Contents:
--cursor— composite the mouse cursor into the capture. It is left out by default, so a screenshot shows the screen rather than where the pointer happened to rest.
Encoding & destination:
-t, --type—png,jpeg,ppm(binary,P6) orpam. Without it, the file's extension picks (.jpg/.jpeg,.ppm,.pam,.png), and anything else — stdout included — is PNG.-q, --quality— JPEG quality, 1–100 (default 90).-c, --clipboard— copy to the Wayland clipboard instead of writing a file. A small daemon detaches to serve the selection (wlrootsdata-control, the protocolwl-copyuses) until another client replaces it — the clipboard is pull-based, so the data must outlive the command.--clipboard-foregroundkeeps it in the foreground (for scripts/debugging). Needs a compositor exposingzwlr_data_control_manager_v1.FILE— destination, or-for stdout (the default). Ignored with--clipboard.--list-outputs— printNAME<TAB>WxH+X,Y(logical geometry) and exit.--list-windows— printID<TAB>APP_ID<TAB>TITLEfor every capturable window and exit; the companion to--app-id/--title.
Because the default FILE is - (stdout), a screenshot pipes straight into an
annotation editor — no temp file. Example Sway bindings sending each source
to satty, which saves the result to your Pictures
directory:
set $pics "$(xdg-user-dir PICTURES)/screenshot-%+.png"
bindsym Print exec wlr-shot screenshot -s - | satty -f - -o $pics
bindsym Shift+Print exec wlr-shot screenshot --active-window - | satty -f - -o $pics
bindsym Control+Print exec wlr-shot screenshot --current-output - | satty -f - -o $pics
bindsym Control+Shift+Print exec wlr-shot screenshot --all - | satty -f - -o $pics
Resolution: a whole output, or a region within a single output, is captured at native (physical) resolution — so a fractionally-scaled monitor keeps full pixel detail. A region spanning several outputs is composited at logical resolution.
Recording (record)
Stream a source to a file whose format follows the extension: .mp4/.mkv for
H.264 video, or .gif/.webp for an animated image (downscaled — GIF to 800 px,
WebP to 1280 px on the long side). Keep those to short clips of a region: every frame
stays in memory until the file is written, and per-frame GIF quantization on a full 4K
output is slow. The same source flags as screenshot apply — -o/sole output,
--current-output, -w ID/--app-id/--title/--pick-window, -a, -g, and -s —
except a region (-g, -s, -a) records a single output for now (the one its
top-left corner sits on). Recording a window follows it across workspaces and even while
occluded; --app-id/--title resolve to an identifier once, at start, so a window
opened later can't steal the recording.
--cursor— composite the mouse cursor into the recording (left out by default). A demo of a pointer-driven interaction needs it.--encoder—auto(default) tries hardware (NVENC, then VAAPI), then softwarelibx264, keeps the first that works on this machine and says which. Force one withnvenc/vaapi/software.--device PATH— DRM render node for VAAPI (default/dev/dri/renderD128).--crf N— constant quality,0–51: lower is better and bigger.0is lossless, about18looks lossless; left out, each encoder keeps its own default. VAAPI has no lossless mode and refuses0: use--crf 1, or--encoder software. Mind the direction:screenshot --qualityis a JPEG scale that runs the other way.--fps N— frame rate (default 30). Capture is damage-driven (a frame only arrives when the screen changes), so a normal recording emits a constant--fps, repeating the last frame through static stretches;--timelapseinstead samples one frame per interval and plays them back at--fps, so the footage is sped up.--timelapse INTERVAL— sample one frame everyINTERVAL(2s,500ms,1m).-d, --duration SECS— stop automatically; otherwise Ctrl-C ends and finalises the file. (Recording a window also ends when the window closes.)- Audio — a video recording captures system audio (the default sink's monitor)
as an AAC track by default, via native PipeWire.
--no-audiorecords silently;--audio-source NODEcaptures another node instead, by its name or serial — a microphone, for instance (pactl list short sourceslists the names). If PipeWire cannot be reached, the recording goes on without sound and says so. Timelapses and GIF/WebP carry no audio. For a host with no PipeWire server running, build with--features audio-fallbackto add a Pulse/ALSA path (via FFmpeg's libavdevice, no extra system dep), tried after PipeWire.
Troubleshooting
multiple outputs; specify -o NAME among: …— with several screens, name one with-o, or use--all,-sor--current-output.- Several windows match
--app-id/--title— the error lists them; narrow the match, or pass the-w IDit prints. -aor--current-outputis unavailable — they need a focus backend (sway, Hyprland, niri for--current-output, cosmic-comp); use-s,-gor-oelsewhere.recording without audio (…)— PipeWire could not be reached; the video is still recorded. Pass--no-audioto record silently on purpose.- What does my compositor support?
wlr-shot doctorsays, and its output is what a bug report needs.
Uninstall
wlr-shot writes no state files. It reads the suite's shared
~/.config/wlr-utils/config.toml, which migrate-config writes from an old
theme.toml; leave it if another tool of the suite still uses it.
License
MIT OR Apache-2.0.