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

In Puppeteer, wait for the page’s actual ready state, then wait for used fonts and the images you need to be fetched and decoded before calling page.screenshot(). A navigation event such as load or network idle is only a milestone: it does not guarantee that an app has finished rendering, lazy images have loaded, or the right font is in use.

A reliable Puppeteer capture sequence

Install Puppeteer and use a readiness condition that matches the page you are capturing. This example waits for navigation, an application marker, lazy content reached by scrolling, used fonts, and image decoding before taking a full-page screenshot.

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({ headless: true });
  try {
    const page = await browser.newPage();
    await page.goto('https://example.com', {
      waitUntil: 'networkidle2',
      timeout: 30000
    });

    // Replace this with a selector that means the page content is ready.
    await page.waitForSelector('#main-content', { timeout: 15000 });

    // For full-page captures, scroll through the page to trigger lazy loading.
    await page.evaluate(async () => {
      const step = Math.max(1, window.innerHeight);
      for (let y = 0; y < document.body.scrollHeight; y += step) {
        window.scrollTo(0, y);
        await new Promise(resolve => setTimeout(resolve, 100));
      }
      window.scrollTo(0, 0);
    });

    await page.evaluate(async () => {
      await document.fonts.ready;
      const images = [...document.images];

      await Promise.all(images.map(async image => {
        if (!image.currentSrc && !image.src) return;

        if (!image.complete) {
          await new Promise(resolve => {
            image.addEventListener('load', resolve, { once: true });
            image.addEventListener('error', resolve, { once: true });
          });
        }

        if (image.complete && image.naturalWidth > 0 && image.decode) {
          await image.decode().catch(() => {});
        }
      }));
    });

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

This is a starting pattern, not a universal drop-in guarantee. The in-page image wait resolves after a load or error event; successful images with data are decoded, while failed images do not block the capture. If a missing image should fail the job, collect failures and throw instead of swallowing decode errors. In production, bound every wait, including any custom page function, with a timeout and report which readiness condition failed.

Choose a navigation and application readiness signal

page.goto() completion is not the same thing as screenshot readiness. Puppeteer’s navigation wait options include load, domcontentloaded, and network-idle conditions; its screenshot guide demonstrates networkidle2. See Puppeteer’s screenshot guide and WaitForOptions.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
#1 Best Overall
Samsung 14" Galaxy Chromebook Go Laptop PC Computer, Intel Celeron N4500 Processor, 4GB RAM, 64GB Storage, ChromeOS, XE340XDA-KA2US, Student Laptop, Silver
  • SLIM. LIGHTWEIGHT. READY TO GO: The all-new slim design is perfect for busy lives on the go.
  • SKILLFULLY DESIGNED. MILITARY TOUGH: Built with premium craftsmanship to withstand the occasional drop or ding.
  • ALL-DAY, ALL-IN-ONE CHARGING: Power through your school day – and beyond – with a long-lasting 12-hour battery.¹
  • 3X FASTER THAN THE PREVIOUS GENERATION OF WIFI: Crush your schoolwork in record time with Wi-Fi that’s three times faster than the previous generation of Wi-Fi.
  • YOUR PHONE AND CHROMEBOOK WORK BETTER TOGETHER: Easily transfer files between devices, and control your phone right from your Chromebook.
Signal Use it when Limit
waitUntil: 'load' You need basic document navigation completion. It does not establish that app-specific rendering is finished or that lazy images are visible.
waitUntil: 'networkidle2' The page settles after its initial requests, and you want a useful navigation milestone. Persistent background requests can prevent idleness; a temporary quiet period can happen before later application work.
waitForSelector() A known element signals that required content is present. The selector must mean the content is ready, not merely that a shell or placeholder exists.
waitForFunction() Your app exposes a meaningful state, such as a render-complete flag. A false or poorly chosen condition can wait forever or capture too early; set a timeout.

Puppeteer documents waitForSelector() and waitForFunction() in its Page API. A useful site-specific condition might wait for the final text, a loaded-state attribute, or the removal of a loading indicator. Network idle is not proof that animations, polling, hydration, or later DOM updates have stopped.

Wait for the fonts the page actually uses

After the target content exists, run await document.fonts.ready in the page. The promise resolves when the document’s used fonts have completed loading and associated layout operations are done. It does not force every declared font to load: unused and optional faces may remain unloaded. See MDN: Document.fonts and MDN: FontFaceSet.ready.

If the screenshot still shows fallback typography, check whether the intended text and font are present before the font wait runs, whether the page actually references that font, and whether the font request fails. Waiting earlier than the app’s final render can miss fonts introduced by later content; wait for the relevant app state first, then wait for fonts.

Rank #2
HP Chromebook 14 Laptop, Intel Celeron N4120, 4 GB RAM, 64 GB eMMC, 14" HD Display, Chrome OS, Thin Design, 4K Graphics, Long Battery Life, Ash Gray Keyboard (14a-na0226nr, 2022, Mineral Silver)
  • FOR HOME, WORK, & SCHOOL – With an Intel processor, 14-inch display, custom-tuned stereo speakers, and long battery life, this Chromebook laptop lets you knock out any assignment or binge-watch your favorite shows..Voltage:5.0 volts
  • HD DISPLAY, PORTABLE DESIGN – See every bit of detail on this micro-edge, anti-glare, 14-inch HD (1366 x 768) display (1); easily take this thin and lightweight laptop PC from room to room, on trips, or in a backpack.
  • ALL-DAY PERFORMANCE – Reliably tackle all your assignments at once with the quad-core, Intel Celeron N4120—the perfect processor for performance, power consumption, and value (2).
  • 4K READY – Smoothly stream 4K content and play your favorite next-gen games with Intel UHD Graphics 600 (3) (4).
  • MEMORY AND STORAGE – Enjoy a boost to your system’s performance with 4 GB of RAM while saving more of your favorite memories with 64 GB of reliable flash-based eMMC storage (5).

Wait for images to load and decode

HTMLImageElement.complete alone is insufficient: it can be true for a broken image or an image with no source. Check for a usable source and, after loading, verify naturalWidth > 0. Then use image.decode() where available; its promise resolves when image data is ready for use and can reject if decoding fails. References: MDN: complete and MDN: decode().

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

Lazy-loaded and full-page images

Images marked for lazy loading may not be fetched until they approach the viewport. The page’s load event therefore does not prove that every lazy image in a full-page capture is ready. Scroll through the areas you intend to capture before checking the images; the browser’s <img> reference and loading property reference describe this behavior.

The example waits on every image in the document after scrolling. For a viewport screenshot, omit the scroll if all required images are eager-loaded. For a specific region or a long page with irrelevant images, scope the wait to that region so unrelated or off-page images do not delay capture.

Why a fixed delay is not a readiness test

A sleep only postpones capture; it cannot establish success. Chrome Headless’s CLI --timeout captures after a maximum delay even if loading is still underway. Use a delay only as a bounded allowance for a known transition, alongside state checks and a meaningful timeout or failure path. See Chrome Headless CLI reference.

Chrome Headless CLI versus Puppeteer

Chrome Headless supports command-line screenshots with --screenshot and viewport sizing with --window-size. The CLI timeout is a time limit, not a font-and-image readiness condition. Puppeteer is a better fit when the capture needs selector waits, page-side font and image checks, or application-specific logic; its Headless overview covers Headless Chrome context.

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.

Troubleshooting incomplete captures

  • Fallback font appears: wait for the actual content or font-using state first, then await document.fonts.ready. Check that the desired face is used and its request succeeds.
  • An image is blank: do not rely on complete alone. Check its source and naturalWidth, then await decode() for successful image data.
  • Full-page capture misses lower images: scroll the relevant page regions to trigger lazy loading before checking image readiness.
  • networkidle2 times out: background requests may keep the page active. Use a specific selector or app-state condition, with a bounded timeout.
  • The screenshot still changes after waits: animations, polling, hydration, or late DOM updates may continue. Define an app-specific capture-ready state and, if necessary, disable animation or stop updates for the capture.
  • A wait hangs: set explicit timeouts and ensure image error events are handled. Decide whether broken images should be reported as failures or allowed in the resulting screenshot.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup

For a one-call screenshot, ScreenshotNeo accepts a URL and returns an image or PDF. The request below follows its API documentation at ScreenshotNeo docs:

Rank #4
HP 14" HD Chromebook Laptop for Students, Intel Quad-Core N4120(> N4020), 4GB RAM, 64GB eMMC, WiFi, Webcam, HDMI, USB-A&C, 14 Hours Battery Life, Zoom, Chrome OS, CUE Accessories
  • Intel Celeron N4120: 4 Cores & Threads, 1.1GHz Base Clock, Up to 2.6GHz Boost Clock, 4MB Cache, Intel UHD Graphics 600. The perfect combination of performance, power consumption, and value helps your device handle multitasking smoothly and reliably with four processing cores to divide up the work.
  • 14" HD Display: 14.0-inch diagonal, HD (1366 x 768), micro-edge, anti-glare. See your digital world in a whole new way. Enjoy movies and photos with the great image quality and high-definition detail of 1 million pixels.
  • Memory & Storage: 4 GB LPDDR4x & 64 GB eMMC Storage. Adequate high-bandwidth RAM to smoothly run multiple applications and browser tabs all at once. An embedded multimedia card provides reliable flash-based storage.
  • Ports:2 x USB 3.0 Type-A,1 x USB 3.0 Type-C,1 x HDMI,1 x Headphone Jack
  • Chrome OS: Chromebook is a computer for the way the modern world works, with thousands of apps. Enjoy the seamless simplicity that comes with Google Chrome and Android apps, all integrated into one laptop. It’s fast, simple, and secure.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com -o shot.webp

ScreenshotNeo accepts cookie/consent banners like a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, with the response identifying the page verdict and billing status in headers. Its MCP server provides take_screenshot, get_page_info, and capture_pdf tools for AI agents and MCP clients. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 shots.

ScreenshotNeo is useful when you want those cleanup and billing behaviors without managing a browser capture flow. Sign up free for 1,000 screenshots a month, with no card.

Frequently Asked Questions

Does document.fonts.ready load every font in the stylesheet?

No. It waits for the fonts used by the document and related layout work; unused or optional faces may not load.

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

Should I wait for every image on the page?

Only if every image matters to the capture. For a viewport or a particular element, scope the wait to the visible or relevant content.

Is networkidle2 enough by itself?

No. It is a navigation milestone, not a guarantee that application rendering, fonts, or lazy images are finished.

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.