ScreenshotNeo

BlogHow-to

How to Wait for JavaScript to Finish Before ApiFlash Captures a Page

ApiFlash waits for network idle by default. Learn when to use wait_for, wait_until, delay, and scroll_page to capture the rendered content you need.

By the ScreenshotNeo team4 October 20267 min read

ApiFlash already waits for network idle by default. For JavaScript-rendered content that appears late, use wait_for with a CSS selector for the content you need. Add a short delay only when residual work such as an animation needs extra time. There is no documented setting that guarantees every script and future page update has finished; configure a meaningful readiness condition, then inspect the capture.

This guide covers ApiFlash’s documented wait controls and their limits, with runnable cURL, Python, and Node.js examples. For API parameter details, see the ApiFlash Screenshot API documentation and its FAQ.

1. Choose the right readiness condition

“JavaScript finished” is not a universal browser state. Timers, analytics, polling, animations, and application updates can continue after the initial page load. Choose a condition that matches the content your screenshot needs:

Setting What it waits for Use it when
wait_until=dom_loaded The initial HTML document is loaded; it does not wait for stylesheets and images. You need the document early and can tolerate dependent resources still loading.
wait_until=page_loaded The page and dependent resources, such as stylesheets and images, have loaded. You need ordinary page resources loaded before capture.
wait_until=network_idle The page has loaded and network activity is idle. This is ApiFlash’s default. Start here for typical pages and keep it unless you have a reason to change it.
wait_for A matching CSS selector appears. If it does not appear within 15 seconds, the capture aborts with an error. A known element marks the content you need becoming available.
delay A fixed pause after the page is loaded, up to 10 seconds. Use a short extra pause for residual work, such as an animation.

The documented wait_until timeout defaults to 30 seconds and can be set from 1 to 30 seconds. If the criterion is not reached in time, ApiFlash captures what has loaded so far. This differs from wait_for: a selector that never appears causes an error after 15 seconds.

2. Wait for the element that matters

When the important content is inserted after initial navigation, target it directly. For example, if the application adds a result card with class rendered-result, set wait_for=.rendered-result. Choose a selector that appears only when the needed content is available. If a placeholder uses the same selector before its content is ready, selector presence alone may be too early: ApiFlash documents waiting for a matching element, not verifying that the element has stopped changing.

Use the default network-idle behavior along with the selector unless you have a page-specific reason to change the navigation condition. The complete request shape is:

https://api.apiflash.com/v1/urltoimage?access_key=YOUR_ACCESS_KEY&url=https%3A%2F%2Fexample.com&wait_until=network_idle&wait_for=.rendered-result

Replace the selector and target URL with values for your page. ApiFlash accepts parameters over GET query strings or POST form data and requires a valid access key. Encode query parameter values as needed. Keep the key private; do not commit it or publish a live request URL containing it.

3. Complete runnable examples

These examples save the response body as an image. Substitute your ApiFlash access key and target page. They use the documented endpoint and wait parameters.

cURL

curl -G 'https://api.apiflash.com/v1/urltoimage' \
  --data-urlencode 'access_key=YOUR_ACCESS_KEY' \
  --data-urlencode 'url=https://example.com' \
  --data-urlencode 'wait_until=network_idle' \
  --data-urlencode 'wait_for=.rendered-result' \
  -o screenshot.png

Python

import requests

params = {
    "access_key": "YOUR_ACCESS_KEY",
    "url": "https://example.com",
    "wait_until": "network_idle",
    "wait_for": ".rendered-result",
}
response = requests.get(
    "https://api.apiflash.com/v1/urltoimage",
    params=params,
    timeout=90,
)
response.raise_for_status()
with open("screenshot.png", "wb") as image_file:
    image_file.write(response.content)

Node.js

const params = new URLSearchParams({
  access_key: 'YOUR_ACCESS_KEY',
  url: 'https://example.com',
  wait_until: 'network_idle',
  wait_for: '.rendered-result',
});

const response = await fetch(
  `https://api.apiflash.com/v1/urltoimage?${params}`
);
if (!response.ok) {
  throw new Error(`ApiFlash returned HTTP ${response.status}`);
}
const image = Buffer.from(await response.arrayBuffer());
await import('node:fs/promises').then(fs => fs.writeFile('screenshot.png', image));

For a quick fixed pause after the page loads, add delay with a value from 0 to 10 seconds. For example, add delay=2 to the query or parameter object. Prefer a selector when you can identify the content; a fixed delay is less specific and can still be too short or longer than necessary.

