ScreenshotAPI Timeout Error When Capturing Slow Websites: Fixes
Diagnose ScreenshotAPI.net timeouts and choose the right timeout, wait event, delay, or lazy-load settings. Learn when a timeout change cannot help.
Direct answer: First check the HTTP status and API error code. For ScreenshotAPI.net, a timeout_error with HTTP 408 means the render exceeded its time budget. Increase the timeout in milliseconds only if the page legitimately needs longer; choose a suitable wait_for_event, add a modest delay for content that appears after that event, or enable lazy_load when off-screen content needs scrolling to load. A longer timeout does not fix an unreachable site, TLS failure, quota limit, or service outage. [ScreenshotAPI.net error reference]
This guide is specifically for ScreenshotAPI.net and its /v3/screenshot endpoint. Other services with similar names may use different parameters and limits; do not copy these settings into another provider’s request.
1. Confirm the endpoint and inspect the response
The documented render endpoint is https://shot.screenshotapi.net/v3/screenshot. Its token parameter is the API key. Keep the key out of source control and logs. Start with the exact HTTP status and response body or error code rather than raising the timeout for every failure.
curl -G 'https://shot.screenshotapi.net/v3/screenshot' \
--data-urlencode 'token=YOUR_API_KEY' \
--data-urlencode 'url=https://example.com' \
-o screenshot.png \
-w '\nHTTP %{http_code}\n'
On an error response, inspect the response body and headers before treating the downloaded file as an image. The vendor’s error catalogue distinguishes timeouts from request aborts, unreachable addresses, refused connections, network or tunnel errors, TLS errors, rate limits, quota failures, and temporary service errors.
2. Classify the failure before changing settings
| Observed result | Likely meaning | Next action |
|---|---|---|
timeout_error, HTTP 408 |
The render took longer than the service’s allowed duration. | Check the site’s behavior and the configured timeout. Tune the wait event, delay, or lazy loading to the actual symptom. |
request_aborted |
The vendor lists timeout, network trouble, or manual cancellation as possible causes. | Check caller/job-runner logs and the response. Determine which layer cancelled the request before changing the render timeout. |
| Unreachable address, connection refused, network or tunnel error | The rendering service could not establish the needed connection to the destination. | Verify the URL, redirects, destination availability, and network accessibility. A longer page timeout is not a connectivity repair. |
| SSL/TLS error | The destination’s TLS handshake or certificate setup failed for the renderer. | Check the destination’s HTTPS configuration and certificate chain. |
| HTTP 429, quota error | A rate or account limit was reached. | Check the account’s limit and usage. Waiting for a new page timeout will not restore quota. |
| Temporary service or internal error, including HTTP 503 | The service may be temporarily unavailable. | Retry later with a bounded retry policy; avoid rapid repeated requests. |
Error names and statuses above follow the vendor’s error documentation. The request_aborted category can have multiple causes, so corroborate it with your caller’s logs and target reachability.
3. Tune the render timeout
The timeout parameter is measured in milliseconds. ScreenshotAPI.net documents a default of 100000 ms and warns that a value that is too low can abort a page before it loads. Increase it when the target has a real reason to need additional rendering time, such as slow initial responses or substantial client-side work.
curl -G 'https://shot.screenshotapi.net/v3/screenshot' \
--data-urlencode 'token=YOUR_API_KEY' \
--data-urlencode 'url=https://example.com' \
--data-urlencode 'timeout=150000' \
-o screenshot.png
Choose a value that fits within the deadline of the application, queue worker, proxy, or job runner making the request. If an outer layer cancels the request sooner, increasing the renderer’s timeout will not help. That outer-deadline check is general integration guidance; ScreenshotAPI.net documents the render timeout, not your client’s deadline.
A larger timeout gives slow pages more time, but also holds the request open longer. Avoid applying a large value indiscriminately: first determine whether the page is slow to navigate, waiting on a never-ending request, or waiting for content that arrives after the chosen event.
4. Match the wait event to the page
wait_for_event determines which browser page-load event ScreenshotAPI.net waits for before proceeding. The documented default is load.
| Value | What it waits for | Use it when | Tradeoff |
|---|---|---|---|
load |
The page’s assets finish loading. | You want a fuller resource load and the site completes its requests normally. | Can take longer than an earlier event. |
domcontentloaded |
The HTML has been parsed; it does not wait for every image, stylesheet, or other resource. | The page structure is enough and waiting for all resources is unnecessary. | Late assets or script-rendered content may be absent. |
networkidle |
No active network requests for at least 500 ms. | Dynamic requests settle and that point corresponds to usable content. | Persistent polling, analytics, or other ongoing requests can keep the page from becoming idle. |
For a slow site that keeps making requests, switching to domcontentloaded can avoid waiting for every resource, but inspect the result for missing content. If the page renders its useful data asynchronously, a faster event may capture too early; use a delay or a more suitable event instead.
curl -G 'https://shot.screenshotapi.net/v3/screenshot' \
--data-urlencode 'token=YOUR_API_KEY' \
--data-urlencode 'url=https://example.com' \
--data-urlencode 'wait_for_event=domcontentloaded' \
-o screenshot.png
These event definitions and the 500 ms network-idle condition are from the vendor’s wait, lazy-loading, and delay documentation.
5. Add a delay only for late-arriving content
delay adds time after the chosen page-load event before capture. The documented default is 0 ms. It is useful for a chart, animation, or API-driven component that appears shortly after the selected event. It is not a substitute for fixing a page that never becomes reachable.
curl -G 'https://shot.screenshotapi.net/v3/screenshot' \
--data-urlencode 'token=YOUR_API_KEY' \
--data-urlencode 'url=https://example.com' \
--data-urlencode 'wait_for_event=domcontentloaded' \
--data-urlencode 'delay=2000' \
-o screenshot.png
Start with a modest delay and inspect whether the needed content appears. Larger delays add rendering time to each capture. If the target’s requests never settle, a delay does not make networkidle finish; choose an event that fits the page.
6. Enable lazy loading for content that appears on scroll
A full-page capture can miss images or sections that the site loads only after they enter the viewport. lazy_load=true simulates scrolling to trigger that deferred content. The documented default is false. scroll_delay sets the pause between simulated scroll steps and defaults to 500 ms; the vendor describes 200–500 ms as moderate for many sites.
curl -G 'https://shot.screenshotapi.net/v3/screenshot' \
--data-urlencode 'token=YOUR_API_KEY' \
--data-urlencode 'url=https://example.com/long-page' \
--data-urlencode 'lazy_load=true' \
--data-urlencode 'scroll_delay=300' \
-o screenshot.png
Use lazy loading when the missing content is tied to scrolling, not simply because the page is slow. A long page multiplied by pauses at multiple scroll positions can consume the timeout budget. If the capture then times out, reduce unnecessary scrolling or the per-step delay, and set a sufficient timeout based on the page.
7. Runnable request examples
The following examples use the documented ScreenshotAPI.net endpoint, token parameter, and the same settings. Replace the placeholder key and target URL. These examples focus on timeout-related configuration; add only the options needed for the page.
cURL
curl -G 'https://shot.screenshotapi.net/v3/screenshot' \
--data-urlencode 'token=YOUR_API_KEY' \
--data-urlencode 'url=https://example.com/slow-page' \
--data-urlencode 'timeout=150000' \
--data-urlencode 'wait_for_event=load' \
--data-urlencode 'delay=1000' \
--data-urlencode 'lazy_load=true' \
--data-urlencode 'scroll_delay=300' \
-o screenshot.png \
-w '\nHTTP %{http_code}\n'
Python
import requests
endpoint = "https://shot.screenshotapi.net/v3/screenshot"
params = {
"token": "YOUR_API_KEY",
"url": "https://example.com/slow-page",
"timeout": 150000,
"wait_for_event": "load",
"delay": 1000,
"lazy_load": "true",
"scroll_delay": 300,
}
response = requests.get(endpoint, params=params, timeout=180)
content_type = response.headers.get("content-type", "")
if not response.ok or "image/" not in content_type:
raise RuntimeError(
f"Screenshot request failed: HTTP {response.status_code}; "
f"content-type={content_type}; body={response.text[:1000]}"
)
with open("screenshot.png", "wb") as image_file:
image_file.write(response.content)
The Python HTTP client timeout is an outer client deadline, in seconds; it is separate from the API’s render timeout in milliseconds. Set the client deadline long enough for the render request and normal network overhead, or the client can stop waiting before the renderer responds.
Node.js
const endpoint = new URL("https://shot.screenshotapi.net/v3/screenshot");
const params = {
token: "YOUR_API_KEY",
url: "https://example.com/slow-page",
timeout: "150000",
wait_for_event: "load",
delay: "1000",
lazy_load: "true",
scroll_delay: "300",
};
for (const [key, value] of Object.entries(params)) {
endpoint.searchParams.set(key, value);
}
const response = await fetch(endpoint, { signal: AbortSignal.timeout(180_000) });
const contentType = response.headers.get("content-type") ?? "";
if (!response.ok || !contentType.startsWith("image/")) {
const body = await response.text();
throw new Error(`Screenshot request failed: HTTP ${response.status}; ${body.slice(0, 1000)}`);
}
const image = Buffer.from(await response.arrayBuffer());
await import("node:fs/promises").then(({ writeFile }) => writeFile("screenshot.png", image));
The explicit client-side timeouts in these examples are caller-side safeguards, not ScreenshotAPI.net parameters. Make them longer than the intended server render budget.
8. A practical tuning sequence
- Confirm the request is going to
https://shot.screenshotapi.net/v3/screenshot, with a valid token and URL. - Record the HTTP status and vendor error code. Follow the error category before changing the render timeout.
- For
timeout_error/ 408, check whether the target is genuinely slow and whether your client or job runner has a shorter deadline. - Keep
loadwhen complete resources matter. Trydomcontentloadedif HTML structure is enough and late resources are not required. - Add a small
delayif needed content appears just after the chosen event. - Set
lazy_load=trueonly for content triggered by scrolling. Keepscroll_delaymoderate, especially on long pages. - Change one setting at a time and compare the error and resulting image. This makes it clear which behavior affected the capture.
- If the error is connectivity, TLS, quota, rate limit, or service availability, address that condition directly; do not keep increasing timeout.
9. Troubleshooting common timeout symptoms
| Symptom | Cause to check | Fix |
|---|---|---|
408 / timeout_error on an otherwise reachable page |
The render budget is too short for the target, or the chosen event takes longer than expected. | Increase timeout deliberately; consider whether domcontentloaded is sufficient. |
| The API request times out in your app before the render error arrives | The caller, reverse proxy, or worker has a shorter outer deadline. | Raise the caller’s deadline above the intended render budget or handle the task asynchronously in your own system. |
| Fast response, but charts or dynamic content are missing | Capture ran at an early event, before late content was rendered. | Use an event that waits appropriately or add a modest delay. |
networkidle never completes |
The page maintains requests, such as polling or other persistent activity. | Use load or domcontentloaded as appropriate, then add a delay only if late content needs it. |
| Images or sections are missing farther down a long page | The site loads them only when scrolled into view. | Enable lazy_load=true; tune scroll_delay while watching the total render budget. |
| Address unreachable, refused connection, tunnel, or network error | Destination availability, URL, redirect, or network path problem. | Validate the public URL and reachability. A page timeout adjustment does not repair the connection. |
| TLS or SSL error | Destination certificate or handshake issue. | Correct the HTTPS/TLS configuration and verify the destination certificate chain. |
| 429 or quota-related response | Rate or account allowance exhausted. | Check usage and account limits; retry only when allowed or after the limit resets. |
| 503 or temporary service failure | Temporary renderer availability issue. | Retry later with capped attempts and backoff; do not loop indefinitely. |
request_aborted without a clear cause |
The vendor lists timeout, network issue, or manual cancellation. | Correlate response details with client and job-runner logs; check both target reachability and outer deadlines. |
10. Performance, reliability, and cost considerations
Longer render timeouts, extra delays, and scroll pauses all extend the time a capture occupies a request or worker. Use them only where the page behavior calls for them. For throughput-sensitive jobs, keep the wait condition and scrolling work as small as the required screenshot allows.
For reliability, distinguish deterministic configuration issues from transient service errors. A bad URL, persistent destination failure, TLS mismatch, or exhausted quota will not improve through blind retries. For temporary service failures, use a bounded retry policy with backoff; for a caller-side timeout, align its deadline with the render budget.
The dossier documents timeout defaults and parameter behavior, but does not provide pricing or benchmark data for ScreenshotAPI.net. Do not infer a per-capture cost or speed from the timeout settings; check the provider’s current account terms for billing details.
11. Or skip the browser setup
If maintaining remote browser-render settings is not the right fit, ScreenshotNeo provides a website screenshot API and MCP server. Its API makes a GET request to https://api.screenshotneo.com/v1/shot; see the ScreenshotNeo API documentation.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
- Cookie banners and consent prompts, newsletter popups, and chat widgets are removed before the shot; each cleanup step can be turned off.
- Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are never billed. The response identifies the page verdict and billing status in headers.
- An MCP server provides
take_screenshot,get_page_info, andcapture_pdftools for Claude, Cursor, and other MCP clients. - 1,000 screenshots per month are free with no card; paid plans start at $5 for 3,000 screenshots. Every feature is on every plan.
Sign up for ScreenshotNeo’s free 1,000 screenshots a month, with no card required.
12. FAQ
Is this the same timeout setting used by every Screenshot API service?
No. This article covers ScreenshotAPI.net’s /v3/screenshot endpoint and documented parameters. Other providers may have different endpoints, units, defaults, or limits.
Does a longer timeout make a blocked website accessible?
No. It gives a render more time. It does not fix destination reachability, a refused connection, TLS errors, quota limits, or service availability.
Should I always enable lazy loading?
No. Enable it when off-screen content is triggered by scrolling. It adds work and may consume more of the timeout budget on long pages.
Can I use networkidle for every dynamic page?
No. It waits for 500 ms without active requests. Pages with persistent network activity may not reach that state.
Where can I confirm the supported settings?
Use ScreenshotAPI.net’s render documentation, lazy-loading and delay guide, and error reference.


