ScreenshotNeo

BlogHow-to

How to Take Screenshots with Python on a Raspberry Pi

Use Raspberry Pi OS Bookworm’s Wayland tools from Python, select regions, troubleshoot black images, and choose the right capture method.

By the ScreenshotNeo team1 October 20267 min read

For a desktop screenshot on current Raspberry Pi OS, check your display session first. Bookworm normally uses Wayland with labwc, so the documented route is the grim utility. Python can run grim as a child process and save the image. To capture a selected area, pipe slurp into grim -g -.

This is different from taking a photograph with a camera connected to the Pi. A screen capture records the display compositor’s output; a camera image comes from a camera sensor. Use Picamera2 only for the second case.

1. Confirm what you want to capture

Goal Use
Entire Raspberry Pi desktop grim on a Wayland session
Selected rectangle of the desktop slurp to choose geometry, then grim
An X11 desktop where the dependency works scrot, including through PyAutoGUI
A photograph from a connected camera Picamera2 and the camera stack

Raspberry Pi’s Raspberry Pi OS documentation describes the operating-system defaults and package guidance. Its Bookworm migration guide documents grim for the Print Screen workflow and slurp | grim -g - for area selection.

2. Check the Raspberry Pi session

Run these commands in the desktop session that should be captured:

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

On Bookworm, expect the session type to be wayland. If the process runs over SSH, from a service account, or outside the logged-in desktop session, it may not have access to the compositor. A Python script cannot automatically capture another user’s display.

3. Install the capture utilities

Install the command-line tools with your system package manager:

sudo apt update
sudo apt install grim slurp

slurp is needed only for interactive region selection. The grim utility requires a Wayland compositor that supports the screencopy protocol, as described in the Debian grim manual.

If your Python program needs a virtual environment, create one on Bookworm or later:

python3 -m venv .venv
. .venv/bin/activate
python -m pip install --upgrade pip

Keep Python packages in the virtual environment. The screenshot utility itself is an operating-system package.

4. Capture the full desktop from Python

The simplest integration is to invoke grim with Python’s subprocess module. This follows the documented CLI workflow; the compositor, login session and permissions still determine whether it works.

#!/usr/bin/env python3
from pathlib import Path
import subprocess
import sys


def screenshot(path: str) -> Path:
    destination = Path(path).expanduser()
    destination.parent.mkdir(parents=True, exist_ok=True)

    result = subprocess.run(
        ["grim", str(destination)],
        check=False,
        capture_output=True,
        text=True,
    )

    if result.returncode != 0:
        detail = result.stderr.strip() or "grim returned a non-zero exit status"
        raise RuntimeError(detail)

    if not destination.is_file() or destination.stat().st_size == 0:
        raise RuntimeError("grim did not create a non-empty image")

    return destination


if __name__ == "__main__":
    output = sys.argv[1] if len(sys.argv) > 1 else "~/Pictures/desktop.png"
    print(f"Saved {screenshot(output)}")

Save it as screen.py, then run:

python3 screen.py ~/Pictures/desktop.png

Use a PNG filename for lossless output. The file format is inferred by the utility from the destination name and supported options.

5. Capture a selected region

Raspberry Pi’s Bookworm instructions use this shell pipeline:

slurp | grim -g - ~/Pictures/selection.png

The following Python program runs the same two-stage workflow and passes the selected geometry to grim:

#!/usr/bin/env python3
from pathlib import Path
import subprocess


def region_screenshot(path: str) -> Path:
    destination = Path(path).expanduser()
    destination.parent.mkdir(parents=True, exist_ok=True)

    selection = subprocess.run(
        ["slurp"],
        check=False,
        capture_output=True,
        text=True,
    )
    if selection.returncode != 0:
        raise RuntimeError(selection.stderr.strip() or "region selection was cancelled")

    geometry = selection.stdout.strip()
    if not geometry:
        raise RuntimeError("slurp returned no geometry")

    capture = subprocess.run(
        ["grim", "-g", geometry, str(destination)],
        check=False,
        capture_output=True,
        text=True,
    )
    if capture.returncode != 0:
        raise RuntimeError(capture.stderr.strip() or "grim failed")

    return destination


if __name__ == "__main__":
    print(region_screenshot("~/Pictures/selection.png"))

Run it from the active desktop:

python3 select_region.py

