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

iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more

If images are missing from a Puppeteer screenshot, first check whether request interception is aborting or leaving their requests unresolved. Puppeteer stalls intercepted requests until a handler continues, responds to, or aborts each one. Then inspect the affected image URLs and wait for the specific assets your screenshot needs; navigation completion or network idleness alone does not prove that those images loaded successfully.

Diagnose the missing image before changing screenshot settings

An empty area in a screenshot does not, by itself, prove that an image was blocked. The image may not have been requested yet, its request may have failed, it may still be loading, or it may have loaded outside the captured region.

Record the affected image URL and browser request outcome, then inspect image elements in the page. Puppeteer’s page.evaluate() runs a function in the page context and returns its result. The following inventory reports each image’s URL, completion state and natural width:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
const images = await page.evaluate(() =>
  [...document.images].map(image => ({
    src: image.currentSrc || image.src,
    complete: image.complete,
    naturalWidth: image.naturalWidth,
  }))
);
console.log(images);

A completed image with a natural width of zero is a useful failure clue. An incomplete image may need more time, or the page may not have requested it yet—for example, because it is lazy-loaded. These browser properties are diagnostic signals, not a Puppeteer guarantee about why a particular image failed.

Check request interception first

Search your code for setRequestInterception(true), request event listeners, and calls to abort(), continue() or respond(). Audit every handler: a handler can block an image intentionally, accidentally match too broadly, or leave a request unresolved.

Puppeteer’s request interception guide explicitly demonstrates aborting image requests and explains that, once interception is enabled, every request stalls unless it is continued, responded to, aborted or completed from browser cache. If interception is not needed, disable it. If it is needed, use a narrow blocking condition and let the image requests required by the screenshot continue.

await page.setRequestInterception(true);
page.on('request', request => {
  if (request.isInterceptResolutionHandled()) return;

  // Apply a narrow block rule only to resources that should be blocked.
  // Continue other requests, including images needed in the screenshot.
  request.continue();
});

This example allows all requests. Replace that policy only with conditions that deliberately block specific resources. If multiple listeners can handle a request, follow Puppeteer’s guidance on handled-state checks and interception priorities rather than assuming the nearest listener is the only one involved. See Page.setRequestInterception() for the API.

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

Wait for the images the screenshot actually needs

Puppeteer’s screenshot guide shows navigation with waitUntil: 'networkidle2' before capture. That can be useful when a page needs to settle, but network idleness is not confirmation that a particular image succeeded. For a more targeted wait, use page.waitForFunction() with a finite timeout.

await page.waitForFunction(
  () => [...document.images].every(image => image.complete),
  { timeout: 10_000 },
);

This predicate checks only that the document’s current image elements have completed; a completed image can still have failed. For diagnosis, collect URLs and natural widths as well, and decide whether a broken image should fail the capture or be tolerated. If images are lazy-loaded, first bring the relevant content into view or wait for the application’s own readiness signal. If the wait times out, inspect which URLs remain incomplete or have zero natural width instead of extending the timeout blindly.

For broader network settling, Puppeteer’s Page.waitForNetworkIdle() and WaitForNetworkIdleOptions expose network-idle waiting and its idle-time and concurrency settings. A page with ongoing network activity may make that strategy unsuitable; prefer a page-specific condition when you know which images matter.

Use this complete diagnostic capture flow

The script below captures a page after its current image elements complete, then prints image diagnostics. It fails clearly if the image wait times out. It does not treat a zero natural width as a universal reason to reject the screenshot; add that policy if missing images must make your job fail.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
const puppeteer = require('puppeteer');

