ScreenshotNeo

BlogHow-to

CaptureKit Screenshots Fail on Cloudflare-Protected Websites: Fixes

A Cloudflare challenge in a CaptureKit screenshot may mean the browser captured an interstitial, not the page. Diagnose the response, rendering, and authorization path.

By the ScreenshotNeo team4 October 20268 min read

If a CaptureKit screenshot shows a Cloudflare challenge, the capture may have succeeded while the destination page did not load. First distinguish that from an API error, a blank or partially rendered page, and a challenge loop. Then check the CaptureKit request and logs. Cloudflare says automated browsers are not supported for solving production challenges, so a proxy, retry, or browser setting cannot be promised as a reliable way to pass one.

1. Identify what the screenshot contains

Start with the returned image or PDF and the HTTP response from CaptureKit. The screenshot is evidence of what its browser rendered; it does not by itself prove that the target page loaded successfully.

What you see Likely category Next step
A Cloudflare interstitial, verification page, or repeated challenge The browser rendered a challenge instead of the destination. Check the target site in a normal browser and review the challenge diagnostics below. If you do not control the zone, do not treat automation as a dependable way to solve its production challenge.
Blank or partially rendered page The page may not have finished rendering, or its resources may not have loaded. Check CaptureKit’s documented wait and rendering options and inspect request logs.
An API error instead of an image The screenshot request itself may have failed. Check the HTTP status, API key, request parameters, account state, and current CaptureKit API documentation.
The intended page The capture appears to have reached the content. Check that the expected page area and content are present before relying on the result.

Cloudflare challenges can come from different products and rules that use browser signals. A challenge screenshot alone does not identify which rule triggered it. Cloudflare’s explanation of how challenges work describes the challenge system; it does not provide a universal fix for every protected site.

2. Check the CaptureKit request before changing browser settings

  1. Confirm the target URL is the URL you intend to capture, including its scheme, hostname, path, and any required query parameters.
  2. Confirm the API key is present in the documented location. CaptureKit’s capture endpoint uses an API key; follow the current CaptureKit Capture documentation for the exact request format.
  3. Check the response status and body. Determine whether CaptureKit returned an image/PDF or an API error. CaptureKit documents general API error classes including 401, 402, 403, 404, 413, 429, and 500; use its current docs and response for the meaning of a particular failure.
  4. Review the request logs, if available, for the target URL, selected format and device options, proxy configuration, and any reported failure.
  5. Only after the request itself is understood, adjust documented rendering waits if the screenshot is incomplete. CaptureKit documents wait-related controls in its API reference, but the cited sources do not establish that a particular wait setting will solve a Cloudflare challenge.

CaptureKit is an HTTP screenshot API. Its documentation lists device emulation and a proxy parameter, but does not promise either will grant access through Cloudflare protection. Use the CaptureKit introduction and product overview alongside the endpoint reference for the options supported by your integration.

3. If the screenshot is incomplete, check rendering waits

A screenshot taken before the page has finished rendering can be blank or incomplete. Check CaptureKit’s documented wait controls and choose the condition that matches the page, such as waiting for a selector, a delay, or network idle if the endpoint supports it. These controls can help with ordinary page rendering; they should not be presented as a way to defeat a production challenge.

  • For a page with a known content container, wait for that selector and verify it belongs to the actual page rather than an interstitial.
  • For a page that loads asynchronously, allow the documented rendering wait to complete before capture.
  • For a page whose network never becomes idle because it maintains long-lived requests, a network-idle condition may be unsuitable; use a more specific documented condition when available.

Do not keep increasing delays without checking the resulting screenshot. A longer wait can consume more time while leaving a challenge page unchanged.

4. Diagnose a Cloudflare challenge loop

If the target displays a challenge repeatedly, check whether its scripts and network requests can load and whether JavaScript is enabled in the browser environment. Cloudflare lists blocked challenge scripts, unsupported browsers, disabled JavaScript, network conditions, and bot-like signals among possible causes of challenge-solving issues. Read its challenge troubleshooting guidance for the site’s current diagnostics.

Cloudflare says most challenges are quick and typically take only a few seconds. That is general guidance, not a CaptureKit timing guarantee or a promise that an automated capture will pass. Cloudflare’s supported browsers guidance says automated browsers and frameworks such as Selenium, Puppeteer, Playwright, and Cypress are not supported for solving production challenges. Do not rely on stealth flags, proxy rotation, or repeated retries as a fix. For automated Turnstile testing, Cloudflare points developers to test keys rather than production challenge solving.

