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

Fix the error by installing or upgrading Pillow in the exact Python environment that runs your program, then use the supported from PIL import ImageGrab API. The _grabscreen name belongs to an older PIL/ImageGrab implementation. Do not download or install a separate package called _grabscreen. After the import is repaired, screen capture still depends on your operating system, display session and, on Linux, XCB or an available capture utility.

What the error actually means

A traceback such as ImportError: No module named _grabscreen usually comes from legacy code that executes an internal import while loading PIL.ImageGrab. The private module was part of an old implementation, not the public interface you should manage today. The traceback alone does not reveal which PIL/Pillow version is installed, whether another Python interpreter is being used, or whether the failure occurs in a desktop session.

Modern Pillow exposes screen capture through ImageGrab.grab(). Pillow documents support for Windows, macOS and Linux. Linux support was added in Pillow 7.1.0, while macOS support dates to Pillow 3.0.0; those are historical feature milestones, not versions you should deliberately install today.

Step 1: prove which Python and Pillow your script uses

Installing a package with one interpreter does not change imports made by another. This is especially common with virtual environments, IDE run configurations, notebooks and operating-system Python installations.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  1. Run this diagnostic with the same command or interpreter that launches your application:
python -c "import sys; print(sys.executable); import PIL; print(PIL.__version__); print(PIL.__file__)"

On systems where python refers to Python 2 or is unavailable, use python3. The output should identify the interpreter path, Pillow version and the package location. If importing PIL fails, continue with the installation step below. If the path is not your virtual environment or IDE interpreter, correct that configuration before changing packages.

Check the interpreter used by a virtual environment

# Windows PowerShell
..venvScriptspython.exe -c "import sys; print(sys.executable)"

# macOS or Linux
./.venv/bin/python -c "import sys; print(sys.executable)"

Use that same executable for both package installation and your program. This avoids silently modifying a different Python installation.

Step 2: install current Pillow in that environment

Pillow is the maintained replacement for the original PIL project. Install or upgrade it with the interpreter selected in Step 1:

python -m pip install --upgrade Pillow

For Python 3 when python is not the correct command:

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
python3 -m pip install --upgrade Pillow

Using python -m pip ties pip to that Python executable. If your project has a dependency lock file, update it according to the project’s normal process rather than mixing a global installation with a locked environment.

Remove an obsolete PIL package if both are installed

Old PIL and Pillow both provide a top-level PIL package. A stale copy can win the import search path even after Pillow is installed. Inspect the path printed in Step 1. If it points to an old application-bundled or system directory, remove that obsolete package using the environment’s package manager or recreate the virtual environment. Do not delete files from a system Python directory blindly.

Step 3: switch to the supported capture call

Use this minimal program after Pillow imports successfully:

from PIL import ImageGrab

image = ImageGrab.grab()
image.save("screen.png")
print("Saved screen.png", image.size)

For a rectangular region, pass a four-item bounding box:

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

# left, top, right, bottom
image = ImageGrab.grab(bbox=(100, 100, 900, 700))
image.save("region.png")

Keep application code on this public API. Code that directly imports _grabscreen, or depends on private files inside PIL, should be migrated rather than repaired by copying an internal module.

Platform checks that remain after the import is fixed

Platform or situation What to verify Likely limitation
Windows Interpreter/Pillow match and an interactive desktop session A service, locked session or restricted desktop may not expose a capturable screen.
macOS Current Pillow and the application’s screen-capture permission The operating system can deny capture even though the Python import works.
Linux/X11 Pillow version, XCB support, DISPLAY and access to the X session Headless shells and missing display permissions commonly cause capture failures.
Linux fallback Whether gnome-screenshot, grim or spectacle is installed and usable The available command depends on the desktop/session type; installing one does not solve an inaccessible display.

Linux: check XCB and the display session

Pillow documents an XCB feature check for the X11 path used by ImageGrab.grab():

python -c "from PIL import features; print(features.check_feature('xcb'))"

True means the installed Pillow build reports XCB support; it does not guarantee that your current user can access a display. Check whether a display variable exists:

echo "$DISPLAY"
python -c "from PIL import ImageGrab; ImageGrab.grab().save('test.png')"

An empty DISPLAY, an SSH session without display forwarding, a container without an X socket, or a Wayland/X11 permission boundary can prevent capture. On supported Linux setups, Pillow may use gnome-screenshot, grim or spectacle when the default path does not produce an image. Install only the utility appropriate to your desktop and verify it can capture outside Python first.

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

Headless automation

A server or CI runner normally has no real desktop to capture. Installing Pillow cannot create one. Use a configured virtual display when your test genuinely needs a desktop, or capture the web page itself with a browser automation or screenshot service. Treat a blank image, timeout or permission error as an environment problem rather than another missing Python module.