async function capture(url) {
  const browser = await puppeteer.launch();
  try {
    const page = await browser.newPage();
    // Do not enable interception unless the page needs it.
    await page.goto(url, { waitUntil: 'networkidle2' });

    try {
      await page.waitForFunction(
        () => [...document.images].every(image => image.complete),
        { timeout: 10_000 },
      );
    } catch (error) {
      const images = await page.evaluate(() =>
        [...document.images].map(image => ({
          src: image.currentSrc || image.src,
          complete: image.complete,
          naturalWidth: image.naturalWidth,
        }))
      );
      console.error('Image wait timed out; image state:', images);
      throw error;
    }

    const images = await page.evaluate(() =>
      [...document.images].map(image => ({
        src: image.currentSrc || image.src,
        complete: image.complete,
        naturalWidth: image.naturalWidth,
      }))
    );
    console.log('Image state:', images);
    await page.screenshot({ path: 'page.png', fullPage: true });
  } finally {
    await browser.close();
  }
}

capture('https://example.com').catch(error => {
  console.error(error);
  process.exitCode = 1;
});

Replace the example URL with the page you are diagnosing. If the screenshot should include only a particular image or region, adapt the readiness condition to those elements rather than waiting on every image in the document. Puppeteer’s Page.screenshot() documents the capture API.

Isolate cache and service-worker behavior when evidence points there

If the same image behaves differently across runs, or the page uses a service worker, compare a run with service-worker bypass enabled. If a stale cached response is plausible, compare with the cache disabled. These are diagnostic controls, not universal image fixes; change one variable at a time so you can tell what affected the result.

await page.setBypassServiceWorker(true); // Ignore service workers for requests
await page.setCacheEnabled(false);       // Disable browser cache

Puppeteer documents Page.setBypassServiceWorker() and Page.setCacheEnabled(); its cache is enabled by default. Restore normal settings after diagnosis unless your capture requirements call for the altered behavior.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Match browser restrictions to the failing request

net::ERR_BLOCKED_BY_CLIENT

This error is not a unique diagnosis for a blocked image. Puppeteer’s troubleshooting guide describes a Chrome for Testing HTTPS-first feature that can produce it for a particular remote HTTP navigation scenario. Check the failing URL and request type before applying that case’s feature-flag workaround; a documented navigation issue should not be generalized to image subresources.

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

Experimental URL allowlist or blocklist

If you connect to Chrome using Puppeteer’s experimental URL allowlist or blocklist options, inspect the configured patterns for the image host. Puppeteer says matching subresource requests such as images can fail. The options are Chrome-only, use URLPattern, and are explicitly not a complete network sandbox. See ConnectOptions.

Choose the next check from the evidence

Evidence Next check
Interception is enabled and the image URL matches an abort rule, or a request remains unresolved. Correct the rule or ensure the request is explicitly resolved; review every request listener.
The image request failed or has not completed, and its element reports incomplete or zero natural width. Use the recorded URL and request outcome to investigate the load; account for lazy loading and wait on the required asset.
The outcome changes when bypassing a service worker or disabling cache. Investigate that service-worker or cached-response path, changing one control at a time.
The error is net::ERR_BLOCKED_BY_CLIENT. Check whether the failing operation is the specific remote HTTP navigation case in Puppeteer’s troubleshooting guide before considering its workaround.
A configured URL pattern matches the image host. Review the experimental Chrome allowlist or blocklist configuration and its scope.

Or skip the browser setup

If your goal is simply to get a website screenshot rather than diagnose a Puppeteer capture, ScreenshotNeo provides a website screenshot API and MCP server. Its API can return PNG, JPEG, WebP or PDF output. For the available request options, see the ScreenshotNeo documentation.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

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

Sign up for ScreenshotNeo’s free plan to get 1,000 screenshots a month with no card.

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

Frequently Asked Questions

Does `networkidle2` guarantee that every image loaded?

No. It waits for network activity to settle; it does not confirm that a particular image succeeded. Inspect the image elements and their request outcomes.

Should I always disable Puppeteer’s cache or bypass service workers?

No. Use those settings as controlled diagnostics only when a cached response or service worker is implicated, then restore normal behavior unless your capture needs otherwise.

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.