ScreenshotNeo

BlogHow-to

How to Fix ApiFlash Request Timeout Errors on Slow Websites

Separate ApiFlash page-render waits from client-side timeouts, then choose the right wait condition and fix the cause without guessing.

By the ScreenshotNeo team4 October 20269 min read

ApiFlash request timeouts can come from two different places: ApiFlash waiting for the target page to reach a load condition, or your own HTTP client, proxy, or gateway ending the request before ApiFlash responds. First record whether you received an HTTP status and response body. If you did, use that error to diagnose the request; if you received no response, inspect the caller-side deadline. For a slow render, choose the page-ready condition that matches what the screenshot needs and set wait_until_timeout within ApiFlash’s documented 1–30 second range. ApiFlash captures whatever has loaded when that wait expires, so a partial image can indicate a readiness issue rather than an HTTP request failure.

1. Identify which timeout you have

Do not assume a slow website is the cause just because the caller reports a timeout. An ApiFlash page-load wait is an option sent to its API. The timeout configured in your HTTP library, proxy, load balancer, or gateway is a separate deadline. The reviewed ApiFlash documentation does not specify one universal caller-side timeout.

  1. Record whether your client received an HTTP response. If yes, save the status code and response body.
  2. If there was no response, record the client exception and the configured timeout for the HTTP call, plus any proxy or gateway deadline.
  3. Redact access keys and cookies before sharing logs. Keep the target URL and timestamp for troubleshooting.

ApiFlash’s wait_until_timeout does not promise that the page will be complete after its limit. Its documentation says the screenshot is captured with whatever has loaded so far when the criterion is not met. Inspect the returned image: if it is partial, adjust the page readiness strategy; if the client got no response, investigate its deadline and the network path.

2. Choose an appropriate page-ready condition

ApiFlash documents three wait_until choices. The default is network_idle, and wait_until_timeout defaults to 30 seconds, with a documented range of 1 to 30 seconds. The timeout is a cap on waiting for the selected criterion, not a promise that the target will be fully rendered by then. See the ApiFlash parameter reference.

Criterion What it waits for Use when
dom_loaded The initial HTML document has loaded. The initial markup is enough, or the page continues making network requests.
page_loaded The page and its dependent resources have loaded. Stylesheets, images, or other dependent assets matter to the capture.
network_idle The page is loaded and the network is idle. A quiet network is a useful signal that content is ready.

A page with polling, streaming, analytics, or other ongoing requests may not become network-idle at a useful point. In that case, test dom_loaded or page_loaded and compare the resulting screenshot. This is a diagnostic choice, not a guarantee for every site.

3. Adjust ApiFlash waits for the content you need

Use wait_until_timeout for the selected load condition

Set the limit between 1 and 30 seconds. The documented default is 30 seconds. If it expires, ApiFlash proceeds with the content loaded so far. Raising the value within that range gives the criterion more time; it cannot exceed the documented cap.

Use wait_for when a particular element matters

If the screenshot needs a specific late-rendering component, pass its CSS selector with wait_for. ApiFlash documents that capture aborts with an error if the selector has not appeared after 15 seconds. Confirm the selector matches the page and is not hidden behind a login or consent flow.

Use delay only for a short settling pause

delay adds a pause after page load and supports up to 10 seconds. It can help with a brief animation or delayed visual update, but it does not identify whether the needed content has arrived. ApiFlash recommends wait_for or an appropriate wait_until condition where they fit; see its FAQ.

4. Make a diagnostic request

ApiFlash accepts screenshot parameters in the query string. The following cURL example requests a capture with a bounded page wait. Replace the placeholder key and target URL; keep the key out of source control and logs.

curl -G "https://api.apiflash.com/v1/urltoimage" \
  --data-urlencode "access_key=YOUR_API_KEY" \
  --data-urlencode "url=https://example.com" \
  --data-urlencode "wait_until=dom_loaded" \
  --data-urlencode "wait_until_timeout=20" \
  --output screenshot.png

