ScreenshotNeo

BlogHow-to

Screenshotlayer Timeout Errors: How to Capture Slow-Loading Web Pages

Diagnose Screenshotlayer capture failures, use its documented delay option carefully, and switch to selector-based waits when a page needs more precise readiness checks.

By the ScreenshotNeo team4 October 202610 min read

Start by reading the complete HTTP response. A slow-looking capture can be caused by a bad URL, an access key problem, an exhausted allowance, or a page that needs more time to render. Screenshotlayer’s published specification describes error responses with a numeric code, a type, and an information message; it does not establish a timeout-specific error code or a current maximum capture duration. If the URL and account check out, try the documented delay parameter. If a fixed delay is not enough, use browser automation and wait for the page content you actually need.

1. Diagnose the response before changing timing

Do not infer the cause from the word “timeout” alone. First check whether your request reached Screenshotlayer and whether the response is an API error or an image. The published specification lists errors such as missing or invalid access keys, usage limit reached, invalid API function, missing resource, and invalid URL. It does not list a specific slow-page timeout code in the material reviewed. Check the Screenshotlayer API specification and confirm current behavior against the service’s live documentation or account dashboard.

  1. Confirm the requested page URL includes http:// or https://, and that the URL is encoded as a query parameter by your HTTP client.
  2. Check that the request uses the correct access_key, and review the account allowance if the response reports a usage limit.
  3. Read the entire response body and status and content-type headers. Do not save a JSON error payload with an image extension.
  4. If the response indicates a valid request but the captured page is missing content rendered after navigation, try a modest delay.

Inspect a response with cURL

curl -sS -D response-headers.txt -G "https://api.screenshotlayer.com/api/capture" \
  --data-urlencode "access_key=YOUR_ACCESS_KEY" \
  --data-urlencode "url=https://example.com" \
  --data-urlencode "delay=3" \
  -o response-body

cat response-headers.txt
file response-body

Use the HTTPS endpoint only if it is available for your account. The published specification describes HTTPS as available to paid customers; verify the current plan rules before relying on that detail. If the body is JSON, inspect its error.code, error.type, and error.info. If it is an image, open it and check whether the content you expected has rendered.

2. Use Screenshotlayer’s delay option carefully

Screenshotlayer documents delay as the number of seconds to wait before taking the screenshot. It can help when a page fills in after initial navigation, for example when client-side JavaScript renders content or an animation needs to finish. A delay only adds time before capture; it does not guarantee that a particular element loaded successfully.

A Screenshotlayer vendor blog describes a range of 1–10 seconds, but that range is not confirmed by the API specification reviewed here. Treat it as vendor-blog guidance and check the current service documentation and account limits before depending on a specific value. The specification also lists a ttl cache setting and a default of 2,592,000 seconds, but this is version-sensitive; check the live documentation before using it to reason about whether a capture is fresh.

Python: request a delayed capture and distinguish JSON errors from an image

import json
from pathlib import Path

import requests

endpoint = "https://api.screenshotlayer.com/api/capture"
params = {
    "access_key": "YOUR_ACCESS_KEY",
    "url": "https://example.com",
    "delay": 3,
}

response = requests.get(endpoint, params=params, timeout=90)
content_type = response.headers.get("content-type", "")

if "json" in content_type.lower():
    try:
        payload = response.json()
    except ValueError:
        payload = response.text
    print("HTTP status:", response.status_code)
    print("API response:", json.dumps(payload, indent=2) if isinstance(payload, dict) else payload)
    response.raise_for_status()
    raise SystemExit("The API returned JSON instead of an image.")

response.raise_for_status()
Path("capture.png").write_bytes(response.content)
print("Saved capture.png; content type:", content_type)

Install the dependency with python -m pip install requests. The client timeout limits how long your script waits for the HTTP response; it does not change Screenshotlayer’s own rendering limit.

Node.js: request a delayed capture and inspect the response

const params = new URLSearchParams({
  access_key: 'YOUR_ACCESS_KEY',
  url: 'https://example.com',
  delay: '3',
});

