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

Use Pyppeteer’s page.screenshot() method with 'fullPage': True to capture the complete scrollable document instead of only the visible viewport. The example below navigates to a page, waits for network activity to settle, saves a PNG, and always closes Chromium.

Install Pyppeteer and a browser

Pyppeteer is an unofficial Python port of Puppeteer. The project repository says it supports Python 3.8 or newer and warns that the repository is unmaintained and has seen only minor changes for a long time. That status matters for new projects: an existing script may continue to work, but browser-version compatibility can become harder to predict.

  1. Create and activate a virtual environment with Python 3.8 or later.
  2. Install the package:
    python -m pip install pyppeteer
  3. On first use, Pyppeteer may download a Chromium build if it cannot find a suitable local Chrome binary. The project README estimates this download at about 150 MB. You can trigger the download before running your script with:
    pyppeteer-install

The documented API is old (version 0.0.25), so test the exact Pyppeteer and Chromium combination in your deployment environment. Current Puppeteer documentation confirms the general fullPage concept, but it does not guarantee that every Pyppeteer build works with every current Chromium release.

Minimal full-page screenshot

After a page is open and has navigated to its URL, pass a dictionary containing fullPage: True. The option defaults to False, so specifying it explicitly avoids accidentally capturing only the viewport.

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.
await page.screenshot({'path': 'full-page.png', 'fullPage': True})

path writes the image to disk. If you omit path, the method returns screenshot data as bytes, or as a string when you request an encoding.

Complete async example

This runnable script follows the usual launch, page creation, navigation, capture, and shutdown sequence:

import asyncio
from pyppeteer import launch

async def main():
    browser = await launch()
    try:
        page = await browser.newPage()
        await page.goto(
            'https://example.com',
            {'waitUntil': 'networkidle2'}
        )
        await page.screenshot({
            'path': 'full-page.png',
            'fullPage': True
        })
    finally:
        await browser.close()

asyncio.get_event_loop().run_until_complete(main())

Run it with python screenshot.py. The result is a PNG named full-page.png in the current directory. networkidle2 is only an example readiness condition: pages with analytics, live feeds, long polling, or application-specific rendering may never reach the state you want. Use a selector or another condition tied to the content your screenshot must contain.

Make dynamic and lazy-loaded content appear

fullPage expands the capture to the document’s scrollable extent; it does not promise that every delayed image, card, or component has loaded. Many sites request assets only when a section approaches the viewport.

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

Wait for a meaningful selector

When the page has a reliable completion marker, wait for that marker rather than using a fixed sleep:

await page.goto('https://example.com/catalog', {'waitUntil': 'domcontentloaded'})
await page.waitForSelector('.catalog-grid .product-card')
await page.screenshot({'path': 'catalog.png', 'fullPage': True})

Choose a selector that represents the content you need. A selector that appears before images finish loading is not sufficient by itself.

Scroll to trigger lazy loading

For pages that load content near the viewport, scroll in increments and wait briefly for each batch. The delay is site-specific; it is not a universal guarantee.

await page.goto('https://example.com/articles', {'waitUntil': 'domcontentloaded'})

await page.evaluate('''async () => {
  await new Promise((resolve) => {
    let y = 0;
    const step = 600;
    const timer = setInterval(() => {
      window.scrollBy(0, step);
      y += step;
      if (y >= document.body.scrollHeight) {
        clearInterval(timer);
        resolve();
      }
    }, 100);
  });
}''')
await page.waitFor(1000)
await page.screenshot({'path': 'articles.png', 'fullPage': True})

For a robust workflow, replace the fixed one-second wait with an application signal (for example, a “loaded” element) and verify that images have nonzero dimensions before capturing. After scrolling, you can return to the top with await page.evaluate('window.scrollTo(0, 0)') if the page’s final scroll position affects sticky UI.

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

Control viewport and reproducibility

Responsive breakpoints, device scale, fonts, ads, and changing data can make two captures differ. Set a fixed viewport before navigation:

await page.setViewport({
    'width': 1440,
    'height': 900,
    'deviceScaleFactor': 1
})

Use the same browser version, viewport, timezone, locale, authentication state, and readiness condition in automated runs. Freeze or remove dynamic widgets where possible. A full-page screenshot can still change when the site itself changes; Pyppeteer does not provide a universal visual-stability guarantee.

Output formats and screenshot options

The Pyppeteer 0.0.25 API reference documents these options:

Option Purpose
path Writes the image to a file. Omit it to receive returned data.
type png or jpeg. PNG is the documented default.
quality JPEG quality from 0 to 100; it does not apply to PNG.
fullPage Captures the full scrollable page when True.
clip Captures a rectangular region instead of the complete page.
omitBackground Leaves the page background transparent where supported.
encoding Returns base64 or binary data when no file path is supplied.

For JPEG output, use a .jpg path or set type: 'jpeg' and choose a quality value. PNG is often preferable for text and diagrams because it preserves sharp edges; this is format guidance, not a comparative benchmark.

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

