ScreenshotNeo

BlogHow-to

How to Capture a Full-Page Screenshot of an Infinite-Scroll Website

A full-page capture can miss content that loads only as you scroll. Learn how to trigger lazy loading, capture the page with Playwright or Firefox, and check the result.

By the ScreenshotNeo team4 October 20268 min read

To capture an infinite-scroll website completely, first scroll through it in increments until the content you need has loaded, then take a full-page screenshot. A full-page capture records the page’s current scrollable content; by itself, it may not trigger items that load only when they approach the viewport. Check the saved image from top to bottom, especially its final section. Playwright’s screenshot guide describes a full-page screenshot as capturing the full scrollable page, but that does not mean an unbounded feed has been exhausted.

1. Understand what “full page” captures

Infinite-scroll pages often fetch more content as you scroll. Images and frames can also be deferred until they are near the viewport. These behaviors are separate from taking a screenshot: the capture can include content already in the document without causing the page’s live viewport to visit every section and trigger more loading.

There may be no finite bottom to capture. Set a practical stopping point: the final item you need, a page-specific end marker, or the point at which the site indicates there is no more content. There is no universal stopping rule for infinite feeds.

2. Capture it manually in Firefox

  1. Open the page and wait for its initial content to settle.
  2. Scroll down in manageable increments. Pause after each movement so newly added items and images can load.
  3. Continue until the last item you need appears or the site indicates the feed has ended.
  4. Open Firefox’s screenshot tool by right-clicking an empty area and choosing Take Screenshot, or use Ctrl+Shift+S on Windows or Linux, or Command+Shift+S on macOS.
  5. Choose Save full page and save the image.
  6. Inspect the image at the top, middle, and bottom. If the final section is absent or images are blank, scroll farther, wait, and capture again.

Menu wording and shortcut availability can vary by platform or Firefox version. If the shortcut does not work, use the page context menu.

3. Automate the capture with Playwright

Playwright’s full-page option captures the full scrollable page. For an infinite feed, drive the page through the relevant scroll range first. The example below scrolls the document in viewport-sized steps, waits briefly after each step, and stops when it reaches the current document bottom or its configurable step limit. The limit prevents an endless loop on feeds that keep loading. Adjust the pause and step limit for the site and the amount of content you need.

JavaScript (Node.js)

import { chromium } from 'playwright';

const targetUrl = 'https://example.com/infinite-feed';
const maxSteps = 30;
const pauseMs = 800;

const browser = await chromium.launch();
const page = await browser.newPage({ viewport: { width: 1365, height: 900 } });

