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
To capture content that appears only as you scroll, first scroll the page in bounded passes, wait for the content and images you need to finish loading, then call page.screenshot({ fullPage: true }). The fullPage option captures the page’s full height; it does not trigger infinite scrolling or guarantee lazy images are ready. The example below combines those steps and sets explicit stopping limits.
Why fullPage: true is not enough
Puppeteer’s Page.screenshot() can capture the full page when you set fullPage: true; the option defaults to false. But a screenshot captures what the page has rendered—it does not make an infinite-scroll site append more content. You must trigger the site’s scrolling behavior, decide when to stop, and verify that the content you want is ready. See Puppeteer’s screenshot guide and ScreenshotOptions reference (version 25.12.0).
Use a bounded scroll-and-check workflow
This Node.js example scrolls down in viewport-sized increments, tracks document height, and stops after the height stays unchanged for several passes or a maximum pass count is reached. It then waits for network activity to settle, checks that images have either loaded or failed, and saves a full-page PNG.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Install Puppeteer in a Node.js project with npm install puppeteer. Replace the example URL and, for a site with a specific completion signal, replace the stability check with that signal.
#1 Best Overall
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch({ headless: true });
try {
const page = await browser.newPage();
await page.setViewport({ width: 1365, height: 900 });
await page.goto('https://example.com', {
waitUntil: 'domcontentloaded',
timeout: 60000,
});
const maxPasses = 30;
const stablePassesNeeded = 3;
let stablePasses = 0;
let previousHeight = 0;
for (let pass = 0; pass < maxPasses && stablePasses < stablePassesNeeded; pass++) {
const height = await page.evaluate(() => document.documentElement.scrollHeight);
await page.evaluate(() => {
window.scrollBy(0, window.innerHeight);
});
await new Promise(resolve => setTimeout(resolve, 700));
const newHeight = await page.evaluate(() => document.documentElement.scrollHeight);
if (newHeight === previousHeight || newHeight === height) {
stablePasses++;
} else {
stablePasses = 0;
}
previousHeight = newHeight;
}
// Give content triggered by the last scroll a chance to settle.
await page.waitForNetworkIdle({ idleTime: 1000, timeout: 15000 }).catch(() => {});
// Wait for images currently in the document to finish loading or fail.
await page.evaluate(async () => {
const images = Array.from(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 });
});
}));
});
await page.screenshot({ path: 'page.png', fullPage: true });
} finally {
await browser.close();
}
})();
Adapt the stop condition to the page
Stable document height is a practical fallback, not proof that the site has no more content. Some feeds load items without changing height until later, use an inner scrolling container, or keep refreshing. If the page exposes a “load complete” state, a known final item, or a stable item count, check that instead. For a feed with no natural endpoint, stop at a chosen item boundary, elapsed time, or pass limit; “infinite” content has no universal final state.
Scroll the element that actually scrolls
The sample scrolls the window. If a feed lives inside a fixed-height container, identify that container and scroll it instead; otherwise the site may never receive the scroll event that triggers loading. Puppeteer’s page interactions guide describes locator-based interactions and scrolling mechanisms. The appropriate selector and completion check depend on the site.
Verify lazy images before capturing
Scrolling gives viewport-triggered lazy images an opportunity to load, but there is no universal Puppeteer switch that guarantees every site’s lazy images have loaded. The sample waits for each image currently in the document to reach a completed state; a broken image also counts as complete, so this check does not promise that every image rendered successfully.
Some sites only create image elements as new content arrives, while others defer image requests until an element is near the viewport. If image completeness matters, combine scrolling with checks for the specific images or site state you care about. Puppeteer’s Page.evaluate() runs code in the page context and waits for a returned promise, which makes such page-specific checks possible.
Rank #3
Choose waits and screenshot options deliberately
Navigation and network idle
The example uses waitUntil: 'domcontentloaded' so it can begin the scroll workflow without treating initial network quiet as proof that the feed is complete. Puppeteer’s screenshot guide also demonstrates navigation with waitUntil: 'networkidle2'. Either navigation choice is only a starting point: scrolling may trigger more requests later.
page.waitForNetworkIdle() resolves when network activity is idle and waits at least the configured idle time. The documented default idle time is 500 ms in Puppeteer’s WaitForNetworkIdleOptions reference; the method is documented at Page.waitForNetworkIdle(). A quiet network does not prove that another scroll cannot append content or that all images are correct, so pair it with a page-specific completion and image check.
Full-page capture and output
Use fullPage: true to capture the full page height. Puppeteer’s screenshot format defaults to PNG; the API also documents other screenshot options, including clipping and viewport capture. Set viewport dimensions before navigation when the site’s responsive layout or loading behavior depends on them. Do not assume every page can be captured as one image: outcome depends on the site, chosen stopping rule, browser behavior, and total page size.
Troubleshoot missing content and incomplete images
- The screenshot shows only the initial viewport: Confirm
fullPage: trueis set, and check whether the site uses an inner scroll container rather than window scrolling. - Later feed items are missing: Increase the bounded pass count or settling delay, or replace height stability with the site’s item count or completion signal. Avoid removing limits on a feed that can grow indefinitely.
- Images are blank: Ensure scrolling reaches the image region and wait for the relevant image elements or site state. A network-idle wait alone does not establish image readiness.
- The script hangs or exceeds its timeout: Keep navigation and network-idle timeouts bounded. Pages with ongoing requests may never become idle within your chosen timeout; handle that outcome and rely on a separate completion rule.
- Some images remain broken: The sample treats both
loadanderroras finished to avoid waiting forever. If successful image rendering is required, inspect the target images’naturalWidthor the site’s own error state and decide whether to retry or report failure.
Or skip the browser setup
If you need a screenshot endpoint rather than a custom Puppeteer workflow, ScreenshotNeo is a website screenshot API and MCP server. Its capture flow accepts cookie and consent banners like a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets; those steps can be turned off. Bot checks and CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and responses include X-Page-Verdict and X-Billed headers. AI agents can use its MCP server tools, including take_screenshot, get_page_info, and capture_pdf.
One GET request returns an image or PDF. For a WebP capture of the target URL:
Best Value
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com -o shot.webp
See the ScreenshotNeo API documentation for request options. The endpoint can capture full pages, but infinite-scroll completion remains dependent on the page’s loading behavior and the capture options you choose; use Puppeteer when you need a custom scroll loop or site-specific stopping rule.
ScreenshotNeo includes 1,000 screenshots per month free with no card; paid plans start at $5 for 3,000. Sign up for the free plan.
Recommended Free Tools
Frequently Asked Questions
Does Puppeteer have a built-in option to load every item on an infinite-scroll page?
No. You need to trigger scrolling and define a page-specific stopping condition.
Does ScreenshotNeo automatically guarantee that an infinite-scroll feed is complete?
No. A screenshot service cannot infer a universal endpoint for an unbounded feed; use a custom browser workflow when completion depends on site-specific scrolling logic.
Quick Recap
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.