To wait for a specific element instead, replace or supplement the readiness settings with the documented selector parameter. Check the exact parameter spelling and supported options in the official documentation.

Python example using Requests:

import requests

params = {
    "access_key": "YOUR_API_KEY",
    "url": "https://example.com",
    "wait_until": "dom_loaded",
    "wait_until_timeout": 20,
}

response = requests.get(
    "https://api.apiflash.com/v1/urltoimage",
    params=params,
    timeout=60,  # Caller-side HTTP deadline; choose for your application.
)

if not response.ok:
    raise RuntimeError(f"ApiFlash HTTP {response.status_code}: {response.text}")

with open("screenshot.png", "wb") as image_file:
    image_file.write(response.content)

The 60-second Requests timeout above is an application example, not an ApiFlash requirement or a universal recommended value. Set the caller deadline based on observed end-to-end duration and the limits of any proxy or gateway in your path.

Node.js example using built-in fetch and an abort deadline:

const params = new URLSearchParams({
  access_key: 'YOUR_API_KEY',
  url: 'https://example.com',
  wait_until: 'dom_loaded',
  wait_until_timeout: '20',
});

const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), 60_000);

try {
  const response = await fetch(
    `https://api.apiflash.com/v1/urltoimage?${params}`,
    { signal: controller.signal },
  );

  if (!response.ok) {
    const body = await response.text();
    throw new Error(`ApiFlash HTTP ${response.status}: ${body}`);
  }

  const image = Buffer.from(await response.arrayBuffer());
  await import('node:fs/promises').then(fs => fs.writeFile('screenshot.png', image));
} finally {
  clearTimeout(timer);
}

As in the Python example, the client deadline is an illustrative setting. If it fires before a response, the code cannot tell whether ApiFlash would eventually have returned a capture; compare the deadline with observed duration and check intermediate infrastructure.

5. Read ApiFlash error responses before changing waits

A returned status often points to a different issue than a slow render. ApiFlash documents these status meanings:

Status Documented meaning What to check
400 Invalid parameters or an uncapturable URL; the response includes an error message. Read the body, validate parameter names and values, and confirm the URL can be captured.
401 Invalid or revoked access key. Check the key configured in the running environment and replace it if revoked.
402 Monthly quota exhausted. Check account usage and quota reset information.
403 A requested feature is unsupported by the plan. Identify the unsupported option or plan restriction.
429 Too many requests. Reduce concurrency or request rate and retry with exponential backoff.
500 Internal capture failure. Preserve the timestamp and redacted request details; contact ApiFlash support if it persists.

Successful responses can include X-Quota-Limit, X-Quota-Remaining, and X-Quota-Reset. ApiFlash also documents a quota endpoint; consult the API reference for its current request format.

6. Check target access and protection

Not every capture failure is caused by slowness. ApiFlash notes that bot-protection systems, including Cloudflare, may block captures. A page that requires sign-in also needs appropriate authentication. Its FAQ discusses authenticating normally and supplying session cookie values. Use only credentials you are authorized to use, protect cookies as secrets, and verify that authentication is actually required before adding it.

If the target blocks automated access, increasing the page wait may not solve the problem. Inspect the response or image for a challenge or login page, then check the site’s access requirements and the capture service’s supported authentication options.

7. Handle rate limits and repeated captures

ApiFlash publishes a rate limit of 20 requests per second with a burst size of 400 (publication year not stated). Above the rate, processing is delayed; requests beyond the burst receive 429. Its documentation also says identical failed captures are limited to five per hour. These limits can affect retries during an incident.

  • On 429, reduce request rate and use exponential backoff, as ApiFlash recommends in its terms.
  • Avoid tight retry loops for a URL that is consistently failing.
  • For recurring public requests, consider the configurable screenshot cache. Request a fresh capture only when needed; the FAQ documents fresh=true.