try {
  await page.goto(targetUrl, { waitUntil: 'domcontentloaded', timeout: 60_000 });
  await page.locator('body').waitFor();

  let previousHeight = 0;
  let stableBottomSteps = 0;

  for (let step = 0; step < maxSteps; step++) {
    const state = await page.evaluate(() => ({
      height: document.documentElement.scrollHeight,
      viewport: window.innerHeight,
      y: window.scrollY
    }));

    await page.evaluate(() => window.scrollBy(0, Math.max(1, window.innerHeight * 0.8)));
    await page.waitForTimeout(pauseMs);

    const next = await page.evaluate(() => ({
      height: document.documentElement.scrollHeight,
      y: window.scrollY,
      viewport: window.innerHeight
    }));

    const atBottom = next.y + next.viewport >= next.height;
    if (atBottom && next.height === previousHeight) stableBottomSteps++;
    else stableBottomSteps = 0;
    previousHeight = next.height;

    // Two stable checks at the current bottom are a practical stop condition,
    // not proof that the site has no more items.
    if (stableBottomSteps >= 2) break;
  }

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

Install Playwright and its browser in your project with npm install playwright and npx playwright install chromium. Save the script as an ES module (for example, capture.mjs) and run node capture.mjs. Replace the example URL with a page you are authorized to access.

The loop uses document scrolling and a pause, so it is a practical starting point rather than a universal feed detector. Some sites load only after a particular item appears, use a nested scrolling panel, or need longer for network activity. If you know the final item or an end marker, wait for that site-specific condition instead of relying only on document height.

Python

from playwright.sync_api import sync_playwright

TARGET_URL = "https://example.com/infinite-feed"
MAX_STEPS = 30
PAUSE_MS = 800

with sync_playwright() as p:
    browser = p.chromium.launch()
    page = browser.new_page(viewport={"width": 1365, "height": 900})
    try:
        page.goto(TARGET_URL, wait_until="domcontentloaded", timeout=60_000)
        page.locator("body").wait_for()

        previous_height = 0
        stable_bottom_steps = 0

        for _ in range(MAX_STEPS):
            page.evaluate("window.scrollBy(0, Math.max(1, window.innerHeight * 0.8))")
            page.wait_for_timeout(PAUSE_MS)
            state = page.evaluate("""() => ({
                height: document.documentElement.scrollHeight,
                y: window.scrollY,
                viewport: window.innerHeight
            })""")

            at_bottom = state["y"] + state["viewport"] >= state["height"]
            if at_bottom and state["height"] == previous_height:
                stable_bottom_steps += 1
            else:
                stable_bottom_steps = 0
            previous_height = state["height"]

            # A practical stopping condition, not proof the feed is exhausted.
            if stable_bottom_steps >= 2:
                break

        page.screenshot(path="page.png", full_page=True)
    finally:
        browser.close()

Install the package and browser with pip install playwright and playwright install chromium. Save as capture.py and run python capture.py. Replace the URL and tune the pause and step limit for the page.

cURL and plain HTTP clients

cURL can fetch a page’s HTML, but it does not run the browser’s JavaScript or scroll the page, so it cannot by itself trigger a JavaScript-driven infinite feed. For that behavior, use a browser automation tool such as Playwright. A browser-based screenshot API can simplify the capture request, but verify whether it can trigger the specific site’s scroll-dependent loading before relying on it for an entire feed.

4. Handle nested scroll panels and lazy images

If the feed scrolls inside a panel, scrolling the outer document may not trigger it. Scroll the panel itself. For a known panel selector, you can replace the document scroll call in the Playwright examples with a targeted scroll:

await page.locator('.feed-panel').evaluate(el => {
  el.scrollBy(0, Math.max(1, el.clientHeight * 0.8));
});

Replace .feed-panel with the page’s actual selector. Continue waiting and checking for new items. If images are deferred, scroll them near the viewport and allow them to finish loading before the final capture. Avoid assuming that a larger delay alone will load items whose loading is triggered by scrolling.

5. Check the output and choose a useful capture size

  • Top: confirm the page began at the expected position and the first relevant content is present.
  • Middle: look for gaps, repeated sections, or missing image content.
  • Bottom: confirm the last item you intended to capture is present and not clipped.
  • Readability: a very tall image may be difficult to inspect or share. Capture a needed range or use multiple screenshots with overlap when readability matters.

Full-page screenshots can be large, and a long feed may continue growing while you capture it. Bound the work to the content you need. If a single image is unwieldy, several overlapping captures can preserve continuity while remaining easier to view.

6. Troubleshooting

Symptom Likely cause What to do
Bottom section is missing The feed had not loaded that section before capture. Scroll farther, wait for new items or a loading indicator to settle, then capture again. Prefer a page-specific end condition when available.
Images or frames are blank Offscreen resources may be deferred until they approach the viewport, or have not finished loading. Scroll them into view, wait for loading to complete, and inspect the output again.
Only part of the feed appears The feed has no fixed finite boundary until scrolling triggers more content; a step limit may also have been reached. Increase the limit if appropriate, or stop at the final item you actually need. Check for an end marker rather than assuming the feed is exhausted.
Scrolling does not load more items The content may be inside a nested scroll container, or the site may require a longer pause or a particular interaction. Scroll the feed panel itself. Inspect the page behavior and wait for its loading state or known item selector.
Playwright navigation times out A page may keep connections open or continue background activity, making a strict load condition unsuitable. The examples use domcontentloaded to avoid waiting for every resource. If navigation still times out, check the URL and network access, then adjust the timeout for the site.
Screenshot is too tall to read The requested feed range produces one extremely long image. Capture only the required extent or make multiple overlapping screenshots.

7. Reliability, performance, and privacy

There is no universal delay, step count, or stopping condition that works for every infinite-scroll implementation. Use a site-specific final item, end marker, or loading indicator where possible. When that is unavailable, a stable page height at the bottom is only a practical heuristic: a delayed response could still add content later.

Scrolling and waiting adds time as the feed grows; full-page capture also has to process the resulting page height. Keep the viewport and requested extent to what the task requires. For repeatable automation, record the URL, viewport, stopping condition, and capture date so you can interpret differences between runs.

Capture only pages you are authorized to access and store. Screenshots can contain account details or other personal information, so inspect the image before sharing it.

8. Or skip the browser setup

ScreenshotNeo is a website screenshot API and MCP server. Its one-request API returns a screenshot or PDF; see the API documentation. For example:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com/infinite-feed -o shot.webp
import requests

r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={"access_key": "YOUR_API_KEY", "url": "https://example.com/infinite-feed"},
    timeout=90,
)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({
  access_key: 'YOUR_API_KEY',
  url: 'https://example.com/infinite-feed'
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await Bun.write('shot.webp', new Uint8Array(await res.arrayBuffer()));

These calls request a screenshot of the URL; for a feed that loads only as it scrolls, confirm the capture reaches the content you need and inspect the result. ScreenshotNeo removes cookie banners, 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. The Free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. Sign up for free and get 1,000 screenshots a month with no card.

Frequently asked questions

Does “full page” mean every item in an infinite feed?

No. It means the browser captures the current scrollable page. Scroll-triggered content may not exist in the page yet.

How do I know when to stop scrolling?

Stop when the final item you need appears or the site provides an end condition. A stable height is a useful fallback, but it cannot prove a delayed feed has ended.

Can I use this workflow on a page with a separate scrolling panel?

Yes. Scroll the panel that contains the feed, since its loading behavior may be tied to that panel’s viewport.

Should I make one giant screenshot?

Only if the resulting image remains useful. For very long feeds, capture the necessary extent or use overlapping images that are easier to inspect.