4. Handle lazy-loaded content and changing pages

A selector wait can target a lazy-loaded element, but some pages load content only after scrolling. ApiFlash’s scroll_page option scrolls through the page and can trigger lazy loading or animations. Enable it when the content depends on scrolling, then inspect the resulting image because sites differ in how they load content.

  1. Identify the element or section absent from the initial capture.
  2. Check whether that content is inserted after navigation or only after scrolling.
  3. For content inserted after navigation, set wait_for to a meaningful selector.
  4. For content triggered by scrolling, use scroll_page and retain the relevant wait condition.
  5. Use a short delay only if a final animation or brief residual update remains.
  6. Check the screenshot and the API outcome; a wait setting does not prove that all application updates have stopped.

5. Troubleshoot missing, stale, or inconsistent captures

Symptom Likely cause What to do
Important content is missing, but the request returned an image. wait_until timed out and ApiFlash captured what had loaded so far, or the screenshot was taken before the late content appeared. Use a selector for the needed content, verify the selector against the live page, and inspect the capture outcome.
The request errors while waiting. The wait_for selector did not match an element within 15 seconds, perhaps because it is misspelled, conditional, or inside content the selector cannot address. Confirm the selector exists on the main page at capture time and is not dependent on another missing state.
The selector matches, but its content is still a placeholder or incomplete. Selector presence only confirms a match; it does not establish that the matched element’s contents have finished changing. Choose a selector tied to the completed state if the page exposes one. Otherwise use a short delay as a bounded fallback and verify the result.
Content appears only after scrolling. The page uses scroll-triggered lazy loading or animations. Try scroll_page and inspect whether it triggers the required section on that site.
The image looks old even though the wait parameters are correct. A matching request may have returned a cached screenshot. Set fresh=true to force a new capture.
The target shows a bot check or does not load. Some strict bot protections block capture access; extra waiting does not solve an access restriction. Check whether the target permits automated access. ApiFlash’s FAQ mentions a supplied proxy as a possible option for some cases; it does not promise to bypass every protection.
Fonts differ from the expected rendering. ApiFlash captures with Chrome on Linux, where system font availability may differ. Headers applied to all requests can also interfere with external font loading. Serve the page’s own fonts and check whether custom headers affect font requests.
A protected page cannot be captured correctly. The page requires authentication or session state. ApiFlash documents sending headers or cookies; its FAQ also mentions JavaScript injection to automate login. Treat API keys, cookies, and session credentials as secrets.

6. Reliability, performance, and cost considerations

Waiting longer can help capture late content, but it also increases the time before a response is ready. Use the narrowest reliable condition: a selector for specific content, the default network-idle condition for ordinary pages, and a short delay for residual work. Avoid treating the maximum delay as a general fix; no bounded pause guarantees that a page with continuing updates has reached a permanent final state.

Account for two different failure behaviors when building a caller: a wait_until timeout can still produce a partial screenshot, while a missing wait_for selector aborts the capture with an error. Check both the HTTP/API result and the image’s contents. Use fresh=true when freshness matters and cached output would be misleading. Protect access keys and session credentials, and avoid placing secrets in logs or public URLs.

The consulted ApiFlash documentation and FAQ do not provide a qualifying dated statistic for capture speed, reliability, or price, so this guide makes no numeric performance or cost claims. For a production workflow, measure response time and failure rates on your own target pages and account for the exact plan and billing terms shown by the provider.

7. Or skip the browser setup

ScreenshotNeo is a website screenshot API and MCP server. One GET request can return a screenshot or PDF, and its options include selector waits, delays, lazy-image loading, and more. See the ScreenshotNeo API docs for the request parameters.

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

ScreenshotNeo removes cookie banners, newsletter popups, and chat widgets before the shot. Bot checks, blank pages, failed loads, timeouts, and cache hits are never billed. Its MCP server lets AI agents use take_screenshot, get_page_info, and capture_pdf. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 screenshots.

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

Frequently asked questions

Does ApiFlash have a setting that waits for every JavaScript task to finish?

No universal “all JavaScript finished” switch is documented. Browser pages can keep running timers, analytics, polling, animations, and application updates. Configure a specific readiness condition for the content you need.

Should I use wait_for or delay?

Use wait_for when you can identify an element that represents the needed content. Use a short delay when you need a bounded pause for residual work such as an animation.

Can I wait for an element that loads lazily?

ApiFlash says wait_for can wait for a lazy-loaded element. If the page loads it only after scrolling, try scroll_page and verify the capture.