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

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

To make Puppeteer include images in a PDF, make the images load before calling page.pdf(). Navigate with an appropriate lifecycle condition, trigger lazy loading, wait for each required image to report complete with a positive naturalWidth, then generate the PDF. Puppeteer waits for fonts by default, but its documented PDF options do not provide an equivalent image-readiness switch. A selector wait only proves that an image element exists in the DOM; it does not prove that the image resource finished successfully.

The reliable sequence

A robust PDF capture has four separate stages:

  1. Open the page and wait for a navigation milestone such as networkidle2.
  2. Trigger any lazy-loaded content by scrolling it into view or invoking the page’s own loading code.
  3. Wait for the specific images you need, checking successful resource completion rather than DOM presence.
  4. Call page.pdf(), remembering that PDF output uses print CSS by default.

The official PDF guide demonstrates navigation with waitUntil: 'networkidle2' and notes that PDF generation waits for fonts by default (PDF generation guide). The PDFOptions reference documents waitForFonts: true, which waits for document.fonts.ready, but lists no image-wait option (PDFOptions).

A complete Puppeteer example

This Node.js script loads a page, starts lazy loading by scrolling, waits for ordinary images to finish successfully, reports failures, and writes a PDF. Replace the URL and selector rules for your site.

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

(async () => {
  const browser = await puppeteer.launch({
    headless: true,
    args: ['--no-sandbox', '--disable-setuid-sandbox']
  });

  try {
    const page = await browser.newPage();
    await page.setViewport({ width: 1440, height: 900, deviceScaleFactor: 1 });

    const failedRequests = [];
    page.on('requestfailed', request => {
      failedRequests.push({
        url: request.url(),
        error: request.failure()?.errorText || 'unknown error'
      });
    });

    await page.goto('https://example.com/article', {
      waitUntil: 'networkidle2',
      timeout: 60_000
    });

    // Trigger common viewport-based lazy loaders.
    await page.evaluate(async () => {
      const step = Math.max(window.innerHeight, 400);
      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);
    });

    // Give intersection-observer callbacks a chance to request images.
    await new Promise(resolve => setTimeout(resolve, 300));

    await page.waitForFunction(() => {
      const images = [...document.images].filter(image => {
        // Exclude intentional placeholders or decorative pixels if needed.
        return !image.matches('[data-ignore-pdf-image]');
      });
      return images.every(image => image.complete && image.naturalWidth > 0);
    }, { timeout: 30_000 });

    const incompleteImages = await page.evaluate(() => [...document.images]
      .filter(image => !image.matches('[data-ignore-pdf-image]'))
      .filter(image => !(image.complete && image.naturalWidth > 0))
      .map(image => ({ src: image.currentSrc || image.src, complete: image.complete })));

    if (incompleteImages.length || failedRequests.length) {
      console.error({ incompleteImages, failedRequests });
      throw new Error('One or more PDF images did not load');
    }

    await page.pdf({
      path: 'article.pdf',
      format: 'A4',
      printBackground: true,
      margin: { top: '16mm', right: '14mm', bottom: '16mm', left: '14mm' }
    });
  } finally {
    await browser.close();
  }
})();

waitForFunction() runs the predicate in the page context; its API is documented in the Page class reference. The particular complete/naturalWidth predicate above is practical implementation guidance, not an official Puppeteer recipe. Adapt it to your page’s placeholders, intentionally empty images, and dynamically inserted content.

#1 Best Overall
Amazon Basics Multipurpose Copy Printer Paper, 8.5 x 11 Inches, 20 lb, 92 Bright, White, 1 Ream (500 Sheets), Jam-Free
  • 1 ream (500 sheets) of 8.5 x 11 white copier and printer paper for home or office use
  • Multipurpose letter size copy paper works with laser/inkjet printers, copiers and fax machines
  • Smooth 20lb weight paper for consistent ink and toner distribution; dries quickly and resists paper jams
  • Bright white paper (92 GE; 104 Euro) offers great contrast for crisp printing and vivid color
  • Virgin copy paper providing professional quality results; acid-free to prevent yellowing

Why images disappear from PDFs

Lazy loading has not started

Many sites leave src empty or put the real URL in data-src until an image approaches the viewport. A page can be “loaded” while below-the-fold images have never been requested. Scroll through the document, call the site’s explicit load routine, or replace the lazy-loading mechanism in a controlled capture environment before waiting.

The wait checks the wrong thing