Caching can reduce repeated work and quota or rate pressure. It does not make one slow origin render faster. ApiFlash’s Nginx guide also describes proxy caching and rate limiting for deployments that route screenshot requests through Nginx.

8. Troubleshooting checklist

  • HTTP 400: Read the response body and correct invalid parameters or the URL.
  • HTTP 401: Verify the access key is valid and not revoked.
  • HTTP 402 or 403: Check quota or whether the requested feature is available on the plan.
  • HTTP 429: Reduce rate and add exponential backoff; do not retry immediately in a loop.
  • HTTP 500: Retry cautiously. If it persists, send support the timestamp, target URL, redacted parameters, and status/body via ApiFlash support.
  • Partial screenshot after a long wait: The selected load criterion may have timed out and capture proceeded with loaded content. Try a different documented criterion or wait for the specific selector.
  • wait_for fails: Confirm the CSS selector exists in the rendered page and appears within 15 seconds; check login, consent, or bot challenges.
  • Caller reports timeout with no HTTP status: Inspect the client library timeout and proxy, load balancer, or gateway deadlines. There is no single client timeout value prescribed by the reviewed ApiFlash docs.
  • Target never becomes idle: Test dom_loaded or page_loaded if network quiet is not a suitable readiness signal.

9. Performance, reliability, and cost considerations

Longer waits can give slow pages more time to reach a chosen condition, but they also keep a synchronous caller waiting longer. Choose the earliest condition that still includes the content your use case needs. Use a selector wait for one essential late element instead of adding a broad delay when possible. A delay is capped at 10 seconds; wait_for has a documented 15-second failure behavior; wait_until_timeout is capped at 30 seconds.

For production systems, set a caller deadline that accounts for the actual capture duration and the deadlines imposed by infrastructure. Handle non-2xx responses explicitly, avoid uncontrolled retries, back off on 429, and consider cache reuse for repeated URLs. Track response status, duration, and quota headers without recording secrets. ApiFlash says its uptime statistics are not publicly displayed, so do not infer a service availability figure from the timeout behavior.

Quota exhaustion produces HTTP 402 according to ApiFlash’s documented mapping. Check the quota endpoint and response headers before increasing retries: retries cannot resolve exhausted monthly quota. Plan and price details change over time; consult the current ApiFlash site if cost is part of the decision.

Or skip the browser setup

ScreenshotNeo is a website screenshot API and MCP server for developers. One GET request can return a PNG, JPEG, WebP, or PDF. Cookie banners are accepted like a visitor and removed before the shot, along with 60+ known consent platforms, newsletter popups, and chat widgets; each cleanup step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits are never billed, and response headers say which result occurred. An MCP server provides take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients.

cURL:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

Python:

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)

Node.js:

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

See the ScreenshotNeo API documentation for parameters and setup. It supports page and element capture, full-page shots with lazy images loaded, device and viewport settings, wait conditions, custom headers and cookies, caching, async jobs, bulk capture, signed image links, and PDF options. One-call capture avoids running your own browser setup. Pricing is 1,000 screenshots a month free with no card; paid plans start at $5 for 3,000, and every feature is on every plan.

Sign up for ScreenshotNeo and get 1,000 screenshots a month free, with no card required.

FAQ

Does a timed-out ApiFlash page wait always mean the API request failed?

No. ApiFlash documents that capture proceeds with whatever has loaded when the selected wait criterion expires. Check whether your client received an HTTP response and inspect the image.

Can I set wait_until_timeout above 30 seconds?

The documented range ends at 30 seconds. The caller’s own HTTP deadline is separate and must be configured in your client and infrastructure.

Should I always use network_idle?

No. It is the default, but pages with continuing network activity may call for dom_loaded, page_loaded, or a selector-specific wait, depending on what the image needs to show.

What details should I send support?

Include the timestamp, target URL, HTTP status and body if present, client-side exception if no response arrived, and redacted request parameters. Never send an unredacted access key or session cookie.