Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

PyAutoGUI screenshot problems usually come from one of four places: a missing Pillow or platform capture dependency, an unsupported or headless display session, a mismatch between logical and physical pixel dimensions, or a separate image-matching failure. First prove that a minimal full-screen capture works, inspect its size and pixels, and only then debug locateOnScreen(). This separates capture failures from template and coordinate problems.

Understand what PyAutoGUI is doing

PyAutoGUI delegates screenshots and image location to PyScreeze, while the screenshot image itself is a Pillow image. Screenshot functionality requires Pillow, and the returned image can be saved directly by passing a filename. The official API also accepts a four-value region tuple: (left, top, width, height). See the PyAutoGUI screenshot documentation.

Capture and matching are different operations. A file can be captured correctly even when locateOnScreen() cannot find a template. Conversely, a matching error may hide an earlier blank, black, scaled, or incorrectly sized capture. Diagnose these stages independently.

Start with a minimal diagnostic script

Run this in the same virtual environment, terminal, IDE interpreter, container, or service account that runs your real automation:

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
import sys
import platform
from pathlib import Path

import pyautogui
from PIL import Image

print("Python:", sys.version)
print("OS:", platform.platform())
print("PyAutoGUI screen size:", pyautogui.size())

image = pyautogui.screenshot("screen-test.png")
print("Captured image size:", image.size)
print("Mode:", image.mode)
print("File exists:", Path("screen-test.png").exists())
print("Top-left pixel:", image.getpixel((0, 0)))

region = pyautogui.screenshot(region=(0, 0, 400, 300))
region.save("region-test.png")
print("Region size:", region.size)

# Re-open the file to verify that writing and reading work.
with Image.open("screen-test.png") as saved:
    print("Saved file reads as:", saved.size, saved.format)

A normal result is an image file whose dimensions and visible content correspond to the display you are using. PyAutoGUI documentation describes roughly 100 milliseconds for a 1,920 × 1,080 full-screen screenshot and about one to two seconds for a locate call; these are documentation estimates, not performance guarantees.

Fix import and dependency errors

Confirm the interpreter and Pillow

Use the interpreter that launches the script:

python -c "import sys, pyautogui, PIL; print(sys.executable); print(pyautogui.__version__); print(PIL.__version__)"

If import PIL fails, install Pillow into that exact environment:

python -m pip install --upgrade Pillow PyAutoGUI

Do not install into one Python installation and run the script with another. In an IDE, compare the selected interpreter with sys.executable.

Linux capture packages

PyAutoGUI’s installation documentation lists scrot, Tkinter, and Python development headers for Linux. Install the packages appropriate to your distribution, then verify the executable is visible to the same user:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
which scrot
python -c "import tkinter; print('Tkinter OK')"

Package names vary by distribution, so follow the installation instructions for your release. A successful Python import does not prove that the operating-system capture utility or display connection is available.

macOS and Windows backends

On macOS, PyAutoGUI invokes the system screencapture command. On Windows, the project description says it uses Windows APIs through Python’s built-in ctypes; Pillow remains a screenshot dependency. Check that the script runs in an interactive desktop session rather than a service or disconnected remote session.

When the screenshot is black, blank, or transparent

Check for a real desktop session

A headless process, locked workstation, disconnected remote desktop, virtual machine without a graphical session, or container without display access may have no pixels to capture. Run the diagnostic while logged into the desktop locally, then compare the result with the same script launched by your scheduler or service. Record the operating system and version, Python, PyAutoGUI and Pillow versions, Linux display server/session, and whether the process is local, remote, or headless.

Inspect the image before changing matching code

Open screen-test.png in an image viewer and inspect several pixels. If it is uniformly black or blank, locateOnScreen() is not the problem. Test a small visible region and a full-screen image separately. If both are blank, investigate the display session and platform backend; if only one is blank, check the region coordinates and monitor arrangement.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Linux display differences

Pillow’s current ImageGrab documentation describes X11 capture and says that, when the default X11 display returns no snapshot, it may fall back to gnome-screenshot, grim, or spectacle when installed. This is Pillow behavior for the documented versions, not a guarantee that every PyAutoGUI release or desktop environment will handle Wayland, permissions, or privacy restrictions identically. Identify the active display session and test the installed stack rather than assuming one universal Linux fix.