await page.waitForSelector('img') only confirms that an <img> node entered the DOM (waitForSelector documentation). It does not confirm that the URL is valid, that bytes arrived, or that the decoded image has dimensions. Check image.complete and image.naturalWidth > 0 for the images that matter.

Network idle is not image readiness

Puppeteer’s networkidle0 and networkidle2 are connection-count conditions sustained for at least 500 ms: zero connections or no more than two, respectively (lifecycle event definitions). They are useful navigation milestones, but they do not express “every intended image decoded successfully.” Persistent analytics, WebSockets, polling, or late application code can also make them unsuitable.

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

Print CSS hides or changes the image

Page.pdf() emulates print media. A stylesheet may set an image or its container to display:none, remove its dimensions, change a background, or move it across a page break. Inspect the page in print media and compare it with the screen rendering. If you need screen styles, call await page.emulateMediaType('screen') before page.pdf(); the API reference documents this behavior (Page.pdf()).

Choosing the right readiness check

Strategy What it proves Where it can fail
domcontentloaded or load A navigation milestone was reached. Late JavaScript, lazy images, and application requests may still be pending.
networkidle0 or networkidle2 The documented connection count stayed low for the idle period. Persistent requests can prevent it; quiet networking does not prove image success.
waitForSelector('img') A matching DOM element exists. The element may have no usable URL or may still be downloading.
Per-image waitForFunction() Selected images are complete and have a positive decoded width. Lazy loading must be triggered first; CSS backgrounds and intentional placeholders need separate handling.

Use a navigation condition to establish a starting point, then use a page-side image condition for the actual guarantee your PDF needs. Do not make an unbounded wait: a permanently broken URL would otherwise hold the job forever.

Rank #2
HP Printer Paper | 8.5 x 11 Paper | Copy &Print 20 lb | 1 Ream Case - 500 Sheets| 92 Bright | FSC Certified | 200060
  • HP Papers is sourced from renewable forest resources and has achieved production with 0% deforestation in North America. Each ream is wrapped in a polyurethane coated paper wrapper to protect the cut sheets from moisture damage
  • Sheet size – 8.5 x 11; Thickness – 20 pounds; Brightness – 92 bright white
  • HP Copy&Print20 20 pounds printer paper is Forest Stewardship Council (FSC) certified and contributes toward satisfying credit MR1 under LEED (Leadership in Energy and Environmental Design)
  • All HP Papers provide premium performance on HP equipment, as well as on all other printer and copier equipment; 100% satisfaction guaranteed; ColorLok technology provides more vivid colors, bolder blacks and faster drying
  • Superior quality, reliability, and dependability for high-volume printing at home, at school and in the office; HP Copy&Print20 print and copy paper prevents yellowing over time to ensure a long-lasting appearance for added archival quality

Adapting the image check

Limit the check to the document’s content

Pages often contain tracking pixels, icons, avatars, or placeholders that should not block a PDF. Scope the predicate to a content container:

await page.waitForFunction(() => {
  const root = document.querySelector('main');
  if (!root) return false;
  return [...root.querySelectorAll('img')]
    .filter(img => !img.matches('.avatar, [aria-hidden="true"]'))
    .every(img => img.complete && img.naturalWidth > 0);
}, { timeout: 30_000 });

Handle responsive images

Read currentSrc, not only the original src, when diagnosing failures. A srcset candidate can be selected for the capture viewport, and that candidate may have a different URL or access policy.

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.

Handle CSS background images

document.images does not include CSS backgrounds. If a hero or card image is a background, wait for the relevant elements and inspect their computed style, or preload known URLs yourself. For a finite list of URLs, a page-side preload can make the dependency explicit:

await page.evaluate(urls => Promise.all(urls.map(url => new Promise((resolve, reject) => {
  const image = new Image();
  image.onload = resolve;
  image.onerror = reject;
  image.src = url;
}))), ['https://example.com/hero.jpg']);

Do not use this as a substitute for triggering the site’s own lazy loader when the page chooses different responsive or authenticated URLs.

Wait for content inserted after the first render

If a framework adds images after an API response, wait for a meaningful content selector and then run the image predicate. If the page can continue adding images, take a stable snapshot of the target container or use a short settling delay followed by a second check.

