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.
Recommended Free Tools
#1 Best Overall
- 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.
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.
Rank #2
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:
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.
The Tool Desk
Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →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.executableandPIL.__file__again. - Run
python -m pip show Pillowwith 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.
Do these 3 things before closing this tab:
1Clear out junk files and repair common Windows errors2Fix the driver behind crashes, sound loss and screen glitches3Repair Windows errors before they cause bigger problemsAn 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:
PC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minuteimport 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.
Best Value
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.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-VerdictandX-Billedheaders 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.
Quick wins for a faster PC:
Scan for outdated or missing drivers - takes under a minuteDriver Scan →Repair Windows errors before they cause bigger problemsFix Now →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.
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.