macOS permissions

PyAutoGUI’s documented backend is screencapture. If a capture is blank or fails on a current macOS release, check the system’s privacy and screen-capture settings for the application that actually launches Python (Terminal, IDE, agent, or service), then retest the minimal script. The cited documentation does not establish one permission procedure for every macOS version.

When the screenshot has the wrong size

Compare logical and actual dimensions

Print both values:

import pyautogui

logical = pyautogui.size()
shot = pyautogui.screenshot()
print("logical:", logical)
print("image:", shot.size)
print("scale:", shot.width / logical.width, shot.height / logical.height)

A saved image with a different size is not automatically a failed write. Multiple monitors, display scaling, remote-desktop settings, and Retina rendering can produce different coordinate spaces.

Retina and high-density displays

Pillow documents macOS Retina captures at twice the logical dimensions by default. Its scale_down=True option was added in Pillow 12.3.0, but you should not assume that a PyAutoGUI screenshot call exposes that Pillow option. Instead, make the screenshot and template use the same scale, or resize one deliberately after capture. Keep region coordinates consistent with the coordinate convention used by the API.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Historical Windows DPI reports

A PyAutoGUI issue opened December 21, 2016 reports undersized screenshots on Windows 10 with Python 3.5.2, PyAutoGUI 0.9.33, and PIL 3.4.2; the reporter described a DPI-scaling compatibility workaround. Those versions and the date matter. Treat it as a troubleshooting clue, not a current blanket prescription. Confirm dimensions and the process’s DPI context on the Windows, Python, PyAutoGUI, and Pillow versions you actually support.

Test a known region

Use a region whose coordinates are known to be visible:

shot = pyautogui.screenshot(region=(100, 100, 800, 600))
print(shot.size)  # expected: (800, 600)
shot.save("known-region.png")

If the region is the requested size but contains the wrong area, your origin, monitor layout, scaling, or window position is wrong. If it is not the requested size, inspect the backend and version combination.

When locateOnScreen() cannot find the image

Prove the target is in the current capture

Save a fresh full-screen image and visually confirm that the target appears at the same rendered size, theme, zoom, and state as the template. A template copied from a Retina display, browser zoom level, dark theme, or different font rendering may not match the current screen.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
import pyautogui

try:
    box = pyautogui.locateOnScreen("button-template.png")
    print("Found:", box)
except pyautogui.ImageNotFoundException:
    print("Template was not found in the current screenshot")

Current PyAutoGUI documentation says a failed locate raises ImageNotFoundException. Handle that exception explicitly instead of treating a missing match as a capture failure.

Match scale and appearance

  • Crop the template from the same display scale used at runtime.
  • Use the same browser zoom, OS scaling, application theme, and window state.
  • Remove transient badges, animations, cursor changes, and dynamic text from the template.
  • Capture a smaller, distinctive control rather than a large area containing changing pixels.
  • Use a region to reduce unrelated content and speed the search.

Use confidence only with OpenCV

The optional confidence argument requires OpenCV. Install it in the active interpreter before using it:

python -m pip install opencv-python
box = pyautogui.locateOnScreen(
    "button-template.png",
    confidence=0.85,
    region=(0, 0, 1200, 900)
)
print(box)

A lower confidence can increase false positives; it cannot correct an incorrectly scaled or absent target. If matching remains unreliable, log the screenshot, template dimensions, display scale, and search region for each failed run.

A repeatable troubleshooting workflow

  1. Record the environment. Note OS/version, Python, PyAutoGUI, Pillow, desktop/display session, monitor scaling, and whether execution is local, remote, scheduled, or headless.
  2. Verify imports. Run import pyautogui and import PIL with the production interpreter.
  3. Check platform dependencies. On Linux, verify the documented packages and capture utility; on macOS, verify the system backend; on Windows, check the actual DPI and desktop context.
  4. Capture full screen. Save and inspect the image and dimensions before any locate call.
  5. Capture a region. Confirm that a known rectangle returns the requested dimensions and expected pixels.
  6. Resolve scale. Compare pyautogui.size(), image size, monitor scaling, and template size.
  7. Debug matching separately. Confirm the target is present, then adjust template, region, appearance, or OpenCV confidence.
  8. Retest in the real launcher. A script that works in an interactive terminal may fail under a service, CI runner, remote session, or different user account.