Rank #3
Amazon Basics Multipurpose Copy Printer Paper, 20 lb, 8.5 x 11 Inches, 3 Reams (1,500 Sheets), 92 Bright White for Home Use
  • 3 ream case (1,500 sheets) of 8.5 x 11 white copier and printer paper for home or office use
  • Multipurpose letter size copy paper works with laser/inkjet printers, copiers and fax machines
  • Smooth 20lb weight paper for consistent ink and toner distribution; dries quickly and resists paper jams
  • Bright white paper (92 GE; 104 Euro) offers great contrast for crisp printing and vivid color
  • Virgin copy paper providing professional quality results; acid-free to prevent yellowing

PDF options that affect image appearance

  • printBackground: true: include CSS background colors and images that print styles allow.
  • format, width, and height: change wrapping and responsive breakpoints, so set the viewport and paper geometry deliberately.
  • preferCSSPageSize: honor the document’s CSS page size when the site defines one.
  • pageRanges: render selected pages only after confirming that the images on those pages are ready.
  • waitForFonts: leave the default enabled unless you have a reason to disable the documented font wait; it does not wait for images.

Check the current option names and defaults in the PDFOptions interface. Capture screenshots or PDFs with the same viewport, media type, and authentication state you use in production; otherwise a breakpoint or permission change can make an image appear to “randomly” vanish.

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

Diagnosing missing images

Log the actual image URLs

const imageState = await page.evaluate(() => [...document.images].map(image => ({
  src: image.src,
  currentSrc: image.currentSrc,
  complete: image.complete,
  naturalWidth: image.naturalWidth,
  naturalHeight: image.naturalHeight
})));
console.table(imageState);

An empty currentSrc, a zero natural width, or a URL that differs from the expected asset points to a page-side loading problem rather than a PDF option.

Capture failed requests

Listen for requestfailed events as shown in the complete script. Also inspect HTTP responses, redirects, authorization headers, cookies, and hotlink restrictions. A resource can fail because it requires a session, rejects the browser’s origin, or is blocked by a request interception rule.

Check print-only rules

Temporarily generate one PDF with emulateMediaType('screen'). If the image returns, the problem is in print CSS, not loading. Review display, visibility, dimensions, object-fit, and page-break rules around the image.

Use bounded retries

For transient origins, retry the navigation or the whole capture with a capped number of attempts. Do not silently produce a PDF after a timeout: return a diagnostic that identifies incomplete images and failed requests, or mark the document as incomplete.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Rank #4
Amazon Basics Multipurpose Copy Printer Paper, 20 lb, 8.5 x 11 Inches, 5 Reams (2,500 Sheets), 92 Bright White
  • 5 ream case (2,500 sheets) of 8.5 x 11 white copier and printer paper for home or office use
  • Multipurpose letter size copy paper works with laser/inkjet printers, copiers and fax machines
  • Smooth 20lb weight paper for consistent ink and toner distribution; dries quickly and resists paper jams
  • Bright white paper (92 GE; 104 Euro) offers great contrast for crisp printing and vivid color
  • Virgin copy paper providing professional quality results; acid-free to prevent yellowing

Performance and reliability practices

  • Wait only for the content region required by the PDF instead of every tracking pixel on the page.
  • Set explicit navigation and image-wait timeouts. A slow image should produce a useful error, not an indefinitely running worker.
  • Reuse a browser process when safe, but create a fresh page and clear session state for each document that needs isolation.
  • Keep the viewport, device scale, locale, timezone, cookies, and authentication consistent with the page whose images you expect.
  • Record the URL, selected currentSrc, failed-request error, and media type with the job so a missing image can be reproduced.
  • Be careful with request interception: blocking images, fonts, third-party CDNs, or required authorization calls defeats the readiness check.

The result you want is not merely a PDF file that was generated without throwing an exception; it is a file whose required image resources were requested, decoded, and left visible by print styles.

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 need a clean screenshot or PDF rather than a custom Puppeteer workflow, ScreenshotNeo provides a website screenshot API and an MCP server. Its capture options include full-page output with lazy images loaded, CSS-selector element capture, device and viewport controls, dark mode, custom CSS and JavaScript, waits for a selector, delay or network idle, cookies and headers, authentication, PDF paper and margin settings, and signed asynchronous jobs.

One GET request is enough:

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

See the ScreenshotNeo API documentation for the other parameters. Equivalent clients are useful when integrating a service without maintaining a browser process:

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)
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 removes cookie-consent banners, newsletter popups, and chat widgets before capture; bot checks, blank pages, failed loads, timeouts, and cache hits are not billed, and response headers identify the page verdict and billing status. Its MCP server exposes take_screenshot, get_page_info, and capture_pdf 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, and every feature is available on every plan. Create a free ScreenshotNeo account.

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

