ScreenshotNeo

BlogHow-to

Best Scroll Settings for Capturing Long Lazy-Loaded Pages with a Screenshot API

Capture long pages without missing lazy-loaded content. Learn which scroll and full-page settings work in Browserless, Playwright, and Puppeteer.

By the ScreenshotNeo team4 October 20268 min read

For Browserless REST, set scrollPage: true at the top level of the JSON request to scroll the page before capture and trigger lazy loading. Pair it with options.fullPage: true to include the full scrollable page in the screenshot. For Playwright and Puppeteer, fullPage: true controls capture extent; it does not by itself guarantee that every viewport-triggered item has loaded. These are provider-specific settings, so check the API you use rather than copying option names across services.

Why long-page screenshots miss content

Many pages load images or other content only when those elements approach the viewport. A screenshot taken immediately after navigation may capture the top correctly while lower images remain unloaded. Full-page capture and lazy-load preparation solve different problems:

  • Full-page capture determines how much of the document appears in the image.
  • Scroll preparation brings lower content into view so viewport-triggered loading can run.
  • Image waiting, when offered, waits for images under that API’s rules; it is a separate control from scrolling.

None of these settings guarantees content that requires a click, login, consent, or some other interaction. Inspect the resulting image against the target page.

Browserless REST: scroll, then capture the full page

Browserless documents scrollPage as a top-level request option that scrolls before capture to trigger lazy loading. Its screenshot options include fullPage. Use both when the goal is a long full-page image with viewport-triggered content loaded.

curl -X POST "https://production-sfo.browserless.io/screenshot?token=YOUR_BROWSERLESS_TOKEN" \
  -H "Content-Type: application/json" \
  --data '{
    "url": "https://example.com/long-page",
    "scrollPage": true,
    "options": {
      "fullPage": true,
      "type": "png"
    }
  }' \
  --output page.png

Replace the example URL and token with your target and Browserless credentials. The screenshot API returns image bytes, so save the response body to a file. The exact supported output options and endpoint details are in the Browserless Screenshot API documentation.

Python request

import requests

endpoint = "https://production-sfo.browserless.io/screenshot"
params = {"token": "YOUR_BROWSERLESS_TOKEN"}
payload = {
    "url": "https://example.com/long-page",
    "scrollPage": True,
    "options": {
        "fullPage": True,
        "type": "png",
    },
}

response = requests.post(endpoint, params=params, json=payload, timeout=90)
response.raise_for_status()
with open("page.png", "wb") as image_file:
    image_file.write(response.content)

Node.js request

const endpoint = new URL("https://production-sfo.browserless.io/screenshot");
endpoint.searchParams.set("token", "YOUR_BROWSERLESS_TOKEN");

const response = await fetch(endpoint, {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    url: "https://example.com/long-page",
    scrollPage: true,
    options: { fullPage: true, type: "png" },
  }),
});

if (!response.ok) {
  throw new Error(`Screenshot request failed: ${response.status} ${await response.text()}`);
}

const image = Buffer.from(await response.arrayBuffer());
await import("node:fs/promises").then(({ writeFile }) => writeFile("page.png", image));

Playwright: full-page capture and lazy-load preparation

In Playwright, fullPage: true captures the full scrollable page. The option is false by default. The documented screenshot setting describes capture extent; do not treat it as a universal instruction to scroll through the page first. If the target loads content only as it enters the viewport, use a deliberate page-specific preparation step and verify the output.

import { chromium } from "playwright";

const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto("https://example.com/long-page", { waitUntil: "networkidle" });

// Page-specific preparation: scroll through the document to trigger viewport loading.
await page.evaluate(async () => {
  const step = Math.max(1, window.innerHeight);
  for (let y = 0; y < document.documentElement.scrollHeight; y += step) {
    window.scrollTo(0, y);
    await new Promise((resolve) => setTimeout(resolve, 250));
  }
  window.scrollTo(0, 0);
});

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

The scroll distance and pause above are illustrative implementation choices, not universal values. Dynamic pages can extend their height while scrolling, and some sites load on different events. Adapt the loop to the page and check whether the bottom content and images appear. Playwright documents the fullPage behavior in its screenshot guide and Page API.

Puppeteer: full-page capture and lazy-load preparation

Puppeteer also supports fullPage: true; its screenshot guide demonstrates full-page capture. As with Playwright, the option controls the screenshot extent. It should not be assumed to trigger every lazy-loading mechanism by itself.

import puppeteer from "puppeteer";

const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto("https://example.com/long-page", { waitUntil: "networkidle2" });

// Page-specific preparation; tune and verify for the target page.
await page.evaluate(async () => {
  const step = Math.max(1, window.innerHeight);
  for (let y = 0; y < document.documentElement.scrollHeight; y += step) {
    window.scrollTo(0, y);
    await new Promise((resolve) => setTimeout(resolve, 250));
  }
  window.scrollTo(0, 0);
});

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

