How to Take a Screenshot of a Webpage Using Python and Playwright
Capture a webpage with Python and Playwright. Set up browsers, save viewport or full-page screenshots, target elements, and troubleshoot common issues.
Use Playwright’s Python package to launch a browser, navigate to a webpage, and save a screenshot. The synchronous example below captures the visible viewport; add full_page=True to capture the full scrollable page. Playwright also supports async code, screenshots of individual elements, and returning image bytes instead of writing a file.
1. Install Playwright and its browsers
Install the Python package, then download the browser binaries Playwright uses. The install command includes Chromium, Firefox, and WebKit. This example uses Chromium.
python -m pip install playwright
playwright install
If your project uses Poetry or uv, install the Playwright package with your project’s package manager, then run playwright install in the same environment. The browser binaries are separate from the Python package, so installing the package alone may not be enough to launch a browser. See the Playwright Python installation guide.
2. Capture a webpage with synchronous Python
Save this as screenshot.py and run python screenshot.py. Replace the example URL with the page you want to capture.
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch()
page = browser.new_page()
page.goto("https://example.com")
page.screenshot(path="screenshot.png")
browser.close()
The screenshot is written to screenshot.png in the current working directory. By default, the browser runs headless, so this script can run without opening a visible browser window. The basic sequence is launch a browser, create a page, navigate, capture, and close the browser. See the Playwright Screenshots guide.
3. Capture the full page or one element
Full-page screenshot
Set full_page=True to capture the full scrollable page rather than just the current viewport:
page.screenshot(path="full-page.png", full_page=True)
Full-page screenshots can be much taller and larger than viewport captures. Long pages may take more time to render and produce larger image files.
Screenshot of a specific element
Use a locator’s screenshot method to capture just the matching element. Choose a selector that identifies the intended element reliably:
page.locator(".header").screenshot(path="header.png")
You can also use a role locator when the element has an accessible role and name:
page.get_by_role("banner").screenshot(path="header.png")
Locator screenshots wait for the target element to be visible. If a page has multiple matches for a selector, make the locator specific enough to identify the element you intend to capture. The locator screenshot API supports animation handling; for example, set animations="disabled" to stop CSS animations, transitions, and Web Animations during capture. The default is "allow".
page.locator(".header").screenshot(
path="header.png",
animations="disabled",
)
See the Locator screenshot API reference for locator-specific options.
4. Use Playwright’s async API
For an asyncio application, use Playwright’s async interface consistently and await browser operations. Save as async_screenshot.py and run it with Python:
import asyncio
from playwright.async_api import async_playwright
async def main():
async with async_playwright() as p:
browser = await p.chromium.launch()
page = await browser.new_page()
await page.goto("https://example.com")
await page.screenshot(path="screenshot.png")
await browser.close()
asyncio.run(main())
Use the sync API in a regular synchronous script and the async API when the surrounding program already uses asyncio. Do not call the sync interface from inside an async event loop.
5. Choose the screenshot output and options
The screenshot API supports options for image format, clip area, and quality, among others. Check the current Page screenshot API reference for supported parameters and details.
- Viewport or full page: omit
full_pagefor the current viewport; setfull_page=Truefor the scrollable page. - One element: call
screenshot()on a locator instead of the page. - File or bytes: provide
path="screenshot.png"to write a file. Omitpathto receive image bytes you can process or send elsewhere. - Format and quality: select a supported image format and, where supported, tune quality. Consult the API reference for format-specific behavior.
- Clip area: use the screenshot API’s clip option when you need a rectangular region rather than the whole viewport or a locator.
- Animation behavior: locator screenshots accept
animations="disabled"to stop animations for the capture; the default is"allow".
Keep the screenshot bytes in memory
When you omit path, Playwright returns the screenshot as bytes. For example:
image_bytes = page.screenshot()
# Pass image_bytes to an image-processing or storage library.
6. Make capture timing more reliable
A screenshot taken immediately after navigation may not reflect content that loads later. Wait for a page state or element that matches the site and task before capturing. For example, wait for a page heading that marks the content you need:
page.goto("https://example.com")
page.get_by_role("heading", name="Example Domain").wait_for()
page.screenshot(path="screenshot.png")
Pick a meaningful readiness condition: a visible heading, a specific locator, or another signal your page provides. A fixed delay can help when a known delayed element is expected, but it makes every run wait the same amount and can still be too short if the page is slower than expected.
For repeatable captures, use a stable viewport and control animated content when it matters. Close the browser after capture, including when an exception occurs; in longer-lived programs, use a try/finally block to ensure resources are released.
7. Troubleshooting common issues
| Symptom | Likely cause | Fix |
|---|---|---|
| Browser executable is missing | The Playwright package is installed, but its browser binaries are not. | Run playwright install in the same environment as the script. |
Import error for playwright |
The package was installed into a different Python environment. | Activate the intended virtual environment and install with python -m pip install playwright. |
| Screenshot is blank or missing page content | The page may still be loading, or the content may appear only after an interaction or delayed request. | Wait for a task-specific locator or readiness signal before capturing; check the destination URL and page behavior. |
| Element locator times out | The selector does not match, the element is not visible, or it has not loaded. | Check the selector against the page, wait for the correct element, and make the locator specific if there are several matches. |
| Only the visible screen is captured | The screenshot call defaults to the viewport. | Pass full_page=True for the whole scrollable page. |
| Output file is not where expected | A relative path is resolved from the script’s current working directory. | Use an absolute path or check the directory from which you ran Python. |
| Async code reports an event-loop or await error | Sync and async APIs are being mixed, or an async call is missing await. |
Use imports from playwright.async_api and await the async operations throughout. |
8. Performance, reliability, and cost
Playwright runs a real browser, so each capture uses browser startup, navigation, rendering, and image encoding. Reuse a browser for multiple pages in a batch rather than launching a new browser for every screenshot, and close it when the batch finishes. Keep captures scoped to the viewport or a single element when a full-page image is not needed; a long page produces more image data.
For reliability, wait for the content your screenshot depends on and close browser resources on both success and failure. Network speed, page scripts, fonts, and third-party resources can affect how long a capture takes and what appears in it. Screenshot output and browser execution happen in your environment; account for that compute and storage in your own costs. The cited Playwright docs do not publish a benchmark for capture speed or a per-screenshot price.
9. Or skip the browser setup
ScreenshotNeo is a website screenshot API: one request returns an image or PDF. Its API documentation describes the available parameters. Here is a runnable cURL example:
curl -G "https://api.screenshotneo.com/v1/shot" \
-d access_key=YOUR_API_KEY \
--data-urlencode url=https://example.com \
-o shot.webp
The equivalent Python request is:
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://example.com"},
timeout=90,
)
open("shot.webp", "wb").write(r.content)
And with Node.js:
const q = new URLSearchParams({
access_key: 'YOUR_API_KEY',
url: 'https://example.com',
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await import('node:fs/promises').then(fs => fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer())));
ScreenshotNeo removes cookie banners, newsletter popups, and chat widgets before the shot. Bot checks, blank pages, and failed loads are never billed. Its MCP server lets AI agents take screenshots. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. Sign up for 1,000 free screenshots a month.
10. Frequently asked questions
Can Playwright take screenshots in Firefox or WebKit?
Yes. Install the browser binaries with playwright install, then launch p.firefox or p.webkit instead of p.chromium.
Can I capture a page without saving an image file?
Yes. Call page.screenshot() without a path and use the returned bytes in memory.
Does a screenshot include content below the fold?
Only when you request a full-page capture with full_page=True; the default captures the viewport.
Can I capture a chart or card without the surrounding page?
Yes. Locate the chart or card and call screenshot() on that locator.