Return bytes instead of saving a file

image_bytes = await page.screenshot({
    'fullPage': True,
    'type': 'png',
    'encoding': 'binary'
})
with open('full-page.png', 'wb') as output:
    output.write(image_bytes)

Capture a region

await page.screenshot({
    'path': 'region.png',
    'clip': {'x': 0, 'y': 0, 'width': 800, 'height': 600}
})

clip is useful for a component or viewport-sized crop, but it is not a substitute for fullPage when the requirement is the entire document.

Common failures and fixes

The image contains only the top of the page

Confirm that the option name is exactly fullPage (camel case) and that its value is the Boolean True, not the string 'True'. Also verify that you are capturing the page object you navigated, rather than a newly created blank page.

Images or lower sections are missing

Lazy loading is the usual cause. Wait for a page-specific selector, scroll through the document to trigger requests, and wait for the resulting content. Check that the URLs are reachable from the machine running Chromium and that resources are not blocked by authentication, robots controls, or a failed request.

networkidle2 never finishes

Continuous analytics, WebSockets, polling, or advertisements can keep network activity above the idle threshold. Use domcontentloaded followed by waitForSelector, or implement an application-specific readiness check.

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

Chromium fails to launch

Run pyppeteer-install, confirm that the process has permission to execute the downloaded browser, and inspect the launch error for missing system libraries in your operating system or container. If Chrome is installed at a known location, configure Pyppeteer to use that executable and test its compatibility with your installed package.

Text or layout changes between runs

Set a fixed viewport and device scale factor, use the same browser build and fonts, stabilize logged-in data, and disable or hide volatile widgets. Capture only after the content-specific readiness condition has passed.

The page is unusually tall or Chromium errors on capture

Very large documents can exceed practical browser or image dimensions. Split the job into known sections with clip, capture individual elements, or export a PDF when a paginated document is more appropriate. Remove unnecessary infinite-scroll content before requesting a full-page image.

Pyppeteer versus a maintained alternative

The Pyppeteer repository explicitly labels itself unmaintained. That is a project-maintenance warning, not proof that your current installation is unusable. For a new Python automation project, compare maintenance activity, browser installation, API conventions, and compatibility with the Chromium version you must run.

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

Playwright’s Python API uses full_page=True (snake case) for the same conceptual operation: a screenshot of the entire scrollable page. Playwright is a separate project with its own browser-management and versioning model. No performance or universal compatibility ranking is established here, so choose based on your required browsers, upgrade policy, and readiness controls.

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 you only need a hosted screenshot, ScreenshotNeo accepts one GET request and returns PNG, JPEG, WebP, or PDF. Its API removes cookie and consent banners, newsletter popups, and chat widgets before capture; each cleanup step can be disabled. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing result.

Use the API documentation at https://screenshotneo.com/docs/. A cURL request is:

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)
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}`);

ScreenshotNeo also provides an MCP server for Claude, Cursor, and other MCP clients, with take_screenshot, get_page_info, and capture_pdf tools. Its 63 options include full-page capture with lazy images loaded, CSS-selector element capture, dark mode, 12 device presets plus custom viewports, retina scale, PDF paper and margin controls, custom CSS and JavaScript, pre-capture clicks, selector hiding, selector or delay or network-idle waits, request and resource blocking, custom headers, cookies, user agents and Authorization, timezone and geolocation, transparent backgrounds, resizing, configurable-TTL caching, signed image links, asynchronous jobs with signed webhooks, bulk capture of up to 100 URLs per call, a usage API, and an OpenAPI specification. Parameter names used by other screenshot APIs also work.

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.

The Free plan includes 1,000 shots per month with no card. Paid plans start at $5 for 3,000 shots; every feature is available on every plan, and yearly billing provides two months free. Sign up for the free ScreenshotNeo plan to try it without adding a card.

When Pyppeteer is still the right choice

  • You need browser-side Python logic, authenticated sessions, or custom DOM manipulation before capture.
  • You must run inside your own network, filesystem, or compliance boundary.
  • You need to inspect page state and decide programmatically when the page is ready.
  • You already have a tested Pyppeteer and Chromium combination and can accept the project’s maintenance status.

In those cases, explicitly set fullPage: True, implement a content-specific readiness strategy, and pin the browser and Python dependencies used by your automation.

Frequently Asked Questions

Does fullPage load every image automatically?

No. It requests the full scrollable extent, but lazy-loaded assets still require scrolling or another site-specific readiness condition.

What is Pyppeteer’s default screenshot format?

PNG. JPEG is available with type: 'jpeg', and JPEG quality accepts values from 0 to 100.

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

Can I capture a full page without writing a file?

Yes. Omit path; the method returns screenshot data, with encoding controlling binary or base64 output.

Is Pyppeteer actively maintained?

The Pyppeteer repository warns that it is unmaintained and has been outside minor changes for a long time. Evaluate that risk before starting a new project.

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.