ScreenshotNeo

BlogHow-to

HTMLCSStoImage Screenshot Is Blank: Common Causes and Fixes

Fix blank HTMLCSStoImage screenshots by checking the request, waiting for delayed content, signaling readiness, and verifying rendering settings.

By the ScreenshotNeo team4 October 20267 min read

A blank or white HTMLCSStoImage screenshot often means capture started before slow HTML, JavaScript-driven content, or external CSS and images were ready. First verify the request input, then try ms_delay=500 and increase it if needed. For pages with variable load times, use render_when_ready and call ScreenshotReady() only after the content you need is ready. [HTML/CSS to Image troubleshooting guide]

1. Confirm the request renders the page you expect

The create-image API accepts either html or url as its input. A supplied url takes precedence over html, so sending both can make the renderer capture a different page than the HTML you are inspecting. For a webpage screenshot, provide a fully qualified, publicly reachable URL. CSS is optional. [API usage] [FAQ]

  • Check the final request payload, including query parameters and defaults.
  • Remove either html or url so the intended input is unambiguous.
  • For a URL capture, confirm it includes the scheme, such as https://, and is publicly accessible to the rendering service.
  • If the page depends on request headers, confirm the required headers are supported and allowed under the documented origin restrictions.

2. Wait for slow content and assets

HTML/CSS to Image waits for the page load event and then monitors additional network traffic. That heuristic can still capture too early when an application renders content later or external resources take longer than expected. [Troubleshooting guide]

Use a short fixed delay to diagnose timing

Start with ms_delay set to 500 milliseconds. If the needed content is still absent, increase it incrementally and compare the output. The parameter is a delay in milliseconds before image generation. A delay is a useful diagnostic, but it cannot adapt to pages whose load time changes from request to request. [Parameter reference]

{
  "url": "https://example.com/report",
  "ms_delay": 500
}

Replace the URL with the page being captured. If the page needs more time, increase ms_delay gradually rather than jumping to a large value without checking the result.

3. Use an explicit readiness signal for asynchronous pages

When a fixed delay remains unreliable, set render_when_ready to true. The renderer then waits for the page’s JavaScript to call ScreenshotReady(). Put that call after the data and assets that must appear in the image are ready. [Troubleshooting guide] [Parameter reference]

<script>
  async function renderReport() {
    const response = await fetch('/api/report');
    const report = await response.json();
    drawReport(report);

    // Call only after the content needed in the screenshot is ready.
    ScreenshotReady();
  }

  renderReport();
</script>

Enable the wait in the image request:

{
  "url": "https://example.com/report",
  "render_when_ready": true
}

If the page never calls ScreenshotReady(), the renderer has no explicit signal that it may proceed. Ensure the call runs on both successful and intentionally empty states that should still be captured. If your page controls the HTML sent to the renderer, define the readiness flow there; do not assume an unrelated third-party page will call this function.

4. Check wait limits, viewport, and media type

If timing changes do not fix the image, verify the render configuration against the intended page. The API documents max_wait_ms as a maximum wait before capture, with a range from 500 to 10000 milliseconds. It supports viewport width and height together and media_type values screen and print. These settings affect when and how content is rendered, so use values that match the page and output you expect. [Parameter reference]

Setting What to check
max_wait_ms Confirm it allows enough time for the renderer’s wait behavior; it is documented from 500 to 10000 ms.
Viewport width and height Set both to the dimensions needed for the layout. A responsive page may hide or rearrange content at a narrow viewport.
media_type Use screen for screen styling or print when you intend to capture print styles.
Custom headers For URL screenshots, check whether the page requires supported headers and whether origin restrictions permit them.

These are settings to inspect when troubleshooting; the documentation does not identify each as a typical cause of blank output.

5. Distinguish a blank page from a white-looking background

A screenshot that appears white may contain transparent pixels rather than missing page content. The FAQ recommends PNG with transparent_background: true when transparency is intended. If you provide CSS through the API’s css parameter, send it there; CSS placed only inside a <style> element in the HTML is not a substitute for the documented parameter in that case. Supported outputs listed in the FAQ include PNG, JPG, WebP, and PDF. [FAQ]

  • Open the result in a viewer that displays transparency distinctly, or inspect it against a colored background.
  • Check whether the page uses print-only or screen-only styles that hide the expected content.
  • Confirm that the requested output format matches how you intend to view or process the result.

