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 glitchesCall driver.get_screenshot_as_png(), then pass the returned PNG bytes to numpy.frombuffer:
png_bytes = driver.get_screenshot_as_png()
png_byte_array = np.frombuffer(png_bytes, dtype=np.uint8)
This produces a one-dimensional NumPy array containing the encoded PNG file bytes—not a height-by-width matrix of pixels. Decode the PNG first when your image-processing code needs pixel values.
What the Selenium result actually contains
Selenium’s get_screenshot_as_png() method returns Python bytes. Selenium obtains the browser’s base64 screenshot response and decodes it before returning those bytes. The Selenium WebDriver API documentation describes the return value, and the NumPy frombuffer reference documents how a buffer becomes a one-dimensional array.
Consequently, this array represents a PNG file in memory:
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 →#1 Best Overall
import numpy as np
png_bytes = driver.get_screenshot_as_png()
png_byte_array = np.frombuffer(png_bytes, dtype=np.uint8)
print(type(png_bytes)) # bytes
print(png_byte_array.dtype) # uint8
print(png_byte_array.ndim) # 1
print(png_byte_array.shape) # (number_of_png_bytes,)
The values are compressed PNG data, including PNG headers and image chunks. They are not directly addressable as [row, column, channel] pixels. Do not reshape this array into guessed dimensions; the encoded length does not reveal the image’s pixel layout.
Set up a complete Python capture
Install the packages in the environment that will run your test or service:
python -m pip install selenium numpy pillow
Use the browser-driver setup appropriate for your environment. This example uses Selenium’s Chrome driver and keeps the screenshot in memory:
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import numpy as np
options = Options()
options.add_argument('--headless=new')
driver = webdriver.Chrome(options=options)
try:
driver.get('https://example.com')
png_bytes = driver.get_screenshot_as_png()
png_byte_array = np.frombuffer(png_bytes, dtype=np.uint8)
print(f'PNG bytes: {png_byte_array.size}')
finally:
driver.quit()
The driver.quit() call belongs in a finally block so a failed navigation or conversion does not leave a browser process running. If your project uses Firefox, a remote Selenium server, or a preconfigured driver service, replace only the driver initialization.
Convert the screenshot into a pixel NumPy array
For computer vision, OCR, color analysis, or image arithmetic, decode the PNG before converting it. Pillow can read the in-memory bytes through a file-like buffer:
Rank #2
import io
import numpy as np
from PIL import Image
png_bytes = driver.get_screenshot_as_png()
image = Image.open(io.BytesIO(png_bytes))
pixels = np.asarray(image)
print(image.mode) # for example, RGB or RGBA
print(pixels.shape) # for example, (height, width, channels)
print(pixels.dtype) # normally uint8 for an 8-bit screenshot
The shape depends on the decoded image mode. An RGB image has three channels; an image with transparency has four. Inspect image.mode and pixels.shape rather than assuming a fixed channel count. If a downstream library requires ownership of the memory, use np.array(image) or np.asarray(image).copy().
The two operations serve different purposes:
- Encoded bytes: use
get_screenshot_as_png()directly for upload, hashing, storage, or writing a PNG. - One-dimensional byte array: use
np.frombuffer(png_bytes, dtype=np.uint8)for byte-level NumPy operations while retaining the PNG encoding. - Pixel matrix: decode the PNG, then convert the decoded image to NumPy.
Understand frombuffer‘s view behavior
np.frombuffer interprets the existing buffer and normally returns a one-dimensional view rather than copying every byte. That is efficient for large screenshots, but it also means the array is tied to the source buffer’s memory characteristics. NumPy’s reference advises considering a copy when the input is mutable or untrusted.
png_bytes = driver.get_screenshot_as_png()
view = np.frombuffer(png_bytes, dtype=np.uint8)
owned_copy = view.copy()
# Use owned_copy when later code must freely mutate the byte array.
In normal Selenium usage, the returned object is an immutable bytes value, so a read-only view is usually sufficient. Copy only when your processing pipeline requires independent, writable storage.
Save the screenshot instead of keeping it in memory
If you need a file, Selenium provides save_screenshot(path) and get_screenshot_as_file(path). Both write PNG data and return True on success or False on an I/O error. Selenium expects the filename to end in .png and warns when it does not.
ok = driver.save_screenshot('artifacts/home.png')
if not ok:
raise OSError('Selenium could not save the screenshot')
# Equivalent file-oriented method:
ok = driver.get_screenshot_as_file('artifacts/home-2.png')
if not ok:
raise OSError('Selenium could not save the second screenshot')
You can still create a NumPy byte array after saving, but that requires reading the file back. Capturing with get_screenshot_as_png() avoids that extra disk round trip when the next step is in-memory processing.
Use the base64 method only when text transport is useful
get_screenshot_as_base64() returns a base64-encoded string, which Selenium documents as useful for embedding an image in HTML. Decode it before using a byte-buffer workflow:
import base64
import numpy as np
encoded = driver.get_screenshot_as_base64()
png_bytes = base64.b64decode(encoded)
png_byte_array = np.frombuffer(png_bytes, dtype=np.uint8)
When your destination accepts binary data, prefer get_screenshot_as_png(); it avoids the base64 expansion and an explicit decode step.
Recommended Free Tools
Choose the representation your next step needs
| Need | Use | Result |
|---|---|---|
| Send or store a PNG without decoding | driver.get_screenshot_as_png() |
Python bytes |
| Perform byte-level NumPy work | np.frombuffer(png_bytes, dtype=np.uint8) |
One-dimensional uint8 array of encoded PNG bytes |
| Inspect or transform pixels | Decode PNG, then np.asarray(image) |
Height-by-width array with channels determined by image mode |
| Persist a PNG directly | save_screenshot or get_screenshot_as_file |
PNG file and a Boolean success result |
| Embed in HTML as text | get_screenshot_as_base64() |
Base64 string |
A reusable function for both byte and pixel workflows
Keep capture and interpretation separate so callers cannot accidentally treat compressed bytes as pixels:
import io
import numpy as np
from PIL import Image
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
def capture_png_bytes(driver) -> bytes:
return driver.get_screenshot_as_png()
def png_bytes_to_array(png_bytes: bytes) -> np.ndarray:
"""Return the encoded PNG as a one-dimensional uint8 array."""
return np.frombuffer(png_bytes, dtype=np.uint8)
def png_bytes_to_pixels(png_bytes: bytes) -> np.ndarray:
"""Decode PNG data and return an array of image pixels."""
with Image.open(io.BytesIO(png_bytes)) as image:
return np.asarray(image).copy()
options = Options()
options.add_argument('--headless=new')
driver = webdriver.Chrome(options=options)
try:
driver.get('https://example.com')
data = capture_png_bytes(driver)
encoded = png_bytes_to_array(data)
pixels = png_bytes_to_pixels(data)
print('encoded:', encoded.shape, encoded.dtype)
print('pixels:', pixels.shape, pixels.dtype)
finally:
driver.quit()
The copy in png_bytes_to_pixels makes the returned pixel array independent of Pillow's image object after the context closes. Keep the encoded array and pixel array under different variable names; that simple convention prevents many downstream shape errors.
Troubleshoot common failures
AttributeError: 'WebDriver' object has no attribute ...
Check that you are calling the method on the Selenium driver instance, not on a WebElement or a NumPy array. The method name is get_screenshot_as_png(), including the final s in screenshots.
The array has shape such as (184532,), not an image shape
That is expected for encoded PNG data. Decode the bytes with an image decoder before converting to pixels. Do not reshape the encoded vector based on a guessed browser width or height.
The browser starts, but capture fails or returns no usable page
Verify that the navigation completed, the driver and browser versions are compatible, and the process has permission to run in its environment. For dynamic pages, wait for the element or state your test requires before calling the screenshot method. A screenshot captures the browser's current state; it does not make asynchronous application work complete.
save_screenshot returns False
Check the destination directory, write permissions, and the filename extension. Create the directory before capture and use a path ending in .png.
Pillow cannot open the bytes
Confirm that the value passed to Image.open is the raw result of get_screenshot_as_png(), or that a base64 result was decoded with base64.b64decode first. Do not pass the one-dimensional NumPy array as though it were already a decoded image; use png_byte_array.tobytes() if you need to reconstruct the original byte stream.
The pixel array is read-only or changes unexpectedly
Remember that frombuffer can expose a view. Call .copy() when you need writable, independently owned data, and avoid mutating an array that another part of the pipeline still uses.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Best Value
Performance and reliability considerations
- Avoid unnecessary conversions. Keep the Selenium bytes when transporting a screenshot. Convert to a NumPy byte view only when NumPy operations are actually useful.
- Decode once. If several image operations are required, create one pixel array and pass it to those operations instead of repeatedly opening the PNG.
- Control browser lifetime. Reuse a driver for a planned sequence of pages, but always call
quit()in cleanup code. A new browser for every image adds startup overhead. - Make readiness explicit. Navigate, wait for the page state your test needs, and then capture. This is more reliable than assuming a fixed sleep is sufficient for every page.
- Record which representation you save. A file containing PNG bytes and a serialized pixel array are different artifacts. Preserve the format in filenames, metadata, or both.
The Selenium documentation pages surfaced for this method are labeled Selenium 4.49.0. The buffer semantics cited above are in the NumPy 2.1 reference; the current NumPy reference landing page identifies NumPy 2.5 and gives the manual date as June 28, 2026. Check the versions installed in your target environment before depending on behavior beyond these stable method contracts: NumPy reference landing page.
Or skip the browser setup
If you need a screenshot from an application or pipeline rather than a locally controlled browser, ScreenshotNeo is the first API option to try: it returns clean shots, bills only clean shots, and its paid entry plan is $5 for 3,000 shots.
One GET request returns PNG, JPEG, WebP, or PDF output. See the complete parameter reference in the ScreenshotNeo documentation.
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(`Screenshot failed: ${res.status}`);
const buffer = Buffer.from(await res.arrayBuffer());
await import('node:fs/promises').then(fs => fs.writeFile('shot.webp', buffer));
- Consent banners, newsletter popups, and chat widgets are accepted or removed before capture; each cleanup step can be turned off.
- Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing. Response headers report the page verdict and whether the request was billed (
X-Page-VerdictandX-Billed). - An MCP server provides
take_screenshot,get_page_info, andcapture_pdftools for 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. Yearly billing gives two months free.
Create a free ScreenshotNeo account to try the 1,000 monthly screenshots without a card.
The Tool Desk
Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Frequently Asked Questions
Does a Selenium screenshot wait for every JavaScript request to finish?
No. Capture reflects the browser state at the moment you call the method. Wait for the specific element, condition, or application state your test requires before calling get_screenshot_as_png().
Can I reconstruct the PNG after making a NumPy byte array?
Yes. png_byte_array.tobytes() produces the encoded byte stream again, which an image decoder or file writer can consume.
Which NumPy version should I install?
Use the version supported by your project and verify it in your environment. The buffer behavior described here is documented in NumPy 2.1, while the current reference landing page identifies NumPy 2.5.
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.

