ScreenshotNeo

BlogHow-to

How to Take a Full-Page Screenshot of a Scrolling Page with BrowserCat

Use Playwright’s fullPage option with a BrowserCat cloud browser to capture a scrolling page. Learn how to handle lazy content, nested scrollers, and common failures.

By the ScreenshotNeo team4 October 20266 min read

To capture a page that extends below the visible viewport with BrowserCat, connect Playwright to BrowserCat, navigate to the page, then call page.screenshot({ path: 'screenshot.png', fullPage: true }). Playwright’s fullPage: true option captures the full scrollable page as if it were displayed on a very tall screen. BrowserCat’s quick start uses a hosted Chromium browser connected at wss://api.browsercat.com/connect. BrowserCat quick start · Playwright screenshot guide

1. Set up Playwright and connect BrowserCat

BrowserCat recommends Playwright as its starting integration. Create a BrowserCat account and API key, install the Node.js dependencies, then keep the key in an environment variable. Do not put a real key in source control.

npm init -y
npm install playwright-core

Save the following as full-page.js. This is a complete Node.js script that connects to BrowserCat, opens a page, waits for the document load event, captures a full-page PNG, and closes the browser even if navigation or capture fails.

import { chromium } from 'playwright-core';

const apiKey = process.env.BROWSERCAT_API_KEY;
const targetUrl = process.argv[2] ?? 'https://example.com';

if (!apiKey) {
  throw new Error('Set BROWSERCAT_API_KEY before running this script.');
}

const browser = await chromium.connect('wss://api.browsercat.com/connect', {
  headers: { 'Api-Key': apiKey },
});

try {
  const context = await browser.newContext();
  const page = await context.newPage();
  await page.goto(targetUrl, { waitUntil: 'load', timeout: 60_000 });
  await page.screenshot({ path: 'screenshot.png', fullPage: true });
  console.log('Saved screenshot.png');
} finally {
  await browser.close();
}

Run it by setting your API key and passing the page URL:

export BROWSERCAT_API_KEY='YOUR_API_KEY'
node full-page.js 'https://example.com'

BrowserCat’s connection example imports Playwright, connects through the WebSocket endpoint with an Api-Key header, and then uses the connected browser to create pages. Its hosted sessions run on Chromium in new headless mode. See the BrowserCat setup guide for account and key steps.

2. Decide when the page is ready

fullPage: true controls capture size; it does not decide whether all application content has finished loading. Select a navigation wait condition that matches the target site, then wait for a meaningful page-specific signal where needed.

Wait strategy Use it when Tradeoff
waitUntil: 'load' You need the document and load-event resources to finish. Some pages continue fetching or rendering after this event.
waitUntil: 'domcontentloaded' The page can render content after its initial HTML parses. Images and app data may still be pending.
Wait for a selector A known heading, table, or app container signals usable content. Choose a selector that reflects the actual content, not just the shell.
Short explicit delay A site has a known animation or delayed render and no better signal. Fixed delays can waste time or still be too short.

For example, if a report appears after the app renders a results container, wait for that container before taking the screenshot:

await page.goto(targetUrl, { waitUntil: 'domcontentloaded', timeout: 60_000 });
await page.locator('[data-testid="report-results"]').waitFor({ state: 'visible', timeout: 30_000 });
await page.screenshot({ path: 'report.png', fullPage: true });

Replace the example selector with a stable selector from the target site. If content depends on scrolling into view, a full-page screenshot does not guarantee that scrolling behavior will be triggered. Inspect the result and handle that page’s loading pattern explicitly.

3. Handle lazy-loaded content and nested scroll areas

Full-page capture describes the full scrollable document, but the cited BrowserCat and Playwright guides do not promise to expand nested scroll panels or trigger every asset that loads only when scrolled into view. Check the output for missing images, cards, and rows. If the page lazy-loads as the main document scrolls, you can scroll through it before capturing, allowing page-specific load handlers to run:

