What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.
If a Python screenshot is black, blank, missing a program window, or showing the wrong monitor, first determine whether the failure affects the whole desktop, a rectangular region, or one application. A desktop-wide failure usually points to dependencies, permissions, the display session, or an incorrect backend. If ordinary desktop areas capture correctly but one program does not, the target may use protected, hardware-accelerated, remote, or overlay rendering that a normal screenshot API cannot read. There is no universal Python switch that bypasses those restrictions.
Use the workflow below: record the exact symptom, prove that a basic screen capture works, verify the library’s documented requirements, select the correct display or window identifier, and then use an authorized capture path provided by the application or operating system.
Start by identifying the capture scope
Three operations are often confused:
- Whole desktop: every visible monitor or the primary display.
- Region: a rectangle such as
(left, top, right, bottom). - Application window: one window identified by a platform-specific handle or identifier.
Pillow documents all three forms, while PyAutoGUI and MSS primarily expose screen or region capture. A script that can save the desktop but cannot capture one program has a different diagnostic path from a script that cannot capture anything.
Recommended Free Tools
Record the symptom before changing code
Write down:
- Operating system and version.
- Desktop session and display backend, especially on Linux.
- Python, Pillow, PyAutoGUI, and MSS versions.
- Monitor count, arrangement, and display scaling.
- Whether the target is minimized, covered, remote, running with elevated privileges, hardware accelerated, or protected.
- Whether the output file is completely black, only the target window is black, the wrong monitor appears, or Python raises an exception.
These details distinguish an installation or session problem from behavior specific to the target program.
#1 Best Overall
Build a minimal baseline capture
Run a whole-screen test before attempting window handles or complex options. Save the image and print its dimensions and a pixel sample.
from PIL import ImageGrab
image = ImageGrab.grab()
print("size:", image.size)
print("sample pixel:", image.getpixel((0, 0)))
image.save("desktop-baseline.png")
Open desktop-baseline.png while a normal, visible desktop window is present. Then test a known visible rectangle:
from PIL import ImageGrab
# left, top, right, bottom; adjust to a clearly visible area
region = ImageGrab.grab(bbox=(100, 100, 900, 700))
print("region size:", region.size)
region.save("region-baseline.png")
If both images are black, empty, incorrectly sized, or never created, investigate the environment before blaming the target application. If they are correct and only one program is missing or black, continue with target-specific checks rather than repeatedly swapping libraries.
Do these 3 things before closing this tab:
1Repair Windows errors before they cause bigger problems2Scan for outdated or missing drivers - takes under a minute3Clear out junk files and repair common Windows errorsFix PyAutoGUI captures
PyAutoGUI’s pyautogui.screenshot() returns a Pillow image, and passing a filename saves it directly. Its screenshot support requires Pillow. On Linux, the PyAutoGUI documentation names the scrot command for screenshot functionality; its installation documentation also lists Linux scrot and Tkinter dependencies.
import pyautogui
image = pyautogui.screenshot("pyautogui-test.png")
print(image.size)
Install the packages in the same interpreter that runs the script, then verify that interpreter:
python -m pip install --upgrade pyautogui pillow
python -c "import sys, PIL, pyautogui; print(sys.executable); print(PIL.__version__); print(pyautogui.__version__)"
On Linux, install the distribution package that provides scrot and Tkinter using your distribution’s package manager, then start a local graphical session. A virtual terminal, a headless SSH session, or a missing DISPLAY can prevent a screen-grabbing utility from seeing the desktop.
Rank #2
Reference: PyAutoGUI Screenshot Functions and PyAutoGUI Installation.
Use Pillow for regions and supported single-window capture
ImageGrab.grab() captures the screen by default, accepts a bbox for a region, and supports a window argument on documented platforms. On Windows, window expects an HWND. On macOS, it expects a CGWindowID. Check your installed Pillow version: the documented Windows window support starts in Pillow 11.2.1, and macOS support starts in Pillow 12.1.0.
Windows HWND example
You must obtain the target window’s HWND using an appropriate Windows API or window-inspection tool, then pass that integer to Pillow:
from PIL import ImageGrab
hwnd = 123456 # replace with the real HWND
image = ImageGrab.grab(window=hwnd)
image.save("window.png")
An invalid, closed, minimized, or inaccessible handle can produce an error or an unusable image. Confirm that the handle belongs to the intended top-level window and that your process has suitable permission.
macOS CGWindowID example
On macOS, obtain the CGWindowID through the operating system’s window APIs and pass it as window=...:
Quick wins for a faster PC:
Repair Windows errors before they cause bigger problemsFix Now →Scan for outdated or missing drivers - takes under a minuteDriver Scan →Clear out junk files and repair common Windows errorsFree Scan →from PIL import ImageGrab
window_id = 987654 # replace with the real CGWindowID
image = ImageGrab.grab(window=window_id)
image.save("mac-window.png")
Retina displays can return images at twice the logical dimensions. Pillow documents scale_down=True when you need dimensions closer to points rather than physical pixels:
from PIL import ImageGrab
image = ImageGrab.grab(bbox=(0, 0, 900, 700), scale_down=True)
image.save("mac-region.png")
Reference: Pillow ImageGrab.
Configure MSS for the correct Linux display
MSS exposes monitors and regions through platform-specific backends. On GNU/Linux it uses the DISPLAY environment variable by default. In an SSH session, container, remote desktop, or multi-display setup, that value may be absent or point at the wrong server.
from mss import mss
with mss() as sct:
print("monitors:", sct.monitors)
monitor = sct.monitors[1] # first physical monitor; 0 is the combined area
shot = sct.grab(monitor)
sct_img = sct.to_png(shot.rgb, shot.size)
with open("mss-monitor.png", "wb") as f:
f.write(sct_img)
Inspect the printed monitor rectangles and select the one containing the target. If you need another display, set DISPLAY before launching Python, for example:
DISPLAY=:1 python capture.py
MSS documents X11 backends and display selection, but its documentation does not establish one universal remedy for every Wayland configuration. If your session is Wayland, consult the desktop environment’s approved portal or native capture API instead of assuming an X11 workaround will apply.
Reference: Python MSS Usage.
Interpret a black or missing program window
When the desktop and unrelated regions are correct but one application is black, the capture path may be seeing a different surface from the one displayed to you. Protected video, anti-capture policies, hardware overlays, remote surfaces, and some accelerated rendering paths can cause this. An anecdotal Reddit report describes “the whole window is just black if taken screenshot”; that wording is a user’s report, not a general technical rule.
The official documentation reviewed for Pillow, PyAutoGUI, and MSS does not promise a universal bypass. Do not treat a library swap as a guaranteed fix, and do not attempt to defeat content protection. Instead:
- Use the application’s own export, screenshot, recording, or print feature if it provides one.
- Check the application’s documented API or automation interface.
- Capture an authorized rendering or export surface rather than the protected window.
- Test with hardware acceleration disabled only if the application’s own support documentation recommends that diagnostic; changing it can alter performance and output.
- For remote applications, capture on the machine where the window is actually rendered or use the remote system’s supported capture facility.
When a native Windows capture API is the right tool
If you are building a Windows application rather than writing a one-off Python script, Microsoft’s Windows screen-capture documentation describes native capture APIs. For WinUI 3, Microsoft says the picker must be initialized with the application’s window handle before calling PickSingleItemAsync. This is an implementation requirement for that Windows UI flow, not a drop-in repair for every Python screenshot.
See Microsoft’s Screen capture documentation for the supported Windows approach.
The Tool Desk
Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Compare the practical options
| Approach | Scope | Platform/version detail | Best diagnostic use |
|---|---|---|---|
| PyAutoGUI | Desktop and region through Pillow | Requires Pillow; Linux screenshot path names scrot |
Quick visible-screen automation |
| Pillow ImageGrab | Desktop, region, and supported single window | Windows window support from 11.2.1; macOS from 12.1.0 | Simple scripts needing a documented window identifier |
| MSS | Monitors and regions | Linux uses DISPLAY; backend/session matters |
Fast, explicit monitor selection and Linux diagnostics |
| Native OS API | Defined by the operating system | Requires platform-specific integration | Production Windows features and authorized capture flows |
None of these entries guarantees pixels from a protected or specially rendered target. Choose based on capture scope, session, and the target application’s behavior.
Troubleshooting checklist
“No module named PIL” or import errors
Install Pillow with the interpreter that runs the script: python -m pip install pillow. Print sys.executable to detect a virtual-environment mismatch.
PyAutoGUI works on one machine but not Linux
Confirm scrot and Tkinter are installed, run inside a graphical session, and verify that the session’s display is available.
MSS captures the wrong monitor
Print sct.monitors, map the returned rectangles to your physical layout, and select the correct entry. Check DISPLAY when using SSH or multiple X servers.
The image dimensions are unexpected on macOS
Account for Retina pixel scaling. Use Pillow’s documented scale_down=True when logical-size output is required.
Best Value
Only one application is black
Run the desktop and known-region baseline tests. If they pass, investigate the target’s export/API or authorized OS capture route; do not promise that another Python library will bypass its restrictions.
The script works locally but fails in a service or container
A background process may have no interactive desktop, display server, or permission to capture it. Run the test in the same user session as the visible application or redesign the workflow around an application export or server-rendered page.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Or skip the browser setup
For websites rather than local desktop programs, ScreenshotNeo returns a PNG, JPEG, WebP, or PDF from one request. It accepts the cookie or consent banner like a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each step can be turned off. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and the response identifies the result with X-Page-Verdict and X-Billed headers. Its MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients.
ScreenshotNeo is not a replacement for capturing a protected local application window; it is a website screenshot API. It can be the simpler route when the thing you need is a web page.
One-call examples
See the full parameter reference in the ScreenshotNeo documentation.
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}`);
It also supports full-page captures with lazy images loaded, CSS-selector element capture, dark mode, 12 device presets or custom viewports, retina scale, PDF paper and page controls, HTML/CSS rendering, custom JavaScript and CSS, pre-capture clicks, hidden selectors, selector/delay/network-idle waits, request and resource blocking, custom headers/cookies/user agents/Authorization, timezone and geolocation, transparent backgrounds, resizing, chosen cache TTLs, signed image links, asynchronous jobs with signed webhooks, bulk capture of up to 100 URLs per call, a usage API, and an OpenAPI specification. Parameter names used by other screenshot APIs also work, easing migration.
The Free plan includes 1,000 screenshots per month with no card. Paid plans start at $5 for 3,000 shots; yearly billing gives two months free, and every feature is available on every plan. Create a free ScreenshotNeo account to try it.
Free tools Windows power users keep installed
One-click scans. No signup required.
Reliability, performance, and cost considerations
- Reliability: save a baseline image and log dimensions, selected display, library versions, and exceptions so a later failure is comparable.
- Performance: capture only the required region or window when possible. MSS release notes describe a local Debian-testing/X11 4K benchmark for version 10.2.0; that result is environment-specific, not a universal speed guarantee.
- Cost: local libraries have no per-shot service charge, but require a logged-in graphical session and maintenance. A hosted website API shifts browser and rendering setup to the service and reports whether a request was billed.
- Security: keep API keys out of source control, and use only authorized headers, cookies, accounts, and target content.
A repeatable decision path
- Classify the request as desktop, region, or window.
- Run Pillow’s whole-screen and region baselines.
- Fix interpreter, Pillow, PyAutoGUI, Linux utility, display, and permission issues.
- Use Pillow’s documented HWND or CGWindowID support when the platform and version provide it.
- Use MSS with the correct monitor and
DISPLAYwhen monitor or region capture is the goal. - If one program alone remains black, use its export/API or an authorized native capture path; do not assume a bypass exists.
- For a web page, use a browser automation workflow or ScreenshotNeo’s single request.
Frequently Asked Questions
Can Python capture a minimized window reliably?
The documented APIs focus on visible screen, region, or platform-identified windows; they do not establish a universal guarantee for minimized windows. Test the target’s own export or API when visibility is not available.
Why does an SSH command capture a blank screen on Linux?
MSS uses the DISPLAY environment variable by default, and the SSH session may not point to the graphical display. Run in the intended local session or explicitly select the reachable display and backend.
Should I install every screenshot library?
No. Choose one that matches the required scope and platform, then verify its documented dependencies. Installing alternatives will not guarantee access to protected application surfaces.
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.