const response = await fetch(
  `https://api.screenshotlayer.com/api/capture?${params}`,
  { signal: AbortSignal.timeout(90000) },
);
const contentType = response.headers.get('content-type') || '';

if (contentType.toLowerCase().includes('json')) {
  console.error('HTTP status:', response.status);
  console.error('API response:', await response.text());
  process.exitCode = 1;
} else if (!response.ok) {
  console.error('HTTP status:', response.status);
  console.error(await response.text());
  process.exitCode = 1;
} else {
  const image = Buffer.from(await response.arrayBuffer());
  const { writeFile } = await import('node:fs/promises');
  await writeFile('capture.png', image);
  console.log('Saved capture.png; content type:', contentType);
}

This example uses the built-in fetch available in current Node.js releases. The 90-second client deadline is an example caller-side limit, not a claimed Screenshotlayer execution ceiling.

3. When a fixed delay is not enough: wait for page content

A fixed delay is a blunt readiness check. A page might render the required content quickly, take longer than the chosen delay, or never render it because an API request failed. With a browser you control, navigate using a lifecycle condition and then wait for a selector that represents the content required in the screenshot.

Playwright supports commit, domcontentloaded, load, and networkidle navigation conditions. Its documentation discourages treating networkidle as a general readiness signal and says fixed waitForTimeout() waits should be used only for debugging. Prefer a meaningful selector or application-specific condition. See the Playwright Page API documentation.

Runnable Node.js example using Playwright

Install Playwright and its Chromium browser:

npm init -y
npm install playwright
npx playwright install chromium

Save the following as capture.mjs. Change #main-content to a selector that appears when the content you need is ready.

import { chromium } from 'playwright';

const targetUrl = 'https://example.com';
const readySelector = '#main-content';
const browser = await chromium.launch({ headless: true });

try {
  const page = await browser.newPage({ viewport: { width: 1440, height: 900 } });
  const response = await page.goto(targetUrl, {
    waitUntil: 'domcontentloaded',
    timeout: 60000,
  });

  if (response && !response.ok()) {
    throw new Error(`Main document returned HTTP ${response.status()}`);
  }

  await page.locator(readySelector).waitFor({
    state: 'visible',
    timeout: 30000,
  });

  await page.screenshot({ path: 'capture.png', fullPage: true });
  console.log('Saved capture.png');
} finally {
  await browser.close();
}

domcontentloaded lets navigation finish once the initial document has been parsed; the selector wait then handles the later application render. If the site exposes a more precise ready marker, use that. A selector that is always present, such as body, will not prove that the page’s important content has loaded.

Condition What it means When it can help
commit The response arrived and document loading started. When you intend to wait separately for a specific element or state.
domcontentloaded The initial HTML document was parsed. When scripts or app content continue rendering after the document parses.
load The page load event fired after dependent resources loaded. When the page’s load event is a useful milestone for your target.
networkidle There were no network connections for at least 500 ms. Use cautiously; persistent polling and analytics can make it unsuitable, and Playwright discourages it as a default readiness signal.

Use a bounded timeout that matches your own job’s latency budget. Increasing it can prevent premature failure, but it also keeps the browser process and caller waiting longer. It cannot fix an unreachable page, a blocked request, or an element that never appears.

4. Or skip the browser setup

