Full-Page Screenshot API: Capture Entire Web Pages Programmatically

Published February 22, 2026 • 10 min read

A standard viewport screenshot only captures the visible portion of a page, typically 1280×720 or similar. But most web pages extend well beyond the fold. Landing pages, documentation, pricing tables, legal pages -- they can stretch thousands of pixels tall. If you need the entire page in a single image, you need a full-page screenshot.

This guide covers how to capture full-page screenshots using an API, how to handle tricky scenarios like lazy-loaded images and infinite scroll, and complete code examples you can drop into your project today.

What Is a Full-Page Screenshot?

A full-page screenshot captures the entire scrollable content of a web page in one image, from the top of the <body> to the very bottom. The resulting image is typically the same width as your chosen viewport but much taller than a standard screen.

Common use cases include:

Quick Start: Full-Page Screenshot with curl

The fastest way to capture a full-page screenshot is with the GrabShot API. Pass full_page=true and you get the entire page:

curl "https://grabshot.dev/api/screenshot?url=https://example.com&full_page=true&api_key=YOUR_API_KEY" \
  --output full-page.png

That's it. The API launches a real Chromium browser, loads the page, scrolls to trigger lazy content, and returns a PNG of the full document height.

Customizing the Output

You can control the viewport width, format, and quality:

# Full-page screenshot at 1440px wide, JPEG format, 85% quality
curl "https://grabshot.dev/api/screenshot?\
url=https://example.com\
&full_page=true\
&width=1440\
&format=jpeg\
&quality=85\
&api_key=YOUR_API_KEY" \
  --output full-page.jpg

The viewport width determines the image width. Height is determined automatically by the page content.

Full-Page Screenshots in Node.js

Here's a complete Node.js function that captures a full-page screenshot and saves it to disk:

const fs = require('fs');

async function captureFullPage(url, outputPath, options = {}) {
  const params = new URLSearchParams({
    url,
    full_page: 'true',
    width: options.width || '1280',
    format: options.format || 'png',
    api_key: process.env.GRABSHOT_API_KEY,
  });

  if (options.quality) params.set('quality', options.quality);
  if (options.delay) params.set('delay', options.delay);

  const response = await fetch(
    `https://grabshot.dev/api/screenshot?${params}`
  );

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

  const buffer = Buffer.from(await response.arrayBuffer());
  fs.writeFileSync(outputPath, buffer);

  return { path: outputPath, size: buffer.length };
}

// Usage
const result = await captureFullPage(
  'https://stripe.com/pricing',
  './stripe-pricing-full.png',
  { width: '1440' }
);

console.log(`Saved ${result.size} bytes to ${result.path}`);

Full-Page Screenshots in Python

The same thing in Python using requests:

import requests
import os

def capture_full_page(url, output_path, width=1280, fmt="png", quality=None):
    params = {
        "url": url,
        "full_page": "true",
        "width": width,
        "format": fmt,
        "api_key": os.environ["GRABSHOT_API_KEY"],
    }
    if quality:
        params["quality"] = quality

    resp = requests.get("https://grabshot.dev/api/screenshot", params=params)
    resp.raise_for_status()

    with open(output_path, "wb") as f:
        f.write(resp.content)

    return {"path": output_path, "size": len(resp.content)}


# Capture a full-page screenshot of a documentation site
result = capture_full_page(
    "https://docs.python.org/3/tutorial/index.html",
    "python-docs-full.png",
    width=1440
)
print(f"Saved {result['size']} bytes")

Handling Lazy-Loaded Content

Modern websites defer image loading until the user scrolls them into view. This is great for performance, but it means a naive screenshot of the full page will have blank placeholders where images should be.

GrabShot handles this automatically: before capturing a full-page screenshot, the browser scrolls through the entire page to trigger lazy-loaded images, IntersectionObserver callbacks, and scroll-triggered animations. You can also add a delay to give extra time for content to render:

curl "https://grabshot.dev/api/screenshot?\
url=https://example.com/gallery\
&full_page=true\
&delay=2000\
&api_key=YOUR_API_KEY" \
  --output gallery-full.png

