For a one-off screenshot that should become a Pillow image, start with Pillow.ImageGrab. Use MSS for repeated captures, monitor or region selection, and direct pixel processing. Choose PyAutoGUI when taking a screenshot is part of mouse-and-keyboard automation. Treat pyscreenshot as a compatibility wrapper for a specific backend, not a default choice. Your operating system, display server (especially Wayland versus X11), monitor layout, and image-processing pipeline matter more than a universal speed ranking.
This guide gives working examples, selection criteria, platform checks, performance context, troubleshooting, and a browser-based alternative when you actually need website rather than desktop screenshots.
Quick decision: which library fits your job?
| Library | Choose it when | Main trade-off |
|---|---|---|
Pillow ImageGrab |
You need one or occasional screenshots saved or manipulated as Pillow images. | Less specialized for high-rate capture and monitor-region workflows; verify current OS behavior in the official reference. |
| MSS | You need a capture loop, a selected monitor or region, or direct handoff to NumPy/OpenCV. | Linux backend and performance depend on your display environment; its data requires attention to channel order and alpha. |
| PyAutoGUI | Capture is one step in desktop automation that also clicks, types, or locates images. | Broader than capture alone; documentation says it handles only the primary monitor. |
| pyscreenshot | A particular Linux or Wayland backend exposed by its wrapper solves a concrete compatibility problem. | The project calls itself obsolete for most cases now that Pillow supports Linux and macOS. |
For a web page, these desktop libraries are the wrong abstraction: they capture the currently visible desktop, not a deterministic page at a chosen viewport. Use a browser screenshot service such as ScreenshotNeo instead.
Start with Pillow ImageGrab for a simple screenshot
ImageGrab.grab() returns a Pillow image, so it is the shortest path from desktop pixels to save(), resizing, or other Pillow operations.
Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Scan for outdated or missing drivers - takes under a minuteDriver Scan →Repair Windows errors before they cause bigger problemsFix Now →#1 Best Overall
from PIL import ImageGrab
image = ImageGrab.grab()
image.save("screen.png")
print(image.size)
Capture a rectangular area by supplying a bounding box in screen coordinates:
from PIL import ImageGrab
# left, top, right, bottom
region = ImageGrab.grab(bbox=(100, 100, 900, 700))
region.save("region.png")
Use ImageGrab when the result itself is a Pillow image and you do not need a capture engine optimized for a long-running loop. Read the platform notes in the ImageGrab documentation before deploying across operating systems, remote sessions, or unusual display configurations.
When ImageGrab is not the best default
- For dozens or thousands of frames, opening and converting images repeatedly can become the bottleneck.
- For direct NumPy or OpenCV processing, MSS exposes pixel-oriented data more naturally.
- For clicking, typing, and image-location logic, PyAutoGUI keeps those operations in one API.
Use MSS for repeated, regional, or pixel-data capture
MSS is designed around monitors and regions. Current documentation prefers creating an mss.MSS instance; reuse that instance inside a loop rather than reopening it for every frame.
import mss
with mss.MSS() as sct:
monitor = sct.monitors[1] # first physical monitor
shot = sct.grab(monitor)
print(shot.width, shot.height)
sct.monitors[0] represents the virtual desktop that spans configured monitors; entries after it represent individual monitors. Select a custom rectangle with a dictionary:
Free tools Windows power users keep installed
One-click scans. No signup required.
import mss
area = {"left": 200, "top": 120, "width": 800, "height": 600}
with mss.MSS() as sct:
shot = sct.grab(area)
# shot exposes pixel data; see conversion examples below
Save an MSS grab as a Pillow image
import mss
from PIL import Image
with mss.MSS() as sct:
shot = sct.grab(sct.monitors[1])
image = Image.frombytes("RGB", shot.size, shot.rgb)
image.save("mss-screen.png")
MSS also exposes BGRA/RGB memory views, pixel tuples, and coordinate lookups. The alpha byte may be unused or zero-filled; remove or ignore it if a downstream renderer interprets it incorrectly. The usage guide documents integrations with Pillow, NumPy, and other processing frameworks: MSS usage documentation.
Rank #2
Feed MSS data into NumPy
import mss
import numpy as np
with mss.MSS() as sct:
shot = sct.grab(sct.monitors[1])
# BGRA byte buffer; reshape to height x width x 4
frame_bgra = np.frombuffer(shot.bgra, dtype=np.uint8).reshape(
shot.height, shot.width, 4
)
frame_rgb = frame_bgra[:, :, :3][:, :, ::-1]
print(frame_rgb.shape)
Benchmark your actual deployment machine instead of assuming that one library is always fastest. Python-MSS 10.2.0 release notes report 9.48 ms per full-screen capture versus 46.2 ms in 10.1.0 in a project-local Debian testing, X11, 4K test using 1,000 captures (best of three runs). Those are setup-specific project figures, not a general guarantee: MSS 10.2.0 release notes.
Linux backend details
On X11, MSS documents an xshmgetimage backend as roughly three times faster than xgetimage in the named implementations; it falls back when MIT-SHM is unavailable. That relative statement is not a universal comparison with Pillow or PyAutoGUI. Confirm whether your process is running under X11, a compatibility layer, or Wayland before drawing conclusions.
Choose PyAutoGUI when capture belongs to GUI automation
PyAutoGUI returns a Pillow image and also provides mouse, keyboard, and image-location functions. A minimal capture is:
import pyautogui
image = pyautogui.screenshot()
image.save("desktop.png")
Limit the capture with region=(left, top, width, height):
import pyautogui
image = pyautogui.screenshot(region=(100, 100, 800, 600))
image.save("panel.png")
Install Pillow as required by PyAutoGUI. On Linux, the screenshot features documented by the project use scrot; install it through your distribution package manager if a screenshot call reports that it is missing. macOS uses the system screencapture utility. The project gives a rough figure of 100 milliseconds for a 1,920 × 1,080 screenshot, which is usage guidance rather than a controlled comparison with MSS: Screenshot Functions.
PyAutoGUI’s scope is desktop automation, not a multi-monitor capture engine. Its documentation currently says only the primary monitor is handled, so test coordinate assumptions before automating a workstation with multiple displays: PyAutoGUI documentation.
Where pyscreenshot fits—and why it is usually not first
pyscreenshot wraps existing capture backends rather than implementing a separate engine. Its README lists routes including xdg-desktop-portal, GNOME Shell D-Bus, and Grim for particular Wayland environments; portal calls may display permission dialogs, and support depends on the compositor and installed backend.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
The project README says it is obsolete in most cases because Pillow now supports Linux and macOS. Use it when a listed backend solves a specific machine-level compatibility issue that your normal Pillow or MSS path cannot solve, then validate the result on the target compositor: pyscreenshot README.
Wayland, X11, and multi-monitor checks
- Identify the session: inspect your desktop’s display-session information and determine whether the application runs under Wayland or X11.
- Confirm permissions: Wayland portals can require an interactive approval and may restrict unattended capture.
- Test one monitor and one region before building a loop. Coordinate systems and virtual-desktop origins differ across environments.
- Run the same code from the production context (local desktop, service, container, or SSH session). A headless or disconnected session may have no capturable display.
- Record the backend and library version with your benchmark so a later deployment is comparable.
Installation and minimal test plan
Create an isolated environment, install only the library you selected, and save a known region.
python -m venv .venv
# macOS/Linux
. .venv/bin/activate
# Windows PowerShell: .venvScriptsActivate.ps1
pip install pillow mss pyautogui
Then test in this order:
- Can the process import the package?
- Does a full-screen capture return nonzero dimensions?
- Does a small region contain the expected pixels?
- Can the output be opened by Pillow or your downstream decoder?
- Does a loop of 100 captures maintain acceptable latency and memory use?
Troubleshooting common failures
Black, blank, or transparent images
The process may have no permission to the display, may be attached to the wrong session, or may be capturing a compositor-protected surface. Try a local interactive session, verify Wayland portal approval, and test X11 where available. With MSS, ignore or strip an unused alpha channel before rendering.
DISPLAY errors or “cannot open display”
Your Linux process cannot reach an X server. Run it in the user session, set the correct display environment when appropriate, and provide authorization (for example, the session’s X authority). A remote shell without a forwarded or active desktop cannot capture that desktop automatically.
PyAutoGUI reports missing scrot
Install the scrot package using your Linux distribution’s package manager, then retry. If policy prevents installing it, use Pillow or MSS with a backend supported by your environment.
Only one monitor is captured
PyAutoGUI documents primary-monitor support only. Switch to MSS and select monitors[0] for the virtual desktop or a specific monitor entry, then verify coordinates on your hardware.
Capture is too slow
Reduce the region, avoid unnecessary color conversions, reuse one MSS instance, and move disk writes off the capture-critical path. Benchmark with the same resolution, display server, and loop length you will use in production; published figures are not portable guarantees.
Wayland works interactively but fails unattended
That behavior is often a portal or compositor policy rather than a Python bug. Check whether the portal requires a user dialog and whether your compositor exposes a permitted backend. If unattended capture is a requirement, design around the supported backend or use a controlled X11 environment.
Best Value
Performance, reliability, and maintenance guidance
- Reuse resources: create one MSS object per worker and close it cleanly.
- Capture less: a small region costs less than a 4K virtual desktop in transfer, conversion, and storage.
- Separate capture from processing: queue frames so OCR, encoding, or disk I/O does not block the capture loop.
- Control memory: do not retain every frame; recycle buffers or process-and-discard.
- Pin and test versions: MSS 10.2.0 changed API guidance, preferring
MSSover older factory/class entry points. Read its release history before upgrading. - Handle privacy: desktop screenshots can include credentials, notifications, and personal data. Restrict file permissions and redact before sending images elsewhere.
Or skip the browser setup
If your actual target is a website, use an HTTP screenshot API instead of installing a browser, managing display servers, or capturing whatever happens to be visible on a desktop. ScreenshotNeo accepts a URL and returns PNG, JPEG, WebP, or PDF. It removes cookie/consent banners, newsletter popups, and chat widgets before capture; bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing status. Its MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients.
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}`);
require('fs').writeFileSync('shot.webp', Buffer.from(await res.arrayBuffer()));
See the complete parameter reference and options in the ScreenshotNeo documentation. You can set full-page capture with lazy-image loading, CSS-selector element capture, dark mode, device presets or custom viewports, retina scale, PDF paper and page settings, custom CSS/JavaScript, clicks, waits, ad/tracker/request blocking, headers, cookies, user agents, authorization, timezone, geolocation, transparent backgrounds, resizing, TTL caching, signed image links, asynchronous webhooks, bulk capture (up to 100 URLs per call), usage data, and an OpenAPI specification.
The Free plan includes 1,000 screenshots per month with no card. Paid plans start at $5 for 3,000 shots; every feature is included on every plan. Create a free ScreenshotNeo account.
Final selection
Pick ImageGrab for the smallest Pillow-first script, MSS for repeated or pixel-oriented capture, PyAutoGUI when screenshots and GUI actions are one workflow, and pyscreenshot only for a verified backend compatibility need. Validate the display session and benchmark on the machine that will run the code.
Do these 3 things before closing this tab:
1Scan for outdated or missing drivers - takes under a minute2Clear out junk files and repair common Windows errors3Fix the driver behind crashes, sound loss and screen glitchesFrequently Asked Questions
Can these libraries capture a web page without opening a browser?
No. They capture the desktop display. For deterministic website screenshots at a chosen viewport, use a browser-based API such as ScreenshotNeo.
Which library should I use with OpenCV?
Start with MSS, convert its BGRA buffer to the channel order your OpenCV pipeline expects, and handle the alpha byte explicitly.
Is MSS always faster than PyAutoGUI?
No universal ranking is established. The projects document different environments and methods, so benchmark your own resolution, display server, and capture loop.
Does Wayland support work everywhere?
No. It depends on the compositor, portal permissions, and installed backend. Test the exact deployment session before committing to a library.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