Performance, reliability, and design choices

Full-screen captures and locate calls are not instantaneous. The documentation’s approximate 100-millisecond capture and one-to-two-second locate figures are for a 1,920 × 1,080 screen and should be treated as rough guidance. Prefer a small region, avoid repeated full-screen searches, and wait for a stable UI state before capturing.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

For reliable automation, log the capture path, image dimensions, region, display scale, and exception type. Keep a diagnostic screenshot for failures, but protect sensitive screen contents. Do not use a screenshot match as the only confirmation for a destructive action; combine it with application state or a second check.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup

If your goal is a clean website image rather than an interactive desktop capture, ScreenshotNeo provides a website screenshot API and MCP server. One GET request returns PNG, JPEG, WebP, or PDF. Before capture it accepts cookie/consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each cleanup step can be turned off. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing status.

Here is the cURL call (the ScreenshotNeo docs cover all options):

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 buffer = Buffer.from(await res.arrayBuffer());
require('fs').writeFileSync('shot.webp', buffer);

ScreenshotNeo also offers full-page captures with lazy images loaded, CSS-selector element shots, dark mode, device presets and custom viewports, retina scale, PDF paper and page controls, custom CSS and JavaScript, click-before-capture, selector hiding, waits for selectors/delays/network idle, request and resource blocking, headers/cookies/user agents/Authorization, timezone and geolocation, transparent backgrounds, resizing, chosen-TTL caching, signed image links, asynchronous jobs with signed webhooks, bulk capture for up to 100 URLs per call, a usage API, an OpenAPI specification, and compatible parameter names used by other screenshot APIs.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

An MCP server exposes take_screenshot, get_page_info, and capture_pdf to Claude, Cursor, and other MCP clients, so AI agents can capture pages without your own browser setup. Every plan includes every feature: 1,000 shots/month free with no card; Starter is $5 for 3,000, Growth $15 for 15,000, Pro $39 for 60,000, Scale $99 for 250,000, and Business $249 for 1,000,000. Yearly billing gives two months free.

Create a free ScreenshotNeo account to use the 1,000 monthly screenshots without a card.

Frequently asked questions

Does saving a PNG prove the screenshot is correct?

No. It proves that an image was produced and written. Inspect its pixels, dimensions, and visible content in the same execution environment.

Why does a template work on one monitor but not another?

Rendered size, DPI scaling, browser zoom, fonts, theme, and monitor coordinates can differ. Capture the template at the runtime scale or normalize both images.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Can PyAutoGUI capture a browser page without the browser being visible?

PyAutoGUI captures the desktop, so the browser must be rendered in an accessible graphical session. For a server-side website image, use an API such as ScreenshotNeo instead.

What should I include in a bug report?

Include OS and display session, Python/PyAutoGUI/Pillow versions, interpreter path, monitor scaling, whether the run is remote or headless, the minimal script, reported and actual image sizes, and a sanitized sample image or pixel inspection.

Frequently Asked Questions

Does saving a PNG prove the screenshot is correct?

No. It proves that an image was produced and written. Inspect its pixels, dimensions, and visible content in the same execution environment.

Why does a template work on one monitor but not another?

Rendered size, DPI scaling, browser zoom, fonts, theme, and monitor coordinates can differ. Capture the template at the runtime scale or normalize both images.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Can PyAutoGUI capture a browser page without the browser being visible?

PyAutoGUI captures the desktop, so the browser must be rendered in an accessible graphical session. For a server-side website image, use an API such as ScreenshotNeo instead.

What should I include in a bug report?

Include OS and display session, Python/PyAutoGUI/Pillow versions, interpreter path, monitor scaling, whether the run is remote or headless, the minimal script, reported and actual image sizes, and a sanitized sample image or pixel inspection.

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.