How to Take Full Page Screenshots with an API
A viewport screenshot captures 800 pixels of content. A full page screenshot captures everything — the entire scrollable page from header to footer. Here's how to do it with a simple API call, and how it compares to self-hosted browser approaches.
Viewport vs full page: the difference
Every screenshot tool defaults to viewport mode — it captures only what fits in the browser window. For most websites, that's the header, hero section, and maybe the first content block. Everything below the fold is cut off.
Viewport screenshot
- Captures visible area only (e.g., 1280x800)
- Small file size
- Fast capture
- Good for: thumbnails, previews, OG images
Full page screenshot
- Captures entire scrollable content
- Can be 5,000-20,000+ pixels tall
- Slightly slower (full render needed)
- Good for: archival, QA, design review, documentation
SnapRender API (easiest)
Add full_page: true to your request body. That's it. The API scrolls the page, triggers lazy loading, waits for content to render, and captures the full scrollable height.
Viewport only (default)
// Viewport-only screenshot (default behavior)
const response = await fetch('https://api.snaprender.dev/v1/screenshot', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
url: 'https://example.com',
viewport: { width: 1280, height: 800 }
})
});
// Result: 1280x800 image — only what's visible in the "window"Full page
// Full page screenshot — captures entire scrollable content
const response = await fetch('https://api.snaprender.dev/v1/screenshot', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
url: 'https://example.com',
full_page: true,
viewport: { width: 1280, height: 800 }
})
});
// Result: 1280x(full height) image — entire page capturedPuppeteer
Puppeteer supports fullPage: true natively. It works well for static pages, but lazy-loaded content requires manual scrolling before capture.
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.setViewport({ width: 1280, height: 800 });
await page.goto('https://example.com', { waitUntil: 'networkidle2' });
// Full page screenshot
await page.screenshot({
path: 'full-page.png',
fullPage: true // <-- this is the key parameter
});
await browser.close();
})();Playwright
Same parameter as Puppeteer. Playwright's auto-waiting helps with dynamic content, but lazy-loaded images still need a scroll-to-bottom pass for complete capture.
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch();
const page = await browser.newPage({
viewport: { width: 1280, height: 800 }
});
await page.goto('https://example.com');
// Full page screenshot
await page.screenshot({
path: 'full-page.png',
fullPage: true // <-- same parameter name
});
await browser.close();
})();The lazy loading problem
Most modern websites lazy-load images and content. Images below the fold don't load until the user scrolls to them. With fullPage: true, Puppeteer and Playwright expand the viewport but don't trigger scroll events — so lazy-loaded images show as blank placeholders.
The fix is to scroll to the bottom of the page before capturing. SnapRender does this automatically. With Puppeteer, you need a manual scroll function:
// SnapRender handles lazy-loaded content automatically.
// With Puppeteer, you need manual scrolling:
async function scrollToBottom(page) {
await page.evaluate(async () => {
await new Promise((resolve) => {
let totalHeight = 0;
const distance = 500;
const timer = setInterval(() => {
window.scrollBy(0, distance);
totalHeight += distance;
if (totalHeight >= document.body.scrollHeight) {
clearInterval(timer);
resolve();
}
}, 100);
});
});
}
// Scroll first to trigger lazy loading, then capture
await scrollToBottom(page);
await page.screenshot({ path: 'full-page.png', fullPage: true });SnapRender handles this automatically. The API scrolls the page, waits for lazy-loaded content to render, then captures. No extra code needed — just set full_page: true.
Full page screenshots in any language
Since SnapRender is a REST API, full page screenshots work from any language or tool. Here are Python and cURL examples:
Python
import requests
# Full page screenshot with SnapRender API
response = requests.post(
"https://api.snaprender.dev/v1/screenshot",
headers={"Authorization": "Bearer YOUR_API_KEY"},
json={
"url": "https://example.com",
"full_page": True,
"viewport": {"width": 1440, "height": 900},
"format": "png"
}
)
with open("full-page.png", "wb") as f:
f.write(response.content)cURL
curl -X POST https://api.snaprender.dev/v1/screenshot \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com",
"full_page": true,
"viewport": {"width": 1280, "height": 800},
"format": "png"
}' \
--output full-page.pngMethod comparison
| Feature | Puppeteer | Playwright | SnapRender |
|---|---|---|---|
| Full page support | Yes (fullPage: true) | Yes (fullPage: true) | Yes (full_page: true) |
| Lazy load handling | Manual scroll needed | Manual scroll needed | Automatic |
| Sticky element handling | Manual CSS injection | Manual CSS injection | Automatic |
| Cloudflare sites | Blocked | Blocked | Bypass included |
| Max page height | Browser memory limit | Browser memory limit | 20,000px |
| Setup required | Chromium install | Browser install | None (API call) |
Full page screenshots, zero setup
100 free screenshots per month. Full page, lazy loading handled, Cloudflare bypass included. No browser to install. No credit card.
Get your API keyFrequently asked questions
A full page screenshot captures the entire scrollable length of a web page — not just the visible viewport. The resulting image can be thousands of pixels tall, capturing everything from the header to the footer including content that requires scrolling to see.
The browser calculates the total height of the page content, resizes its internal viewport to match, and captures the entire area in one render pass. This is more reliable than scrolling and stitching multiple viewport captures, which can miss sticky elements or cause layout shifts.
A viewport screenshot captures only what's visible in the browser window (typically 1280x800 pixels). A full page screenshot captures the entire scrollable content, which can be 5,000-20,000+ pixels tall depending on the page.
It depends. Puppeteer and Playwright need custom scrolling logic to trigger lazy-loaded images before capture. SnapRender's API handles this automatically — it scrolls the page to trigger lazy loading before capturing the full page.
SnapRender is the easiest — add full_page: true to your API request. No browser setup, handles lazy loading, works with Cloudflare-protected sites. Puppeteer and Playwright also support it but require self-hosted infrastructure.