6. A practical debugging sequence

  1. Make the input unambiguous: send html or a fully qualified public url, not both.
  2. Capture once with the intended viewport and media type.
  3. Add ms_delay: 500; increase the delay step by step if content is still missing.
  4. For content with variable readiness, enable render_when_ready and call ScreenshotReady() after rendering the needed content.
  5. Check max_wait_ms against its documented range and the page’s timing needs.
  6. Check whether the apparent white output is actually transparent, and verify the CSS parameter if using API-supplied CSS.
  7. For URL captures requiring authentication or special request behavior, inspect the documented custom-header support and origin restrictions.

7. Common errors and fixes

Symptom Likely explanation Fix
The output shows an older or unrelated page Both url and html were sent; url overrides html. Send only the input you mean to render and inspect the outgoing request.
The page shell appears, but charts or data are missing JavaScript or data requests finish after the renderer’s load and network monitoring heuristic. Try ms_delay from 500 ms, or use render_when_ready and call ScreenshotReady() after rendering.
The page is blank when using readiness mode The page may not call ScreenshotReady(), or it may call it before the desired content is ready. Verify the call runs, and move it after the content and assets required in the screenshot are ready.
The layout differs from the browser Viewport dimensions or screen/print media differ from the intended view. Set viewport width and height together and select the intended media_type.
The image looks white despite expected transparency The viewer may display transparent pixels on white. Check the image against a colored background; use PNG and the documented transparency setting if transparency is intended.
The screenshot omits protected content The URL may require authentication or request headers. Check supported custom headers and origin restrictions. For signed image URLs, keep the API key on the server.

8. Signed URLs and credential safety

If you use a signed image URL, generate its HMAC SHA256 token on your server using the API key as the secret. Do not put the API key in client-side code. Treat a completed signed URL as a capability: anyone who obtains it can request the image it authorizes. [Signed URL guide]

9. Performance, reliability, and cost considerations

  • Performance: A fixed delay adds that wait to each capture. Keep it close to the time your content needs. For pages with variable load times, an explicit readiness signal avoids choosing one delay for every case.
  • Reliability: Signal readiness only after the data and visual assets that matter are ready. A readiness callback that fires too early produces an incomplete image; one that never fires prevents the intended completion path.
  • External resources: Slow CSS, images, scripts, or data requests can arrive after the initial page load. Check whether the needed resources are available to the rendering service.
  • Cost: The cited documentation does not provide enough information here to state a price or estimate the cost of a given render. Check the provider’s current pricing and account terms before estimating production spend.

Or skip the browser setup

ScreenshotNeo is a website screenshot API and MCP server from Yorker Media. It takes a URL in one GET request and returns PNG, JPEG, WebP, or PDF. Its clean-shot options accept cookie and consent banners like a visitor and remove 60+ known consent platforms, newsletter popups, and chat widgets; each step can be turned off. Only clean shots are billed: bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, with the outcome reported in X-Page-Verdict and X-Billed headers. An MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. The free plan includes 1,000 shots per month with no card; paid plans start at $5 for 3,000 shots. Every feature is on every plan. [ScreenshotNeo documentation]

cURL:

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

Python:

import requests

r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={"access_key": "YOUR_API_KEY", "url": "https://example.com"},
    timeout=90,
)
open("shot.webp", "wb").write(r.content)

Node.js:

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://example.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`ScreenshotNeo returned ${res.status}`);
await import('node:fs/promises').then(fs => fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer())));

Keep the API key in server-side code or another secret store. See the ScreenshotNeo API documentation and product details.

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

FAQ

Should I always use a fixed delay?

No. A fixed delay is a simple first diagnostic. If page readiness varies, an explicit signal is more reliable because the page determines when the needed content has rendered.

Can I send both HTML and a URL as a fallback?

The documented behavior is that a supplied URL overrides HTML. Choose one input for each request so the rendered source is clear.

Does a white image always mean the page failed to render?

No. If transparency is enabled, a viewer may show transparent pixels as white. Check the output against a colored background.

Can I put the API key in browser JavaScript to create a signed URL?

No. Keep signing and the API key server-side; a signed URL itself should also be handled as a link that grants access to its image.