await page.goto(targetUrl, { waitUntil: 'load', timeout: 60_000 });
await page.evaluate(async () => {
  const step = Math.max(300, window.innerHeight * 0.8);
  for (let y = 0; y < document.documentElement.scrollHeight; y += step) {
    window.scrollTo(0, y);
    await new Promise(resolve => setTimeout(resolve, 150));
  }
  window.scrollTo(0, 0);
});
await page.screenshot({ path: 'screenshot.png', fullPage: true });

This scroll loop is a practical fallback, not a universal guarantee: content can change the page height while loading, and site code may load only after a particular interaction. For a nested panel with its own scrollbar, identify and scroll that panel separately, or capture the panel as an element if that is the actual deliverable. Playwright supports locator-level screenshots for a single element; see its screenshot documentation.

4. Choose file output or a buffer

Use the path option when the script should save directly to disk. Without a path, Playwright returns an image buffer that you can pass to storage or image-processing code.

const pngBuffer = await page.screenshot({ fullPage: true });
// Pass pngBuffer to your storage or image-processing code.

Playwright documents both saving to a file and returning a buffer. Its screenshot API also accepts options for image format, clip area, and quality. For a full-page capture, the main setting needed here is fullPage: true; use other output options only when your downstream workflow requires them.

5. Common problems and fixes

Symptom Likely cause Fix
BrowserCat connection fails The API key is missing or invalid, or the WebSocket endpoint or header is mistyped. Check the key in the BrowserCat dashboard, confirm the endpoint is wss://api.browsercat.com/connect, and pass the key as Api-Key.
Screenshot contains only the first viewport The screenshot call omitted the full-page option. Set fullPage: true in page.screenshot().
Page is mostly blank or unfinished The screenshot was taken before the app rendered its useful content. Wait for a page-specific selector or a known application-ready signal before capture.
Images or content near the bottom are missing They may be lazy-loaded only when scrolled into view. Scroll through the main document before capture, then inspect the result. Handle site-specific loading where needed.
A scrollable widget is cut off It is a nested scroller, separate from the document’s main scroll area. Scroll that element explicitly or capture the element itself; full-page mode is for the page’s scrollable document.
Navigation times out The site remains active after the chosen event or is slow to respond. Choose a suitable navigation event, set a justified timeout, and wait on a specific content selector rather than assuming every background request ends.
Output is too large for the next processing step A long page produces a tall image with many pixels. Save the buffer and resize or process it downstream, or capture only the section needed.

6. Performance, reliability, and cost considerations

  • Very tall pages take more resources: capture time and image size grow with page dimensions. Avoid repeated fixed delays; wait on actual content when possible.
  • Stabilize dynamic pages: personalized content, animation, rotating banners, and data updates can make repeated screenshots differ. Wait for the intended state and inspect representative outputs.
  • Close sessions: use try/finally so the remote browser closes when an error occurs.
  • Protect credentials: use environment variables or a secret manager. BrowserCat’s configuration documentation says to use secure https/wss connections when credentials are involved.
  • Verify current service settings: browser availability and configuration options can change; check BrowserCat’s current browser configuration docs before depending on a particular engine or option.

Or skip the browser setup

If you only need a website screenshot, ScreenshotNeo offers a one-call screenshot API. The request below returns a full-page WebP image:

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

See the ScreenshotNeo API documentation for request options and setup. 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 ScreenshotNeo and get 1,000 screenshots a month free, with no card.

FAQ

Does fullPage: true scroll the page like a person?

It captures the full scrollable page as if displayed on a very tall screen. That description does not guarantee that page-specific lazy loading or nested scroll panels will be triggered.

Can I capture a screenshot without creating a local PNG file?

Yes. Call page.screenshot({ fullPage: true }) without path to receive an image buffer.

Which browser does the BrowserCat quick start use?

The quick start says hosted sessions run on Chromium in new headless mode. Check BrowserCat’s current configuration documentation for changes.

Sources