For sites that append content as the user scrolls, a loop based on the initial document height may stop too early. Re-read the height as you scroll or use a target-specific stopping condition. Puppeteer’s screenshot guide and screenshot reference describe its screenshot API.

Browserless BQL: image waiting is a separate setting

If you use Browserless BQL and the issue is unloaded images, its screenshot operation provides a waitForImages option, which defaults to false. The reference also gives fullPage a false default and documents a 30-second default screenshot timeout. Image waiting and full-page extent address different parts of the capture; neither should be assumed to trigger arbitrary scroll-based page behavior. See the BQL screenshot operation reference for available controls.

Choosing the right settings

Implementation Prepare lazy content Capture full document Key detail
Browserless REST scrollPage: true options.fullPage: true Use the documented REST field locations.
Playwright Page-specific scrolling or another supported preparation fullPage: true Full-page is false by default and defines extent.
Puppeteer Page-specific scrolling or another supported preparation fullPage: true Full-page is false by default and defines extent.
Browserless BQL Use the available controls and target behavior fullPage waitForImages is separate and defaults to false.

Before choosing a service or implementation, check four things: whether it has a documented scroll-before-capture option, whether full-page capture is supported and enabled, whether image waiting is available, and what timeout or navigation-wait behavior applies.

Edge cases and verification

  • Infinite scroll: the page may keep adding content. Decide what counts as the desired end; an unbounded scroll cannot produce a finite, stable capture without a stopping rule.
  • Content added during scrolling: the document height may grow. A loop using only the starting height can miss newly appended sections.
  • Interaction-gated content: scrolling will not open accordions, dismiss overlays, accept consent, or sign in unless the workflow explicitly performs those actions.
  • Slow image delivery: reaching an image can start its request, but the capture may happen before it finishes. Use a documented image-wait option where available or a page-specific readiness check.
  • Sticky headers and animations: these can affect how a tall image looks or when content stabilizes. Review the output at the top, middle, and bottom.
  • Very tall output: full-page images can consume significant memory and may exceed service limits. If the page is exceptionally long, consider capturing sections separately if your workflow permits.

Troubleshooting

Symptom Likely cause Fix
Bottom images are blank or missing The page was captured without scrolling far enough to trigger loading, or capture began before images completed. Enable Browserless REST scrollPage, or add page-specific scrolling in browser automation; use a documented image wait where applicable.
Only the viewport appears Full-page capture is disabled or the option is in the wrong place for that API. Set Playwright/Puppeteer fullPage: true, or Browserless REST options.fullPage: true.
Browserless ignores the scroll option The field may be nested incorrectly or the endpoint may not be Browserless REST Screenshot API. Put scrollPage at the top level of the JSON request and confirm the endpoint’s documented schema.
Capture times out Navigation, resource loading, or page behavior took longer than the configured or service timeout. Review navigation wait behavior and timeout controls; avoid waiting for a condition the page never reaches.
Page height is cut off The page grew after scrolling began, or the capture reached a service or browser limit. Track changing document height, inspect service limits, and capture sections when a single image is impractical.
Some content remains absent after scrolling It may require interaction, authentication, a different trigger, or a page-specific wait. Identify the site’s loading condition and reproduce the required interaction or readiness check before capture.

Performance, reliability, and cost

Scrolling through a long page adds time because the browser must visit regions that were outside the viewport; waiting for images or network activity can add more. A longer timeout alone does not make content load or guarantee correctness. Use the narrowest readiness condition that matches the page, set a timeout that fits the target, and inspect representative captures after changes to the page or capture workflow.

Hosted APIs and self-managed Playwright or Puppeteer have different operational and pricing models. The cited documentation establishes the controls described above, not comparative costs or performance benchmarks. Check the current terms and limits of the exact provider you choose, and account for retries in your own workflow.

Or skip the browser setup

ScreenshotNeo provides a website screenshot API and MCP server. A single GET request can return a screenshot as PNG, JPEG, or WebP, or a PDF. See the ScreenshotNeo site and API documentation for parameters and setup.

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}`);
  • Cookie banners are accepted and removed, and known consent platforms, newsletter popups, and chat widgets are removed before the shot; each step can be turned off.
  • Bot checks and CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed. Response headers report the page verdict and billing status.
  • An MCP server gives AI agents tools to take screenshots, get page information, and capture PDFs.
  • The free plan includes 1,000 screenshots a month with no card. Paid plans start at $5 for 3,000 screenshots.

Sign up free for 1,000 screenshots a month, with no card required.

FAQ

Does full-page capture automatically load every lazy image?

No general guarantee follows from the full-page setting. It defines capture extent in Playwright and Puppeteer; Browserless REST separately documents scrolling before capture to trigger lazy loading.

What scroll distance or pause should I use?

There is no universal value established by the documented controls. Tune the preparation to the target page and verify the image.

Should I use image waiting or scrolling?

They solve different problems. Scrolling can trigger viewport-based loading; image waiting can wait for images according to the provider’s implementation. Some pages need both, and interaction-gated content may need additional steps.