arrow_back Back to blog
Tutorials April 12, 2026 4 min read

How to Capture Full Page Screenshots with an API

Taking a screenshot of a page is easy. Taking a screenshot of the entire page — every pixel, below the fold, past the lazy-loaded content — is where things get interesting.

Most headless browser setups require you to scroll the page, wait for images to load, calculate the full document height, resize the viewport, and then capture. That’s a lot of code for something that should be one parameter.

With len.sh, it is one parameter.


The Basics: full_page=true

curl "https://api.len.sh/v1/screenshot?url=https://example.com&full_page=true&access_key=YOUR_API_KEY" \
  --output full-page.png

That captures the entire scrollable page from top to bottom in a single PNG. The default viewport width is 1280px, and the height extends to fit the full document.

Without full_page, you get only the visible viewport (1280x720 by default). With it, you get everything.


Handling Lazy-Loaded Content

Modern sites load images and content as you scroll. A naive full-page screenshot will capture placeholder elements instead of the actual content.

The wait_until parameter controls when len.sh considers the page ready:

ValueBehavior
load (default)Wait for the load event
domcontentloadedDOM is parsed, don’t wait for images
networkidle0No network activity for 500ms
networkidle2At most 2 network connections for 500ms

For pages with lazy loading, use networkidle2 to let content finish loading:

curl "https://api.len.sh/v1/screenshot\
?url=https://example.com/blog\
&full_page=true\
&wait_until=networkidle2\
&access_key=YOUR_API_KEY" --output blog-full.png

If the page triggers loading via scroll events that a static viewport won’t fire, add a delay to give the browser extra time:

curl "https://api.len.sh/v1/screenshot\
?url=https://example.com/feed\
&full_page=true\
&wait_until=networkidle2\
&delay=2000\
&access_key=YOUR_API_KEY" --output feed.png

Controlling Width and Format

Full page screenshots can get large. A few parameters help you control the output:

Width — set the viewport width to match your target device:

# Mobile-width full page
curl "https://api.len.sh/v1/screenshot\
?url=https://example.com\
&full_page=true\
&width=390\
&access_key=YOUR_API_KEY" --output mobile-full.png

Format and quality — use WebP or JPEG to reduce file size:

# WebP at 70% quality
curl "https://api.len.sh/v1/screenshot\
?url=https://example.com\
&full_page=true\
&format=webp\
&quality=70\
&access_key=YOUR_API_KEY" --output full-page.webp

Device emulation — capture as a specific device:

# Full page as iPhone 15
curl "https://api.len.sh/v1/screenshot\
?url=https://example.com\
&full_page=true\
&device=iphone-15\
&access_key=YOUR_API_KEY" --output iphone-full.png

Available device presets include iphone-15, iphone-15-pro-max, ipad-pro, pixel-8, samsung-s24, macbook-pro-16, desktop-1080p, and desktop-4k.


Dealing with Fixed Headers and Sticky Elements

Fixed navigation bars and sticky elements can repeat across every “viewport” in a full page screenshot, creating visual noise. Inject custom CSS to hide them:

curl "https://api.len.sh/v1/screenshot\
?url=https://example.com\
&full_page=true\
&css=header,nav,.sticky-bar,.fixed-banner{position:static!important;}\
&access_key=YOUR_API_KEY" --output clean-full-page.png

Or remove them entirely:

curl "https://api.len.sh/v1/screenshot\
?url=https://example.com\
&full_page=true\
&css=.cookie-banner,.newsletter-popup{display:none!important;}\
&access_key=YOUR_API_KEY" --output no-popups.png

len.sh also has built-in blockers for common annoyances:

curl "https://api.len.sh/v1/screenshot\
?url=https://example.com\
&full_page=true\
&block_ads=true\
&block_cookie_banners=true\
&block_popups=true\
&access_key=YOUR_API_KEY" --output clean.png

Capturing a Specific Element Instead

Sometimes you don’t want the full page. You want a specific section. The selector parameter captures just the matching element:

# Capture only the main content area
curl "https://api.len.sh/v1/screenshot\
?url=https://example.com/article\
&selector=article.main-content\
&access_key=YOUR_API_KEY" --output article.png

This is useful for capturing specific components, charts, or content blocks without the surrounding page chrome.


Code Examples

JavaScript (Node.js)

const response = await fetch(
  "https://api.len.sh/v1/screenshot?" +
    new URLSearchParams({
      url: "https://example.com",
      full_page: "true",
      wait_until: "networkidle2",
      format: "webp",
      quality: "80",
      access_key: "YOUR_API_KEY",
    })
);

const buffer = await response.arrayBuffer();
await Bun.write("full-page.webp", buffer);

Python

import requests

response = requests.get("https://api.len.sh/v1/screenshot", params={
    "url": "https://example.com",
    "full_page": "true",
    "wait_until": "networkidle2",
    "format": "webp",
    "quality": 80,
    "access_key": "YOUR_API_KEY",
})

with open("full-page.webp", "wb") as f:
    f.write(response.content)

Using the len.sh SDK

import { LenSh } from "@len-sh/sdk";

const client = new LenSh({ accessKey: "YOUR_API_KEY" });

const screenshot = await client.screenshot({
  url: "https://example.com",
  fullPage: true,
  waitUntil: "networkidle2",
  format: "webp",
  quality: 80,
});

await Bun.write("full-page.webp", screenshot);

Retina / High-DPI Screenshots

For crisp screenshots on retina displays, use the device_scale parameter:

# 2x retina full page screenshot
curl "https://api.len.sh/v1/screenshot\
?url=https://example.com\
&full_page=true\
&device_scale=2\
&access_key=YOUR_API_KEY" --output retina-full.png

The output image will be 2560px wide (1280 viewport x 2 scale). File sizes increase proportionally, so consider using WebP format for retina captures.


Caching

Full page screenshots are cached by default for 24 hours (86400 seconds). Override this with cache_ttl:

# Cache for 1 hour
curl "https://api.len.sh/v1/screenshot\
?url=https://example.com\
&full_page=true\
&cache_ttl=3600\
&access_key=YOUR_API_KEY" --output cached.png

# No cache (always fresh)
curl "https://api.len.sh/v1/screenshot\
?url=https://example.com\
&full_page=true\
&cache_ttl=0\
&access_key=YOUR_API_KEY" --output fresh.png

Cached screenshots are served from Cloudflare’s edge network, so subsequent requests for the same URL and parameters are fast.


Common Use Cases

Archiving — capture full page snapshots of web pages for legal or compliance records.

QA and testing — generate full page screenshots across multiple viewport widths to verify responsive layouts.

Portfolio and case studies — show complete page designs in client presentations.

Content monitoring — track visual changes to competitor pages, pricing pages, or product listings.

Documentation — capture tool interfaces and dashboards for user guides.


Pricing

Full page screenshots count as one screenshot toward your monthly quota, regardless of page length. The Free tier includes 100 screenshots/month. Pro (25,000/month) starts at EUR 19/month.

All plans include full API access with no feature gating.

Try len.sh for free

Start capturing screenshots with a simple API call. No credit card required.