By default the API takes the screenshot when the browser fires its load event. Many pages are not finished at that moment: they still fetch data, or they load images only when you scroll. You will find which case you have and add the option that fixes it.
The examples use two small test pages, so the result is the same every time you run them.
Find the cause
| You see | Cause | Fix |
|---|---|---|
| A spinner, "Loading…" or empty cards | The page fetches its data after load |
Step 2: wait for a selector |
| Grey boxes where images should be (full page) | Images load when they scroll into view | Step 3: simulate scrolling |
Error timeout (422) |
The page never reached the wait condition | Step 4 |
| A cookie banner, an ad or a sign-up box | Not a timing problem | Remove cookie banners and ads |
| "Access denied" or a challenge page | The site blocks automated browsers | Capture sites with bot protection |
For a failed request, open Logs, click the request, and read the error message:
Wait for the content
Find an element that exists only when the content is ready: the chart, the first row of a table, the product price. Open the page in your browser, inspect that element and copy a selector for it.
Then ask the API to wait for it:
{ "url": "https://app.example.com/reports/weekly", "wait": { "for_selector": "#report", "for_selector_mode": "visible" } }
Node.js
const image = await client.take( TakeOptions.url('https://app.example.com/reports/weekly').waitForSelector('#report') );
Python
image = client.take( TakeOptions.url('https://app.example.com/reports/weekly').wait_for_selector('#report') )
Ruby
image = client.take( RenderScreenshot::TakeOptions.url('https://app.example.com/reports/weekly').wait_for_selector('#report') )
CLI
rs take https://app.example.com/reports/weekly --wait-selector "#report" -o report.png
If you own the page, the most reliable signal is one you add yourself: set an attribute when the page is done, for example document.documentElement.dataset.screenshotReady = 'true', and wait for html[data-screenshot-ready="true"].
No good selector? Two other options:
| Option | Use when |
|---|---|
"wait": { "until": "networkidle" } |
The page stops making requests when it is done. Not good for pages with live chat, analytics beacons or polling. |
"wait": { "delay": 2000 } |
You know the page needs a fixed time. Adds the delay to every request, up to 10,000 ms. |
Load lazy images
A full-page capture takes the whole page in one image, but the browser does not scroll. Images that load on scroll stay grey. Turn on scroll simulation:
{ "url": "https://shop.example.com/collections/spring", "capture": { "mode": "full_page", "scroll": { "simulate": true, "delay": 400 } } }
The full_page preset turns scroll simulation on for you. Raise scroll.delay (milliseconds between scroll steps) for pages with slow images.
Fix timeouts
A timeout means the page did not reach the wait condition within wait.timeout (30 seconds by default). Try these in order:
- Wait for a selector instead of
networkidle. Pages with chat widgets or analytics never become idle. - Block what you do not need. Ads, trackers and chat widgets are often the slowest part of a page:
{ "block": { "ads": true, "trackers": true, "chat_widgets": true } }
- Raise the timeout, up to 60 seconds. Also raise your HTTP client timeout above it, or your code gives up first:
{ "wait": { "for_selector": "#report", "timeout": 45 } }
A timeout costs no credits, and retryable is true, so one retry is fine. If the same URL times out again with 45 seconds, the page needs one of the other fixes.
Next steps
- Remove cookie banners and ads.
- Capture pages behind a login.
- The full list of wait options is in wait strategies.