5. Escalate with useful diagnostics

  1. Reproduce the issue and preserve a HAR (HTTP Archive) recording of the browser network activity.
  2. Export the browser console log from the reproduction.
  3. Record the CaptureKit response status and the request details needed to identify the capture, while keeping API keys and other secrets private.
  4. If Cloudflare shows an error code or Ray ID, provide it to the site administrator along with the time of the attempt and your diagnostics.

Cloudflare recommends checking network and browser conditions and collecting a HAR and console logs when escalating. See its challenge-solving issue guide. A HAR may contain sensitive headers, cookies, or query values; share it only through an appropriate private channel.

6. If you control the protected Cloudflare zone

For an authorized workflow on a zone you control, Cloudflare documents a Browser Run screenshot endpoint that renders a webpage, including its HTML and JavaScript, before taking a screenshot. Cloudflare also documents configuring a WAF skip rule so Browser Run is allowed without the site’s bot-protection configuration interfering. This route requires control and authorization for the target zone; it is not a fix for arbitrary third-party websites.

See Cloudflare’s Browser Run screenshot endpoint and Browser Run FAQ for setup and account or Workers Binding details.

7. Common errors and fixes

Symptom Possible cause What to do
401 from the screenshot API Missing or invalid API key, or incorrect authentication format. Check the key and the endpoint’s current authentication instructions. Never put a secret key in a public page or commit it to source control.
402, 403, 404, 413, 429, or 500 Account, permission, request, rate, or server issue; the exact meaning depends on the current API behavior. Read the response body and CaptureKit’s current error documentation. Correct the request or account condition indicated there, and preserve the request details for support.
Image shows a Cloudflare page The capture rendered a challenge interstitial. Confirm that the target is protected and that the API request succeeded. For a site you control, use an authorized owner workflow; otherwise ask the site administrator for an approved access path.
Image is blank or cuts off content Rendering may be incomplete, or the selected viewport or wait condition may not suit the page. Inspect the result and logs, then adjust documented rendering or device settings. Do not assume that a longer wait will pass a challenge.
Retry returns the same challenge The same protection decision may continue to apply. Avoid retry loops. Investigate the challenge through the authorized site owner or use a permitted test configuration.
Proxy setting does not change the result Proxy support is not a documented Cloudflare challenge bypass guarantee. Use proxy settings only for supported, authorized network needs. Do not infer that another proxy will solve a production challenge.

8. Reliability, performance, and cost considerations

Treat a screenshot as usable only after checking what it contains. If the workflow depends on a particular page element, validate that element or an equivalent content signal before storing or acting on the image. Distinguish a captured challenge from an API failure in monitoring so that retries do not hide the real issue.

Wait settings affect capture latency, and aggressive retries add requests without guaranteeing progress. Cloudflare’s general statement that most challenges take a few seconds is not a CaptureKit service-level commitment. The research sources do not establish CaptureKit pricing, challenge pass rates, or a benchmark for these cases; check CaptureKit’s current account and API documentation for applicable costs and limits.

Or skip the browser setup

If your task is simply to capture pages that are accessible to your chosen screenshot service, ScreenshotNeo is a website screenshot API and MCP server. Its API accepts one GET request with a URL and returns a PNG, JPEG, WebP, or PDF. See the ScreenshotNeo API documentation for options and setup.

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,
)
r.raise_for_status()
with open("shot.webp", "wb") as image:
    image.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}`);
if (!res.ok) throw new Error(`ScreenshotNeo returned HTTP ${res.status}`);
const image = Buffer.from(await res.arrayBuffer());
await import('node:fs/promises').then(fs => fs.writeFile('shot.webp', image));

ScreenshotNeo accepts cookie/consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and responses identify the page verdict and billing status in headers. Its MCP server provides take_screenshot, get_page_info, and capture_pdf for AI agents using Claude, Cursor, or another MCP client.

ScreenshotNeo cannot be represented as a way to bypass Cloudflare production challenges. As with any capture, check the returned result and use only authorized access paths. The free plan includes 1,000 shots per month with no card; paid plans start at $5 for 3,000 shots. Sign up for ScreenshotNeo and get 1,000 free screenshots a month with no card.

FAQ

Does a challenge screenshot mean the CaptureKit API failed?

Not necessarily. It may mean the API returned an image of the challenge page. Check the HTTP response and logs to distinguish that from an API error.

Can I solve Cloudflare challenges with a longer wait?

A wait can help with ordinary rendering delays, but Cloudflare does not support automated browsers for solving production challenges. A longer wait is not a dependable challenge fix.

Can I use Cloudflare Browser Run for any website?

The documented WAF skip setup is for a zone you control and are authorized to configure. It is not a general-purpose method for capturing protected third-party sites.

What should I send the site administrator?

Share the reproduction time, error code and Ray ID if shown, plus relevant HAR and console diagnostics through a private channel. Remove secrets and sensitive user data first.