The delay parameter (in milliseconds) adds a pause after the page load event, giving JavaScript time to fetch and render deferred content.

Dealing with Infinite Scroll

Pages with infinite scroll (Twitter feeds, Pinterest boards, search results that load on scroll) present a unique challenge: they never truly "end." The page keeps growing as you scroll.

For these pages, you have two practical strategies:

  1. Set a max height -- cap the screenshot at a specific pixel height to avoid runaway captures
  2. Use viewport-only mode -- skip full_page and capture just what's visible at a specific scroll position
# Capture up to 5000px of an infinite-scroll page
curl "https://grabshot.dev/api/screenshot?\
url=https://example.com/feed\
&full_page=true\
&max_height=5000\
&api_key=YOUR_API_KEY" \
  --output feed-partial.png

This prevents the API from scrolling indefinitely and gives you a practical snapshot of the first chunk of content.

Full-Page Screenshots for Visual Regression Testing

One of the most valuable uses of full-page screenshots is visual regression testing. By capturing the complete page before and after a code change, you can detect unintended layout shifts, broken styles, or missing content anywhere on the page -- not just above the fold.

A basic workflow looks like this:

  1. Capture a baseline full-page screenshot on your main branch
  2. Deploy or preview the new branch
  3. Capture the same page again
  4. Diff the two images pixel-by-pixel
  5. Flag any differences above a threshold
const { execSync } = require('child_process');

// Capture baseline and candidate
async function comparePages(baseUrl, candidateUrl, pagePath) {
  const baseline = await captureFullPage(
    `${baseUrl}${pagePath}`,
    `./screenshots/baseline-${Date.now()}.png`,
    { width: '1440' }
  );

  const candidate = await captureFullPage(
    `${candidateUrl}${pagePath}`,
    `./screenshots/candidate-${Date.now()}.png`,
    { width: '1440' }
  );

  // Use ImageMagick to generate a diff
  const diffPath = `./screenshots/diff-${Date.now()}.png`;
  execSync(
    `compare -metric AE "${baseline.path}" "${candidate.path}" "${diffPath}"`,
    { stdio: 'pipe' }
  );

  return { baseline, candidate, diff: diffPath };
}

For a more complete solution, check out DiffShot, which handles the comparison, highlighting, and reporting for you.

Try Full-Page Screenshots Free

GrabShot's free plan includes 25 screenshots per month with full-page support. No credit card required.

Try It Now →

Optimizing Large Screenshots

Full-page screenshots of content-heavy sites can produce large files. A 1440px-wide screenshot of a long page might weigh 5-15 MB as a PNG. Here are some strategies to keep file sizes manageable:

Strategy How Typical Savings
Use JPEG instead of PNG format=jpeg&quality=80 60-80% smaller
Use WebP format=webp&quality=80 70-85% smaller
Reduce viewport width width=1024 30-50% smaller
Set max height max_height=3000 Caps file size

For archival purposes, PNG is the safest choice (lossless). For sharing on Slack, embedding in reports, or visual comparisons where pixel-perfect accuracy isn't critical, JPEG or WebP will save significant bandwidth.

Full-Page Screenshots of Authenticated Pages

Need to capture a dashboard or admin panel behind a login? You can pass cookies or custom headers to the API:

curl "https://grabshot.dev/api/screenshot?\
url=https://app.example.com/dashboard\
&full_page=true\
&api_key=YOUR_API_KEY" \
  -H "X-Screenshot-Cookie: session_id=abc123; token=xyz789" \
  --output dashboard-full.png

This lets you capture internal tools, SaaS dashboards, and gated content without exposing credentials in the URL.

When Not to Use Full-Page Mode

Full-page screenshots aren't always the right tool. Skip them when:

Summary

Full-page screenshots let you capture every pixel of a web page in a single image. With the GrabShot API, it's a single parameter: full_page=true. The API handles lazy loading, scrolling, and rendering automatically.

Whether you're archiving legal documents, running visual regression tests, or building design review workflows, full-page capture gives you the complete picture. Try it free and see for yourself.