Common symptoms and precise fixes

The same _grabscreen error remains

  • Print sys.executable and PIL.__file__ again.
  • Run python -m pip show Pillow with that exact interpreter.
  • Remove or rebuild an environment containing the obsolete PIL package.
  • Restart the IDE, notebook kernel or long-running process after changing packages.

ModuleNotFoundError: No module named PIL

Pillow is not installed in the active interpreter. Run python -m pip install Pillow using the interpreter path printed by your program, then retry.

The import succeeds but grab() fails

Check the desktop/display conditions in the platform table. On Linux, check XCB and the display variable; on macOS, allow the application screen recording permission; on Windows, avoid running the capture code as a non-interactive service. A successful import proves only that Python found Pillow.

The result is black, blank or incomplete

Confirm that the target desktop is actually rendered and unlocked, test a full-screen grab before a bbox, and verify the session type and permissions. For web pages, browser overlays, consent dialogs and lazy content can also make an apparently successful capture unusable; a page-oriented capture workflow may be more appropriate.

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

An upgrade is prohibited by an old application

First identify the application’s Python and dependency constraints. If Pillow cannot be upgraded, isolate the legacy environment and evaluate an operating-system-appropriate capture API rather than copying _grabscreen into the project. The right alternative depends on platform, display server, required capture region and whether the process is interactive.

Verify the repair with a repeatable test

from PIL import ImageGrab

try:
    shot = ImageGrab.grab()
    shot.save("pillow-capture.png", format="PNG")
except Exception as exc:
    raise SystemExit(f"Screen capture failed: {exc}")
else:
    print(f"Captured {shot.width}x{shot.height} to pillow-capture.png")

Run it from the same shell, virtual environment and user session as the real application. A generated file with the expected dimensions confirms the Python import and basic capture path; it does not prove that every future server, login state or display session will work.

Or skip the browser setup

If your real goal is a screenshot of a public web page rather than the physical desktop, ScreenshotNeo avoids local display configuration. It accepts a URL and 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 disabled. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads and cache hits are not billed, and response headers identify the page verdict and billing result.

One request is enough:

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

See the ScreenshotNeo API documentation for authentication, output and options. The same request in Python is:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
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 data = Buffer.from(await res.arrayBuffer());
await import('node:fs/promises').then(fs => fs.writeFile('shot.webp', data));

ScreenshotNeo also supports full-page captures with lazy images loaded, CSS-element capture, device presets, arbitrary viewports, retina scale, PDF settings, custom CSS and JavaScript, clicks, selector waits, delays, network-idle waits, request/resource blocking, headers, cookies, user agents, authorization, timezone, geolocation, transparent backgrounds, resizing, chosen cache TTLs, signed image links, asynchronous jobs with signed webhooks, bulk capture of up to 100 URLs per call, usage reporting and an OpenAPI specification. An MCP server exposes take_screenshot, get_page_info and capture_pdf to Claude, Cursor and other MCP clients.

The Free plan includes 1,000 screenshots per month with no card. Paid plans start at $5 for 3,000 shots; every feature is available on every plan. Create a free ScreenshotNeo account to try it.

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

Cost, reliability and security considerations

  • Local Pillow capture has no per-image service charge, but it requires a functioning desktop, display permissions and maintenance of the Python environment.
  • Do not place API keys in browser JavaScript, public repositories or client-side HTML. Store them in environment variables or a server-side secret store.
  • For repeatable web captures, set an explicit wait condition, viewport, timezone and user agent when the page depends on them. Use caching deliberately: a cache hit is identified in the response and is not billed by ScreenshotNeo.
  • Check X-Page-Verdict and X-Billed headers when diagnosing an unexpected result or charge.

FAQ

Can I install a package named _grabscreen?

No. It is an internal name from an old capture implementation. Install Pillow in the active interpreter and use ImageGrab.grab().

Does upgrading Pillow guarantee Linux screenshots?

No. Linux capture also requires a compatible build, XCB/display access or a usable fallback utility.

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

Is this error proof that my Python version is wrong?

No. It identifies a legacy import path, but only the interpreter and package-path checks can show which installation your script is loading.

Frequently Asked Questions

Can I install a package named _grabscreen?

No. It is an internal name from an old capture implementation. Install Pillow in the active interpreter and use ImageGrab.grab().

Does upgrading Pillow guarantee Linux screenshots?

No. Linux capture also requires a compatible build, XCB/display access or a usable fallback utility.

Is this error proof that my Python version is wrong?

No. It identifies a legacy import path, but only the interpreter and package-path checks can show which installation your script is loading.

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.

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.