How to Screenshot a Web Page with a Load-on-Scroll Gallery
Load gallery items before capturing a full-page screenshot. Use Playwright to scroll and verify the content, then capture the rendered page.
A full-page screenshot captures the page’s scrollable content as the browser renders it; it does not guarantee that a gallery has loaded every item triggered by scrolling. For a reliable capture, scroll through the gallery, wait for each batch to appear, and then take the screenshot. With Playwright, use page.screenshot({ path: 'screenshot.png', fullPage: true }) after the gallery-loading step. The right wait condition depends on the site: use an item count, a load-more control, or another page-specific signal where possible.
1. Why full-page capture can miss gallery items
Lazy-loaded galleries often request or render content as it approaches the viewport. Playwright defines fullPage: true as capturing the full scrollable page, but its screenshot option does not promise to trigger every site’s scroll-based loading behavior. That means a screenshot can include the full page height while still showing empty image slots or missing rows. See the Playwright screenshot guide and Page screenshot API.
The key is to separate two steps: first make the gallery render the items you need, then capture the page. If the gallery is infinite or virtualized, set a clear stopping point; trying to capture an unbounded list as one image may never produce a stable complete result.
2. Manual workflow in a browser
- Open the page and wait for its initial content to settle.
- Scroll down through the gallery in increments. Pause until the next row or batch appears, then continue until you reach the desired end.
- If your capture tool begins at the current scroll position, return to the top.
- Capture the full page using the browser’s capture feature or a scrolling screenshot extension.
- Inspect the output for missing tiles, gaps, clipped content, or repeated sticky headers. If content is absent, retry with smaller scroll increments or longer pauses.
There is no universally reliable pause duration: image loading and gallery behavior vary by site and network. A scrolling extension may automate the scroll-and-capture cycle. For example, FullPage Capture describes waiting for images while scrolling and handling some inner scroll areas; those are publisher-described capabilities, not independent guarantees. Check the tool’s current listing, permissions, and output limits before relying on it. Chrome Web Store
3. Playwright: scroll, wait for the gallery, capture
Install Playwright for Node.js and its Chromium browser using the official installation instructions. Save the following as capture-gallery.mjs, replace the URL and gallery selectors, then run it with Node.js. The example scrolls in increments until the document height stops growing for several checks. That is a practical fallback, not proof that every gallery is complete: prefer a known item count or an explicit site signal when available.
import { chromium } from 'playwright';
const url = 'https://example.com/gallery';
const output = 'gallery.png';
const maxPasses = 80;
const stableChecksNeeded = 4;
const browser = await chromium.launch({ headless: true });
const page = await browser.newPage({ viewport: { width: 1440, height: 1000 } });
try {
await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 60000 });
// Replace this selector with a gallery-specific signal if possible.
// For example, wait for the gallery container to exist.
await page.locator('[data-gallery]').waitFor({ state: 'visible', timeout: 30000 });
let previousHeight = 0;
let stableChecks = 0;
for (let pass = 0; pass < maxPasses && stableChecks < stableChecksNeeded; pass++) {
const height = await page.evaluate(() => document.documentElement.scrollHeight);
if (height === previousHeight) stableChecks++;
else stableChecks = 0;
previousHeight = height;
await page.evaluate(() => window.scrollBy(0, Math.max(500, window.innerHeight * 0.8)));
await page.waitForTimeout(500); // Tune to the page; use a DOM/network signal when available.
}
// Optional: wait for gallery images to finish loading in the DOM.
await page.waitForFunction(() => {
const images = [...document.querySelectorAll('[data-gallery] img')];
return images.length > 0 && images.every(img => img.complete && img.naturalWidth > 0);
}, { timeout: 30000 }).catch(() => {
console.warn('Some gallery images did not report as loaded before the timeout. Inspect the output.');
});
await page.evaluate(() => window.scrollTo(0, 0));
await page.screenshot({ path: output, fullPage: true });
console.log(`Saved ${output}`);
} finally {
await browser.close();
}
Run it with node capture-gallery.mjs. Replace [data-gallery] with a selector present on the target page. If the page exposes a known item count, wait until that count is reached instead of relying on document height. Some virtualized galleries remove off-screen items from the DOM; in that case, capture sections as you scroll or use the site’s export/API if one exists. A single full-page screenshot cannot include items that are no longer rendered.
Use an item count when the site exposes one
If the page has a stable selector for gallery cards and you know how many items should appear, make that count the completion condition. For example, after replacing the selector and expected count, use:
const expectedItems = 120;
await page.waitForFunction(({ selector, count }) => {
return document.querySelectorAll(selector).length >= count;
}, { selector: '[data-gallery-item]', count: expectedItems }, { timeout: 60000 });
Check the argument signature against the Playwright version installed in your project. If the gallery has a “Load more” button, click it until it disappears or becomes disabled, waiting for the item count to increase after each click. Avoid assuming that network idle means the gallery is complete: pages may keep background requests open, and some galleries only request the next batch after scrolling.
4. Choosing a capture method
| Method | Useful when | Check before relying on it |
|---|---|---|
| Playwright full-page screenshot | You need repeatable, scripted capture. | Scroll-triggered content may need an explicit loading pass first. Full-page mode captures the scrollable page, not a universal lazy-loading workflow. Playwright docs |
| Browser developer tools | You need a one-off capture without installing an extension. | Behavior for scroll-loaded images and nested scrollers depends on the browser and page. Verify the result. |
| Scrolling screenshot extension | You want a point-and-click workflow that scrolls the page. | Handling of sticky elements, inner scroll areas, long pages, and export formats varies. Treat vendor feature descriptions as claims and inspect the output. |
Compare methods on four practical points: whether they trigger the gallery, how they treat sticky elements, whether they handle nested scroll containers, and whether they export the image or PDF format you need.
5. Common problems and fixes
| Symptom | Likely cause | What to try |
|---|---|---|
| Blank or missing gallery images | The relevant rows were not scrolled into view, or requests had not finished. | Scroll through the gallery and wait for an item-specific signal. Check that image elements report successful loads; inspect the output. |
| Screenshot ends before the last items | The gallery loads in batches, or the script stopped when page height paused briefly. | Increase the maximum scroll passes, use a known item count, and wait for the next batch after each scroll. Confirm the intended end of the gallery. |
| Repeated or obscuring sticky header | The capture method stitches viewport frames or the page’s fixed elements overlap content. | Try a browser-native full-page capture or adjust the page for capture if you control it. Inspect the saved image; extension behavior varies. |
| Gallery is inside a panel that does not move | The page body is not the element that scrolls; a nested container owns scrolling. | Find the scrollable gallery container and scroll that element in the script, or use a tool that supports the specific inner scroller. Verify items remain rendered. |
| Image wait times out | Some images failed, the selector is wrong, or the page uses backgrounds/canvas instead of image elements. | Check the selector and inspect failed requests. Use the page’s own loaded-state signal where possible; do not treat a timeout as proof the capture is complete. |
| Very tall output is clipped or unwieldy | Browser, image encoder, or extension limits may apply to large dimensions. | Capture defined sections and save them separately, or use PDF/another export format if appropriate. Check the tool’s documented limits. |
| Items appear once, then disappear | The gallery may virtualize rows and recycle DOM elements outside the viewport. | Capture each viewport or section as you go, or use an available site export/API. A final full-page capture cannot show items that are no longer in the rendered document. |
| Screenshot contains private information | The page includes account details, messages, or other sensitive content. | Review and redact the image before sharing. Avoid capturing real user data unless needed and authorized. |
6. Performance, reliability, and output size
- Prefer a real completion condition. An item count, load-more state, or gallery-specific signal is more meaningful than an arbitrary sleep. A short delay can still be useful between scroll steps when no signal is available, but tune it for the target page.
- Bound the work. Set a maximum number of scroll passes and define how many gallery items you need. This prevents scripts from running indefinitely on infinite galleries.
- Expect large output. Full-page screenshots can have very tall dimensions and consume memory. For huge galleries, capture sections and keep their order or use a format better suited to long documents.
- Make reruns diagnosable. Log the final item count, page height, and any image failures. Save to a predictable path and inspect representative runs when the page changes.
- Handle failures explicitly. Set navigation and wait timeouts, close the browser in a
finallyblock, and distinguish a partial capture from a confirmed complete one in your pipeline.
7. Or skip the browser setup
ScreenshotNeo is a website screenshot API. Its full-page capture loads lazy images, which can simplify a scroll-loaded gallery capture. See the API documentation for request options.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
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}`);
Replace the example URL with the gallery URL. ScreenshotNeo removes cookie banners, newsletter popups, and chat widgets before the shot. Bot checks, blank pages, and failed loads are never billed. Its MCP server lets AI agents take screenshots, and 1,000 screenshots a month are free with no card; paid plans start at $5 for 3,000. Every feature is on every plan. Create a free account and get 1,000 screenshots a month with no card.
8. FAQ
Does fullPage: true scroll the page for me?
It captures the full scrollable page. Do a deliberate loading pass first when the site only renders gallery items after scrolling.
How long should I wait between scrolls?
There is no universal duration. Wait for a gallery-specific DOM or item-count signal when possible; otherwise use a tuned delay and inspect the result.
Can one screenshot capture an infinite gallery?
Not as a reliably complete, bounded result. Define a range, capture sections, or use the site’s export/API if available.
Why did my nested gallery stay empty?
The scrollable area may be an inner panel instead of the page. Scroll that container and confirm its items remain in the rendered document before taking the final capture.