If the selection UI never appears, verify that slurp is installed and that the process has access to the current Wayland session.

6. Capture with PyAutoGUI when your session supports its dependency

PyAutoGUI’s screenshot documentation says that Linux screenshots use the scrot utility. That makes this route dependent on an X11-compatible setup:

sudo apt update
sudo apt install scrot
python3 -m venv .venv
. .venv/bin/activate
python -m pip install pyautogui
import pyautogui

image = pyautogui.screenshot()
image.save("desktop.png")

Raspberry Pi OS Bookworm defaults to Wayland, so do not treat this as a session-independent replacement for grim. If it produces a black image or fails to connect, check the session type before changing Python code.

7. Desktop screenshot versus Picamera2

Raspberry Pi’s camera documentation and the Picamera2 manual describe camera capture. Picamera2 reads frames from a supported camera; it does not capture the pixels rendered by your desktop compositor.

  • Use grim when you need what the monitor is displaying.
  • Use Picamera2 when you need an image from a camera sensor.
  • A camera is not required for a desktop screenshot.

8. Common errors and fixes

Symptom Likely cause Fix
grim: command not found The utility is not installed or is not on PATH. Install the system package, then run command -v grim.
Black image from PyAutoGUI or scrot The documented PyAutoGUI path uses an X11-oriented dependency, while Bookworm normally uses Wayland. Check XDG_SESSION_TYPE; use grim for Wayland or run the X11 route in a compatible session.
grim cannot connect to a compositor The script is outside the logged-in desktop session, or the compositor does not support the screencopy protocol. Run it inside the target session and confirm the compositor supports the protocol.
slurp exits immediately The selection was cancelled, no interactive display is available, or slurp is missing. Install slurp, run from the desktop, and handle its non-zero exit status.
Works in a terminal but not from a service Services usually lack the user’s Wayland environment and display permissions. Run the capture in the desktop user context or explicitly arrange a supported session environment.
SSH command fails An SSH shell is not automatically attached to the graphical session. Use a command launched within the active desktop session; do not assume SSH has compositor access.
Empty output file The command failed before writing, or the destination directory does not exist. Create the parent directory, inspect stderr, and check the return code as in the examples.

9. Reliability, performance and storage considerations

  • Session availability: A compositor screenshot needs an active supported display session. A headless process cannot capture a desktop that is not running.
  • Race conditions: If another program changes the screen during capture, the resulting image reflects the compositor’s frame at capture time. Add your own coordination if the screenshot must follow a UI action.
  • File safety: Write to a known directory, create it before capture, and verify that the file exists and is non-empty.
  • Failure handling: Check subprocess return codes and retain stderr in logs. Treat a cancelled slurp selection as an expected user action.
  • Format and size: PNG preserves pixels but uses more storage than a lossy format. Choose the output format and retention policy for your workload.
  • Automation: For repeated captures, avoid launching unnecessary desktop tools and keep the Python process in the same graphical session as the target display.

10. Or skip the browser setup

If what you actually need is a screenshot of a web page rather than the Raspberry Pi desktop, ScreenshotNeo provides a website screenshot API. One GET request returns PNG, JPEG, WebP or PDF, so there is no browser, Wayland session or display server to configure. See the ScreenshotNeo API documentation for options.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

ScreenshotNeo removes cookie banners, newsletter popups and chat widgets before the shot. Bot checks, blank pages and failed loads are never billed, and response headers report the page verdict and billing status. Its MCP server lets AI agents use take_screenshot, get_page_info and capture_pdf. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000.

Create your free ScreenshotNeo account.

11. FAQ

Can Python capture the screen without installing a Python screenshot library?

Yes. Python can invoke the system’s grim command with subprocess. The compositor and session still need to support the utility.

Which command captures only one monitor?

Use slurp to select the monitor or rectangle, then pass its geometry to grim -g. The exact geometry is chosen interactively.

Why does the Print Screen key work while my script does not?

The desktop shortcut runs inside the logged-in graphical session. A script launched from SSH, cron or a service may not have the same session environment or permissions.

Should I use Picamera2 for a screenshot?

Only when you mean a photograph from a connected camera. For the desktop image shown on screen, use the compositor capture path.

Does PyAutoGUI work on every Raspberry Pi OS installation?

No. Its documented Linux screenshot path depends on scrot, and Bookworm’s default Wayland desktop makes that route dependent on the active session.