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.

For a full-page screenshot, scroll through the page in steps to trigger viewport-based lazy loading, then wait for the images needed in the capture to finish loading before taking the shot. A browser’s load event alone is not enough: lazy images may still be pending. The right wait conditions depend on the page, so treat scrolling and image checks as capture preparation—not a universal guarantee.

Why screenshots can miss lazy-loaded images

With native loading="lazy", the browser may defer fetching an image until it is within a browser-calculated distance of the viewport. That distance is not necessarily the point at which the image becomes visibly onscreen. A full-page screenshot can include parts of a document that were never brought near the viewport during ordinary loading.

The document load event does not certify that lazy images have finished loading. MDN explains that this event fires after eagerly loaded content has loaded; lazily loaded content may still be pending. An image’s HTMLImageElement.complete property can help determine whether its loading has finished, but production code should also check whether it loaded successfully.

These browser behaviors explain the preparation strategy below. They do not establish how every hosted screenshot service works internally.

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

Choose preparation based on the capture

Viewport-only screenshot

Focus readiness checks on images in the target viewport. Waiting for every image in the document may add unnecessary delay when offscreen content is not part of the shot.

Full-page screenshot

Activate lazy-loading regions throughout the scrollable document before capture, then wait for the images relevant to the shot. Playwright describes a full-page screenshot as capturing the full scrollable page, but requesting one does not itself prove that the page’s lazy-loading logic ran or that all image requests completed.

Prepare the page in a browser automation worker

The following Playwright example navigates to a page, scrolls down in viewport-sized increments to trigger viewport-based loading, scrolls back to the top, waits for image elements to finish, and takes a full-page screenshot. It is a starting point, not a site-independent guarantee: nested scrollers, scripts that load content dynamically, and slow or failed requests may need separate handling.

  1. Install Playwright in a Node.js project with npm install playwright, then install a browser with npx playwright install chromium.
  2. Save the script below as capture.mjs.
  3. Run it with node capture.mjs https://example.com, replacing the URL with the page you need to capture.
import { chromium } from 'playwright';

const url = process.argv[2];
if (!url) throw new Error('Usage: node capture.mjs https://example.com');

const browser = await chromium.launch({ headless: true });
try {
  const page = await browser.newPage({ viewport: { width: 1365, height: 900 } });
  await page.goto(url, { waitUntil: 'load', timeout: 60_000 });

  // Bring successive regions near the viewport so viewport-triggered
  // lazy-loading logic has a chance to run.
  await page.evaluate(async () => {
    const pause = (ms) => new Promise(resolve => setTimeout(resolve, ms));
    const step = Math.max(1, window.innerHeight);
    for (let y = 0; y < document.documentElement.scrollHeight; y += step) {
      window.scrollTo(0, y);
      await pause(150);
    }
    window.scrollTo(0, 0);
  });

  // Wait for image elements to settle. A completed image can still be broken,
  // so record failures separately rather than treating complete as success.
  const imageResults = await page.evaluate(async () => {
    const images = [...document.images];
    await Promise.all(images.map(img => {
      if (img.complete) return Promise.resolve();
      return new Promise(resolve => {
        img.addEventListener('load', resolve, { once: true });
        img.addEventListener('error', resolve, { once: true });
      });
    }));
    return images.map(img => ({
      src: img.currentSrc || img.src,
      complete: img.complete,
      naturalWidth: img.naturalWidth
    }));
  });

  const failed = imageResults.filter(img => !img.complete || img.naturalWidth === 0);
  if (failed.length) console.warn('Images not successfully loaded:', failed);

  await page.screenshot({ path: 'page.png', fullPage: true });
} finally {
  await browser.close();
}

The example waits for each image’s load or error event without imposing an image timeout. In a production capture queue, add a deadline and define whether failed images should cause a retry, a partial screenshot, or a failed job. A page can also keep adding images after the initial list is read; if that happens, wait for the site’s relevant content state and recheck the image set before capture.

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

Understand the three loading approaches

Approach Trigger and useful fit Trade-off
Native loading="lazy" Browser-managed deferral based on a calculated distance from the viewport; suitable for ordinary image markup. The browser controls the trigger distance, and the page load event does not certify lazy-image completion.
Custom Intersection Observer A script reacts when targets intersect a viewport or another root. A positive rootMargin can start work before an image becomes visible. Requires callback and fallback behavior. Targets still need to approach the observed root; the observer does not make every offscreen image load by itself.
Screenshot preparation scroll A capture worker moves through the page to activate viewport-triggered content, then waits for images; useful for full-page captures. Nested scrollers, network delays, page scripts, and dynamically added content can require tailored readiness logic. No fixed scroll increment or delay works for every site.

Keep layout stable while images load

Set explicit width and height values on image elements, including lazy-loaded images. An unloaded lazy image without dimensions may initially occupy no space, causing nearby content to move when the image appears. Stable dimensions make the page less likely to shift between the preparation scroll and the screenshot.

Playwright timing and capture considerations

Playwright provides page.waitForLoadState() and a full-page screenshot option. Its documentation notes that explicit load-state waits are often unnecessary for ordinary actions because Playwright auto-waits. Screenshot readiness is a separate concern: a successful navigation or load-state wait does not establish that lazy images throughout a long page have been triggered and loaded.

  • Wait for the state the page needs. Some pages render essential content after navigation; wait for a suitable selector or application-specific ready signal before scrolling.
  • Use capture-specific image checks. For a viewport image, inspect images in that viewport. For full-page capture, activate regions through the document and inspect the images intended to appear in the result.
  • Account for nested scroll containers. Scrolling window does not move an independently scrolling panel. If relevant images live in one, scroll that container too.
  • Set bounds for production. Long pages and stalled image requests can keep a worker busy. Use job-level and image-level deadlines, and decide how to handle incomplete captures.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Troubleshoot missing or broken images

  • Images are missing below the fold: the capture may have happened before lazy-loading triggers ran. Scroll through the document before checking image readiness.
  • The page loaded, but images did not: navigation’s load event covers eagerly loaded content, not necessarily lazy images. Wait for the target images separately.
  • An image reports complete but appears blank: completion alone is not success. Check naturalWidth or another success signal, and inspect failed requests.
  • Images in a panel remain absent: the panel may have its own scroll root. Scroll it rather than only the main document.
  • Images appear in the wrong place or content shifts: reserve space with explicit image dimensions and wait for the page’s dynamic layout to settle before capture.
  • A fixed delay still misses images: there is no documented universal delay or scroll step. Use page-specific readiness checks and bounded retries instead of assuming one timing value fits all sites.

Or skip the browser setup

ScreenshotNeo is a website screenshot API with a one-call option for a screenshot. It accepts cookie and consent banners like a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each of those steps can be turned off. Bot checks and CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers report the page verdict and billing status.

For an image output, use the API’s documentation for available parameters and formats. Example cURL request:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

ScreenshotNeo also has an MCP server with take_screenshot, get_page_info, and capture_pdf tools 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. Sign up for 1,000 free screenshots a month—no card required.

Frequently Asked Questions

Does scrolling guarantee every lazy image will load?

No. It gives viewport-triggered loading a chance to run. Page-specific scripts, nested scroll areas, request failures, or content added later can still require custom handling.

Should I wait for network idle before taking a full-page screenshot?

Network idle alone does not prove that lazy images outside the viewport were triggered or that all target images loaded. Combine an appropriate page-ready condition with scrolling and image-specific checks.

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.

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.