ScreenshotAPI Not Loading JavaScript Content in Screenshots: Fixes
Fix missing JavaScript content in ScreenshotAPI screenshots by checking blocked scripts and requests, choosing the right readiness signal, and tuning lazy loading and timeouts.
If a ScreenshotAPI screenshot is missing content that appears after a page loads, check three things first: JavaScript and the page’s data requests must be allowed, capture must wait for the content to be ready, and lazy-loaded content may need scrolling. A page can run its scripts successfully and still be captured before those scripts finish rendering the visible interface.
The steps below refer specifically to ScreenshotAPI.net. The target URL, request, account, and API version were not supplied, so these are diagnostic steps rather than a diagnosis of a particular capture. Confirm each option against the API version and account you use.
1. Check whether JavaScript or data requests are blocked
Inspect the actual request parameters or payload, including options assembled in shared configuration. ScreenshotAPI.net documents these blocking options as false by default:
| Option | Effect | What to check |
|---|---|---|
block_js |
Disables JavaScript when true. | Remove an explicit true when the page needs client-side rendering. |
block_xhr |
Blocks XHR/AJAX requests. | Keep it false if the page fetches data through XHR. |
block_fetch |
Blocks Fetch API requests. | Keep it false if the page fetches data through fetch(). |
A JavaScript application may load its shell but show empty charts, tables, or cards if its API calls are blocked. Other resource-blocking settings can also matter when the interface depends on those resources. See ScreenshotAPI.net’s API documentation for the options applicable to your request.
2. Wait for the page state that corresponds to the content
A browser lifecycle event is not the same as application readiness. Choose a wait based on what the page does:
| Wait strategy | Waits for | Useful when | Limitation |
|---|---|---|---|
domcontentloaded |
The initial HTML document has been parsed. | You need an early milestone and the content is already in the document. | It does not wait for images, styles, external resources, or later application rendering. |
load |
The document’s load event. | The page’s important resources finish around the normal load event. | Application data or delayed rendering can still arrive later. |
networkidle |
A period of network quiet, as defined by the service. | Dynamic pages use API or AJAX requests that settle after load. | Long-running connections may keep a page from becoming idle; network quiet alone does not prove a specific component is visible. |
wait_for_selector |
The chosen DOM element exists. | A known chart, dashboard panel, or result element marks readiness. | Confirm this option is available for your API version and account. An element can exist before its data is complete. |
delay |
A fixed elapsed time after page load. | A late script, animation, or API response needs a small additional interval. | It is approximate: too short can still miss content, and too long adds render time. |
ScreenshotAPI.net documents wait_for_event values including load, domcontentloaded, and networkidle. Its feature page also describes combining a selector wait, network-idle wait, and delay; verify exact support for your version before relying on the selector parameter.
3. Add a measured delay only if needed
The documented delay is in milliseconds and waits after page load before capture. The listed default is zero. Start with a modest value, inspect the result, and increase it only if the relevant content is still arriving late. A fixed delay is useful for predictable short waits, but a readiness signal tied to the content is usually easier to reason about.
As ScreenshotAPI.net’s Lazy Loading & Delay documentation explains, “This parameter defines a waiting period (in milliseconds) before the screenshot or render is captured after the page has been loaded in the browser.” The docs include 500 ms and 2,000 ms examples; those are configuration examples, not guarantees that a given site will be ready in that time.
4. Use lazy-load scrolling for below-the-fold content
Lazy loading is a separate problem from delayed JavaScript data. If images or sections load only when scrolled into view, enable lazy_load=true so the service scrolls down the page to trigger viewport-dependent content. The documented scroll_delay controls the pause between scroll steps; its listed default is 500 ms, with examples from 100 to 1,000 ms.
Long pages and large scroll delays can consume the available timeout. Reduce the per-step delay if it is more than the page needs, and remember that scrolling does not guarantee that an unrelated API request has finished.
5. Set a timeout that fits the page
The documented timeout is the maximum wait for page loading before the request is aborted. The reference lists 100,000 ms as the default. A low custom timeout can cut off a heavy page, while a high timeout can tie up a request longer than necessary. Treat the documented default as a service reference, not a promise for every plan or API version. Check whether lazy-load scrolling, selector waits, or added delay fit within the timeout you configure.
6. A practical diagnostic sequence
- Capture the same target URL again with the options you believe are being sent. Verify the final query or request payload rather than only the calling code.
- Ensure
block_js,block_xhr, andblock_fetchare not enabled if the page needs scripts or API data. - Choose a
wait_for_eventmilestone that does not capture too early. For an API-driven page, try the documented network-idle option if its requests settle. - If the page has a clear readiness element and your version supports it, wait for that selector.
- Add a small
delayonly when observation shows the content consistently appears after the chosen signal. - Enable lazy-load scrolling for content activated by entering the viewport; tune
scroll_delayfor page length and timeout. - Inspect the resulting image and the service response. Confirm the target URL and intended options reached the render endpoint, which requires a target URL and API token.
Changing one setting at a time makes it easier to identify which condition was responsible. The available sources do not establish the cause of any specific blank output or diagnose bot protection.
7. Runnable request examples
The examples show the general shape of a ScreenshotAPI.net render request. Use the endpoint, authentication format, and parameter encoding documented for your account and API version; do not assume another similarly named service accepts the same options. Replace placeholders with your own target and credentials.
cURL
curl -G "YOUR_SCREENSHOTAPI_RENDER_ENDPOINT" \
--data-urlencode "url=https://example.com" \
--data-urlencode "block_js=false" \
--data-urlencode "block_xhr=false" \
--data-urlencode "block_fetch=false" \
--data-urlencode "wait_for_event=networkidle" \
--data-urlencode "delay=500" \
--data-urlencode "timeout=100000" \
--data-urlencode "YOUR_DOCUMENTED_TOKEN_PARAMETER=YOUR_API_TOKEN" \
-o screenshot.png
Only include options supported by your version. If networkidle is unsuitable for a page with persistent connections, try a different documented event and a content-specific readiness option where available.
Python
import requests
endpoint = "YOUR_SCREENSHOTAPI_RENDER_ENDPOINT"
params = {
"url": "https://example.com",
"block_js": "false",
"block_xhr": "false",
"block_fetch": "false",
"wait_for_event": "networkidle",
"delay": 500,
"timeout": 100000,
"YOUR_DOCUMENTED_TOKEN_PARAMETER": "YOUR_API_TOKEN",
}
response = requests.get(endpoint, params=params, timeout=110)
response.raise_for_status()
with open("screenshot.png", "wb") as image_file:
image_file.write(response.content)
The client timeout is slightly longer than the example render timeout so the client can receive the service response. Adjust both to the documented limits and expected behavior of your service and network.
Node.js
const endpoint = "YOUR_SCREENSHOTAPI_RENDER_ENDPOINT";
const params = new URLSearchParams({
url: "https://example.com",
block_js: "false",
block_xhr: "false",
block_fetch: "false",
wait_for_event: "networkidle",
delay: "500",
timeout: "100000",
YOUR_DOCUMENTED_TOKEN_PARAMETER: "YOUR_API_TOKEN",
});
const response = await fetch(`${endpoint}?${params}`);
if (!response.ok) {
throw new Error(`Screenshot request failed: HTTP ${response.status}`);
}
const image = Buffer.from(await response.arrayBuffer());
await import("node:fs/promises").then(({ writeFile }) =>
writeFile("screenshot.png", image)
);
For a selector wait, add the documented selector parameter only after verifying its name and availability for your API version. Avoid putting secret tokens in URLs that may be logged; use the authentication method the service documents if it supports a header.
Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server for developers. One GET request with a URL returns a PNG, JPEG, WebP, or PDF. The equivalent request is:
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 request options. ScreenshotNeo removes cookie banners, newsletter popups, and chat widgets before capture; bot checks, blank pages, and failed loads are never billed. Its MCP server lets AI agents take screenshots. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000.
Sign up free for 1,000 screenshots a month, with no card required.
Troubleshooting common symptoms
| Symptom | Likely cause | What to try |
|---|---|---|
| Empty app shell or missing text | JavaScript was disabled or capture happened before rendering. | Check block_js; choose a later event or wait for a readiness element if supported. |
| Layout appears, but charts or data are empty | XHR or Fetch requests are blocked, still pending, or the app has not rendered their results. | Check block_xhr and block_fetch; wait for the relevant content or a suitable network state. |
| Some images or lower sections are missing | They load only near the viewport. | Use lazy_load=true and tune scroll_delay; allow enough timeout for the page length. |
| Intermittent incomplete captures | A fixed delay is shorter than variable render time, or the chosen event is too early. | Prefer a supported selector tied to the desired content; otherwise adjust the event or measured delay. |
| Request times out | The page is slow, the configured timeout is too short, or long lazy-load scrolling consumes the budget. | Check the page’s actual readiness needs, reduce unnecessary scroll pauses, and tune timeout within service limits. |
| Options seem to have no effect | Parameters may be misspelled, encoded incorrectly, unsupported in that version, or not present in the final request. | Inspect the outgoing request and compare option names with the official reference for your account/API version. |
Performance, reliability, and cost considerations
- Wait only for what matters. A lifecycle event is usually cheaper than a long arbitrary delay; a selector can be more targeted when available and reliable.
- Keep delays measured. Longer waits add latency to each render and do not guarantee readiness if the page is blocked or errors.
- Use lazy scrolling selectively. It can make long-page captures substantially slower because each scroll step may pause. Use it when content is viewport-triggered.
- Allow for variability. API response times and page behavior can vary. A readiness condition for the actual content is generally more robust than assuming one fixed wait fits every capture.
- Do not treat defaults as guarantees. Documented values such as a 500 ms scroll pause or 100,000 ms timeout are service settings, not independent performance benchmarks or promises across accounts.
FAQ
Does enabling JavaScript guarantee the page will be complete?
No. Scripts can run while data requests or later UI rendering are still pending. Wait for a suitable page state or content readiness signal.
Should I always use network idle?
No. It can help when API requests settle, but persistent network activity can make it unsuitable, and network quiet does not prove a specific component is ready.
Does lazy loading fix missing API data?
Not by itself. Lazy-load scrolling triggers content that depends on entering the viewport; API-driven content needs its requests allowed and enough time to render.
Is a longer delay always more reliable?
No. It increases render time and can still capture an incomplete page if the underlying request fails or takes longer than expected.


