ScreenshotNeo

BlogScreenshots on your device

How to Take Desktop Screenshots in Bash

Capture Linux desktops from Bash with the right X11 or Wayland command, save or copy images, troubleshoot failures, and automate repeatable shots.

By the ScreenshotNeo team29 September 20268 min read

How to Take Desktop Screenshots in Bash

Use the command that matches your graphical session:

  • Wayland: grim screenshot.png
  • Wayland region: grim -g "$(slurp)" screenshot.png
  • X11: scrot screenshot.png
  • X11 with ImageMagick: import -window root screenshot.png

Bash is only starting the capture utility. The display server (X11 or Wayland), compositor protocol, installed packages, and destination (file or clipboard) determine which command works. There is no single desktop screenshot command that works on every Linux installation.

1. Identify X11 or Wayland

Check the session type before choosing a tool:

Choose the capture utility from the display session: X11 uses scrot or ImageMagick import, while Wayland uses grim when the compositor supports screencopy.
Choose the capture utility from the display session: X11 uses scrot or ImageMagick import, while Wayland uses grim when the compositor supports screencopy.
printf 'session=%s\n' "${XDG_SESSION_TYPE:-unknown}"

Typical output is x11 or wayland. If it is empty or unexpected, inspect your desktop session and environment:

echo "$DISPLAY"
echo "$WAYLAND_DISPLAY"
echo "$XDG_CURRENT_DESKTOP"

An X11 session normally has DISPLAY; a Wayland session normally has WAYLAND_DISPLAY. Remote shells, containers, sudo sessions, and scheduled jobs may not inherit these variables even when a graphical desktop is running.

2. Wayland screenshots with grim

Grim’s manual documents PNG output, standard-output mode, geometry selection, output selection, and cursor handling. Grim requires a compositor that exposes the screencopy protocol. Install it with your distribution’s package manager, then capture the complete layout:

grim screenshot.png

With no filename, grim writes image data to standard output. This is useful for pipelines:

# Save through a shell redirection
grim > screenshot.png

# Send the PNG to a Wayland clipboard
# wl-copy is a separate package
grim - | wl-copy

For a particular output, use the output option shown by your installed version:

grim --help

Flags can differ between distributions and versions, so treat the local help as authoritative for output names, cursor inclusion, and format details.

Interactive region capture with slurp

slurp draws a selection rectangle and prints its layout coordinates. Grim consumes those coordinates:

grim -g "$(slurp)" selected.png

This requires both a compositor supported by grim and a working slurp installation. Press Escape during selection to cancel. Because command substitution passes the selected rectangle to grim, spaces and punctuation in the result are handled by the quoted expansion.

Useful Bash functions

#!/usr/bin/env bash
set -euo pipefail

out="${1:-$PWD/screenshot-$(date +%Y%m%d-%H%M%S).png}"
mkdir -p "$(dirname -- "$out")"
grim -- "$out"
printf 'saved %s\n' "$out"

Save this as capture-wayland.sh, run chmod +x capture-wayland.sh, and call ./capture-wayland.sh /tmp/desktop.png. The script creates the destination directory and uses a timestamp when no path is supplied.

3. X11 screenshots with scrot

Scrot’s manual describes a scriptable command-line utility that can save images and capture a screen, window, or rectangle. A full-screen capture is:

scrot screenshot.png

Check the installed version for window and selection flags:

scrot --help

Many builds provide an interactive selection mode and a focused-window mode, but option spelling is version-dependent. Use the local help output before putting a flag into a long-lived script.

ImageMagick import on X11

ImageMagick’s import documentation shows how to capture some or all of an X server screen. Capture the root window:

import -window root screenshot.png

Some installations expose the command through the magick launcher:

magick import -window root screenshot.png

If one form is not recognized, run import -help or magick import -help. ImageMagick may also prompt for a window or rectangle when invoked without a target, depending on the build.

4. Desktop-specific commands

GNOME

GNOME provides gnome-screenshot for full screen, active window, area, clipboard, delay, and output filename workflows. Exact flags vary with the installed release. Read the local manual and verify them with:

gnome-screenshot --help

For example, a script should explicitly provide an output filename and avoid relying on interactive prompts. A delay is useful when a script opens a menu or moves the pointer before capture; make the delay long enough for the desktop animation to finish.

KDE Plasma

KDE’s Spectacle can be started from the command line and supports background and capture-mode workflows. Consult the installed Spectacle documentation and:

spectacle --help

Use the version-specific option names for full screen, current window, rectangular region, delay, and output path. This avoids scripts breaking after a desktop upgrade.

One frontend with multiple backends

Projects such as gscreenshot document several X11 and Wayland backends. They can simplify a personal workflow, but functionality and dependencies still vary by configuration. A wrapper cannot add a compositor protocol that your session does not provide.

5. Files, stdout, and clipboard pipelines

Choose a destination deliberately:

Goal Command pattern Dependency
Save a file grim shot.png or scrot shot.png Capture utility
Capture into another program grim - | command Program must read PNG stdin
Copy on Wayland grim - | wl-copy wl-copy
Copy on X11 Use your desktop utility’s clipboard flag Version-specific option

Protect paths containing spaces with quotes:

out="$HOME/Pictures/My Captures/desktop.png"
mkdir -p "$(dirname -- "$out")"
scrot -- "$out"

For automation, check the exit status and verify that a non-empty file was created:

if grim "$out" && test -s "$out"; then
  echo "capture succeeded: $out"
else
  echo "capture failed" >&2
  exit 1
