Full-page screenshots
A full-page screenshot captures the whole scrollable document at the viewport width you choose. The image is as tall as the page, up to capture.scroll.max_height. This guide is part of the capture guides. For a comparison with Puppeteer, Playwright, Selenium and browser tools, read full page screenshots: every method tested.
The minimal request
The examples read your key from RS_API_KEY. If you do not have a key, create a free account first.
With GET, use the full_page preset. It sets full-page mode and turns on scroll simulation:
curl -G "https://api.renderscreenshot.com/v1/screenshot" \ -H "Authorization: Bearer $RS_API_KEY" \ --data-urlencode "url=https://example.com" \ --data-urlencode "preset=full_page" \ -o full-page.png
full_page=true also works in GET, but it only sets capture.mode. Scroll simulation stays off, so lazy images below the first screen can stay empty.
With POST, set the mode and the scroll options in capture:
curl -X POST https://api.renderscreenshot.com/v1/screenshot \ -H "Authorization: Bearer $RS_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "url": "https://example.com", "capture": { "mode": "full_page", "scroll": { "simulate": true, "delay": 400 } } }' \ -o full-page.png
Parameters that matter
| Parameter | Default | Notes |
|---|---|---|
capture.mode |
viewport |
Set to full_page. GET: full_page=true or preset=full_page. |
capture.scroll.simulate |
false |
Scrolls through the page before the capture so lazy loaders fire. The full_page preset sets it to true. |
capture.scroll.step |
viewport height | Pixels per scroll step. Smaller steps trigger observers with small margins; more steps take longer. |
capture.scroll.delay |
400 |
Milliseconds to wait at each step. Raise it when images arrive slowly. |
capture.scroll.max_height |
16000 |
Maximum capture height in pixels. Content below it is not captured. |
capture.beyond_viewport |
true |
Captures content outside the visible window. |
viewport.width |
1280 |
The page height depends on the width: narrow layouts are taller. 1 to 7,680. |
viewport.scale |
1 |
2 doubles the pixel height of the image as well as the width. |
wait.until / wait.delay |
load / 0 |
Applied before the scroll. wait.delay is capped at 10,000 ms. |
wait.timeout |
30 |
Seconds for the whole render, maximum 60. Long pages with a slow scroll need more. |
Only full_page and preset exist as GET parameters. scroll.step, scroll.delay and scroll.max_height need POST. See the capture parameter reference.
Estimate the scroll time
The scroll takes about (page height / step) x delay. A 12,000 px page at the default step of 800 px and the default delay of 400 ms needs 15 steps, about 6 seconds, before the capture starts. Keep that below wait.timeout, together with the page load.
Tune the scroll for slow images
When the bottom images of a page are still empty, the scroll moved on before they arrived. Give each step more time, and use a step smaller than the viewport so each image is on screen during at least one pause:
{ "url": "https://example.com/gallery", "capture": { "mode": "full_page", "scroll": { "simulate": true, "step": 600, "delay": 800, "max_height": 12000 } }, "wait": { "until": "networkidle", "timeout": 60 } }
networkidle waits until no request has run for 500 ms, which helps the last images finish after the scroll.
Remove fixed bars before the capture
A fixed cookie bar or chat button is drawn once, where the first screen ends, on top of the content. Remove it in the same request with page modifications:
{ "url": "https://example.com", "capture": { "mode": "full_page", "scroll": { "simulate": true } }, "block": { "cookie_banners": true }, "page": { "remove": [".chat-launcher"], "styles": ["header.site-header { position: absolute !important; }"] } }
The sticky header article explains each failure mode, and block ads and cookie banners covers block.cookie_banners.
SDK examples
All six SDKs have fullPage() (Python and Ruby: full_page) and preset(). Use the preset to get scroll simulation. The builders have no methods for scroll.step, scroll.delay or scroll.max_height; send those in a raw POST body as shown above.
Node.js
import { writeFile } from 'node:fs/promises'; import { Client, TakeOptions } from 'renderscreenshot'; const client = new Client(process.env.RS_API_KEY); const image = await client.take( TakeOptions.url('https://example.com') .preset('full_page') .format('webp') .quality(80) ); await writeFile('full-page.webp', image);
Python
import os from renderscreenshot import Client, TakeOptions client = Client(os.environ['RS_API_KEY']) image = client.take( TakeOptions.url('https://example.com') .preset('full_page') .format('webp') .quality(80) ) with open('full-page.webp', 'wb') as f: f.write(image)
Ruby
require 'renderscreenshot' client = RenderScreenshot.client(ENV.fetch('RS_API_KEY')) image = client.take( RenderScreenshot::TakeOptions .url('https://example.com') .preset('full_page') .format('webp') .quality(80) ) File.binwrite('full-page.webp', image)
PHP
use RenderScreenshot\Client; use RenderScreenshot\TakeOptions; $client = new Client(getenv('RS_API_KEY')); $image = $client->take( TakeOptions::url('https://example.com') ->preset('full_page') ->format('webp') ->quality(80) ); file_put_contents('full-page.webp', $image);
Java
Client client = new Client(System.getenv("RS_API_KEY")); byte[] image = client.take( TakeOptions.url("https://example.com") .preset("full_page") .format("webp") .quality(80) ); Files.write(Path.of("full-page.webp"), image);
Go
client, err := rs.New(os.Getenv("RS_API_KEY")) if err != nil { log.Fatal(err) } image, err := client.Take(ctx, rs.URL("https://example.com"). Preset("full_page"). Format(rs.FormatWebP). Quality(80), ) if err != nil { log.Fatal(err) } os.WriteFile("full-page.webp", image, 0o644)
WebP or JPEG keeps long captures small. A full page at scale 2 has four times the pixels of the same page at 1x; see retina screenshots.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Grey boxes or placeholders below the first screen | Scroll simulation is off (full_page=true alone) |
Use preset=full_page or capture.scroll.simulate: true |
| The last images are still empty | Each step moved on before the images arrived | Raise scroll.delay, lower scroll.step, add wait.until: networkidle |
| Image ends before the page does | scroll.max_height reached (16,000 px by default) |
Raise max_height, or capture one part with element mode |
| Feed or search page never seems to end | Infinite scroll adds content at every step | Set a lower max_height, for example 8,000 |
| Cookie bar in the middle of the image | A fixed bar is drawn where the first screen ended | block.cookie_banners: true or page.remove |
| Header repeated or covering content | Fixed or sticky header | page.styles with position: absolute !important |
| Hero section is much taller than in the browser | The section uses 100vh |
Set a pixel height with page.styles |
| Request times out on long pages | Scroll time plus load time is above wait.timeout |
Raise wait.timeout (max 60) or shorten the scroll with a larger step |
| Image is wider than expected | Content wider than the viewport | Fix the width with viewport.width |
Limits
capture.scroll.max_heightdefaults to 16,000 px. In our browser tests, full Chrome repeated the top of the page after 16,384 device pixels, so check the bottom of the image if you raise it.viewport.widthaccepts 1 to 7,680 px andviewport.scale1 to 3.wait.timeoutis 30 seconds by default and 60 at most.wait.delayis capped at 10,000 ms.- One full-page capture is one render and uses one credit.
Related parameters
- Capture parameters:
mode,scroll.*,clip,beyond_viewport - Presets: what
full_pagesets - Wait strategies:
until,delay,for_selector - Element screenshots: capture one part of a long page instead