ScreenshotNeo is a website screenshot API and MCP server. One GET request returns a PNG, JPEG, WebP, or PDF. Its API accepts the parameter names used by other screenshot APIs, which can make migration easier. See the ScreenshotNeo API documentation for request options.

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}`);

ScreenshotNeo removes cookie banners, newsletter popups, and chat widgets before capture; each cleaning step can be turned off. Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed, and response headers identify the page verdict and billing status. Its MCP server gives AI agents tools to take screenshots, get page information, and capture PDFs. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 screenshots.

Create a free ScreenshotNeo account for 1,000 screenshots a month with no card.

5. Troubleshooting common failures

Symptom Likely cause What to do
JSON reports missing_access_key or invalid_access_key. The key is absent, mistyped, or not valid for the account. Check the account dashboard and ensure the key is URL-encoded by your client. Keep secret keys out of source control and public browser code.
JSON reports usage_limit_reached. The account reached its monthly request allowance. Check current account usage and plan limits before retrying. More delay or retries will not resolve a quota error.
JSON reports invalid_url. The URL is malformed, lacks its protocol, or was incorrectly encoded. Use the full URL including protocol and pass it as a query parameter through a URL-encoding client option.
The saved “image” contains JSON or text. The client saved an API error body without checking its content type. Inspect headers and body before writing the file; parse JSON errors and only save a successful image response.
The screenshot is valid but misses a chart, product list, or other late content. The page renders that content after the initial navigation event. Try a modest documented delay with Screenshotlayer. For content-specific control, use Playwright and wait for a selector or application state.
Playwright times out during goto(). The main document did not reach the selected lifecycle event before the navigation deadline, or the host was unreachable or slow. Choose a suitable waitUntil condition, set a deliberate navigation timeout, and inspect the target’s response and network behavior. Then wait separately for the needed content.
Playwright times out waiting for a selector. The selector is wrong, the content did not render, or it is not visible in the current page state. Confirm the selector in the rendered DOM, check whether the content is inside a frame, and wait for the actual state needed (attached, visible, or hidden).
Waiting for networkidle never finishes. The site keeps requests open or starts recurring requests such as polling. Use domcontentloaded or another appropriate navigation milestone, then wait for a meaningful selector or condition.
Intermittent failures disappear on retry. The failure may be transient, such as a temporary network or origin problem. Use bounded retries only for plausibly transient failures, with a delay between attempts. Do not retry invalid-key, invalid-URL, or quota errors. Screenshotlayer’s retry policy and an optimal retry count are not established by the sources reviewed.

6. Performance, reliability, and cost considerations

  • Wait for the content, not an arbitrary duration. A fixed delay can waste time on fast pages and still be too short on slow ones. A selector-based browser wait ties completion to the page state you care about.
  • Set caller and navigation deadlines deliberately. Your HTTP client timeout, browser navigation timeout, selector timeout, and any upstream capture limit are separate limits. Increasing one does not necessarily increase the others.
  • Keep retries bounded. Retry only likely transient failures and avoid repeating requests for configuration or allowance errors. Repeated requests may consume allowance; the Screenshotlayer specification lists a monthly usage-limit error.
  • Check caching before diagnosing stale output. Screenshotlayer’s specification includes ttl and force parameters. Their current behavior and limits should be verified in live documentation before use. A cached screenshot may not reflect a fresh render.
  • Compare operational cost, not only per-request price. Self-managed Playwright requires you to run and update a browser and handle browser processes, concurrency, and failures. A hosted API reduces that operational work but has provider-specific quotas, limits, and site compatibility. The sources reviewed do not provide a current price, latency benchmark, or reliability comparison for Screenshotlayer, Playwright hosting, and Cloudflare.

Cloudflare Browser Rendering is another hosted option to investigate: its API documents screenshots and a selector wait with a configurable timeout. That documentation establishes available controls, not that it is faster, more reliable, or cheaper for a particular site. See the Cloudflare Browser Rendering snapshot API.

7. FAQ

Does Screenshotlayer publish a specific timeout error code?

The specification reviewed describes several error codes but does not establish a timeout-specific code. Read the response payload and check current official documentation for current behavior.

Will adding a longer delay fix every slow page?

No. Delay can allow late rendering to finish, but it cannot fix a failed page request, blocked content, invalid credentials, or exhausted usage allowance.

Should I always wait for network idle?

No. Sites with persistent connections or recurring requests may never become idle, and Playwright discourages network idle as the default readiness signal. Prefer the selector or condition that means the needed content is ready.

Is a hosted browser rendering service automatically more reliable?

The cited documentation confirms that hosted browser capture and selector waits are available. It does not establish comparative reliability for your target page; check compatibility and limits with the pages and workload you need to capture.

Sources