fi

6. Automation patterns in Bash

Timestamped captures

#!/usr/bin/env bash
set -euo pipefail

folder="${1:-$HOME/Pictures/captures}"
mkdir -p -- "$folder"
name="desktop-$(date -u +%Y%m%dT%H%M%SZ).png"

case "${XDG_SESSION_TYPE:-}" in
  wayland) grim -- "$folder/$name" ;;
  x11) scrot -- "$folder/$name" ;;
  *) echo "Set up an X11 or Wayland graphical session first" >&2; exit 2 ;;
esac
printf '%s\n' "$folder/$name"

Repeated captures

for n in 1 2 3; do
  grim "capture-$n.png"
  sleep 1
 done

Use a delay when the application needs time to render. A screenshot command captures what is currently composited; it does not wait for a web page, animation, or asynchronous data unless your script does so.

Capturing from cron or a service

Scheduled processes commonly fail because they lack the graphical environment and authorization. Pass the correct DISPLAY, WAYLAND_DISPLAY, and runtime directory, and run with the desktop user. Wayland security may reject capture from a process that is not in the user session. For unattended jobs, a browser-rendering API is often simpler than maintaining a logged-in desktop.

7. Troubleshooting

Symptom Likely cause Fix
grim: compositor does not support screencopy Missing protocol support Check compositor documentation, update the compositor, or use its desktop screenshot tool.
grim: failed to connect Wrong or missing Wayland environment Run inside the graphical user session and inspect WAYLAND_DISPLAY and XDG_RUNTIME_DIR.
Can't open display X11 DISPLAY is absent or unauthorized Run as the logged-in desktop user and set the session’s DISPLAY; avoid blindly copying values between users.
slurp exits immediately Selection tool unavailable or compositor incompatibility Run slurp directly, install it, and confirm the compositor supports the required interfaces.
Black or blank image Permission, unsupported protocol, or an application rendering issue Try the desktop’s native tool, test a simple visible window, and inspect utility stderr.
File is missing Parent directory does not exist or path is wrong Use mkdir -p, quote the path, and check the command exit code.
Clipboard paste fails wl-copy or an X11 clipboard helper is absent Install the matching clipboard utility and keep the capture process alive until the clipboard manager receives the data.
Works in a terminal, fails in SSH SSH session has no access to the local display Run the command on the desktop host or configure a supported remote display; do not assume SSH forwards Wayland capture.

8. Performance, reliability, and security

  • Write locally first: Save to a local filesystem, then upload or process the file. Network mounts add latency and can produce partial files.
  • Use PNG when fidelity matters: It is lossless but larger. Convert afterward when JPEG or WebP is more suitable.
  • Control capture frequency: A tight loop can consume CPU, disk, and compositor bandwidth. Add a sleep and rotate old files.
  • Check completion: Test the exit code and file size before notifying another process.
  • Mind sensitive content: Desktop captures can include passwords, notifications, tokens, and private documents. Restrict file permissions and clean up temporary images.
  • Expect environment dependence: Tool availability, compositor protocols, desktop versions, and command flags differ. Pin packages or test scripts after upgrades.

9. When you need a website screenshot instead

Desktop utilities capture the local display. They are the wrong layer when you need a repeatable screenshot of a URL on a server, in CI, or from an AI workflow. ScreenshotNeo provides a website screenshot API and MCP server: one GET request returns PNG, JPEG, WebP, or PDF. It can load lazy images, capture a CSS-selected element, emulate dark mode and device presets, set a viewport and retina scale, run custom CSS or JavaScript, click before capture, wait for a selector, delay, or network idle, block ads or resource types, send headers/cookies/user agents, set timezone and geolocation, resize images, cache with a chosen TTL, create signed links, run asynchronous jobs with signed webhooks, capture up to 100 URLs per bulk call, and expose usage and OpenAPI endpoints. Its parameter names are compatible with those used by other screenshot APIs.

A website screenshot service can remove consent banners and other overlays before returning the page image.
A website screenshot service can remove consent banners and other overlays before returning the page image.

10. Or skip the browser setup

For a URL screenshot, call the API directly. See the ScreenshotNeo documentation for all options.

cURL

curl -G "https://api.screenshotneo.com/v1/shot" \
  -d access_key=YOUR_API_KEY \
  --data-urlencode url=https://stripe.com \
  -o shot.webp

Python

import requests

r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
    timeout=90,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)

Node.js

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const fs = await import('node:fs/promises');
await fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer()));

ScreenshotNeo removes cookie and consent banners, newsletter popups, and chat widgets before capture. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed; response headers identify the page verdict and whether the request was billed. An MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. The Free plan includes 1,000 shots each month with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.

11. FAQ

Can scrot capture a Wayland desktop?

Scrot and ImageMagick’s X11 import target an X server. Use grim when your Wayland compositor supports screencopy, or use the desktop’s Wayland-aware tool.

Does grim capture every Wayland compositor?

No. Grim currently needs compositor screencopy support, and slurp adds its own compatibility requirement for region selection.

How do I capture only one monitor?

Use grim’s output-selection option shown by grim --help, or use your desktop tool’s monitor option. Output names are environment and version dependent.

Why does a screenshot from cron fail?

The job usually lacks the logged-in user’s display variables or permissions. Run it in the graphical session, pass the required environment, and verify authorization before scheduling.

Can Bash wait for a web page to finish loading?

A desktop command only captures the current screen. Use browser automation with explicit waits, or a website screenshot API when the input is a URL.