Frequently asked questions

Does setting waitForFonts solve missing images?

No. It waits for document.fonts.ready. Image resources require their own loading check.

Should I always use networkidle0?

No. It can hang on pages with persistent connections, and even a successful idle period does not prove that lazy or application-triggered images decoded.

Best Value
Sale
Amazon Basics Multipurpose Copy Printer Paper, 20 lb, 8.5 x 11 Inches, 8 Reams (4,000 Sheets), 92 Bright White, Great for Crisp Ink Printing
  • 8 ream case (4,000 sheets) of 8.5 x 11 white copier and printer paper for home or office use
  • Multipurpose letter size copy paper works with laser/inkjet printers, copiers and fax machines
  • Smooth 20lb weight paper for consistent ink and toner distribution; dries quickly and resists paper jams
  • Bright white paper (92 GE; 104 Euro) offers great contrast for crisp printing and vivid color
  • Virgin copy paper providing professional quality results; acid-free to prevent yellowing

Why does a background image remain absent?

Backgrounds are not represented by document.images. Inspect the computed style or preload the specific background URL, then verify that print CSS leaves the element visible.

Can a broken image make my job wait forever?

Yes, if the predicate waits for every image without a timeout. Use a bounded timeout and report the incomplete URL so the caller can retry or fix the source.

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

Why does the screen look correct but the PDF does not?

The PDF uses print media by default. A print rule may hide the image or alter its dimensions; compare a screen-media PDF and inspect the print stylesheet.

Frequently Asked Questions

Does setting waitForFonts solve missing images?

No. It waits for document.fonts.ready; images need a separate resource-readiness check.

Should I always use networkidle0?

No. Persistent connections can prevent it, and network idleness does not prove that lazy images decoded.

Why does a background image remain absent?

CSS backgrounds are not included in document.images; inspect computed styles or preload the required URL and verify print CSS.

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

Can a broken image make my job wait forever?

Yes. Set a timeout and report incomplete URLs instead of waiting without a bound.

Quick Recap

Bestseller No. 1
Amazon Basics Multipurpose Copy Printer Paper, 8.5 x 11 Inches, 20 lb, 92 Bright, White, 1 Ream (500 Sheets), Jam-Free
Amazon Basics Multipurpose Copy Printer Paper, 8.5 x 11 Inches, 20 lb, 92 Bright, White, 1 Ream (500 Sheets), Jam-Free
1 ream (500 sheets) of 8.5 x 11 white copier and printer paper for home or office use; Virgin copy paper providing professional quality results; acid-free to prevent yellowing
$6.97
Bestseller No. 2
HP Printer Paper | 8.5 x 11 Paper | Copy &Print 20 lb | 1 Ream Case - 500 Sheets| 92 Bright | FSC Certified | 200060
HP Printer Paper | 8.5 x 11 Paper | Copy &Print 20 lb | 1 Ream Case - 500 Sheets| 92 Bright | FSC Certified | 200060
Sheet size – 8.5 x 11; Thickness – 20 pounds; Brightness – 92 bright white
$6.97
Bestseller No. 3
Amazon Basics Multipurpose Copy Printer Paper, 20 lb, 8.5 x 11 Inches, 3 Reams (1,500 Sheets), 92 Bright White for Home Use
Amazon Basics Multipurpose Copy Printer Paper, 20 lb, 8.5 x 11 Inches, 3 Reams (1,500 Sheets), 92 Bright White for Home Use
Virgin copy paper providing professional quality results; acid-free to prevent yellowing
$23.99
Bestseller No. 4
Amazon Basics Multipurpose Copy Printer Paper, 20 lb, 8.5 x 11 Inches, 5 Reams (2,500 Sheets), 92 Bright White
Amazon Basics Multipurpose Copy Printer Paper, 20 lb, 8.5 x 11 Inches, 5 Reams (2,500 Sheets), 92 Bright White
Virgin copy paper providing professional quality results; acid-free to prevent yellowing
$34.85
SaleBestseller No. 5
Amazon Basics Multipurpose Copy Printer Paper, 20 lb, 8.5 x 11 Inches, 8 Reams (4,000 Sheets), 92 Bright White, Great for Crisp Ink Printing
Amazon Basics Multipurpose Copy Printer Paper, 20 lb, 8.5 x 11 Inches, 8 Reams (4,000 Sheets), 92 Bright White, Great for Crisp Ink Printing
Virgin copy paper providing professional quality results; acid-free to prevent yellowing
$49.99

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.