ScreenshotNeo

BlogHow-to

How to Wait for a Webpage to Finish Loading Before a Cloudinary Screenshot

Use Cloudinary URL2PNG’s delay option for predictable pages, or wait for a page-specific condition in browser automation when rendering is asynchronous.

By the ScreenshotNeo team4 October 20268 min read

Direct answer: Cloudinary URL2PNG documents a delay option that waits after navigation before taking a screenshot. Use it when a predictable short pause is enough. Cloudinary’s reviewed URL2PNG documentation does not describe a CSS-selector wait or a network-idle option. For pages whose content appears asynchronously, use browser automation to wait for the specific content or application state you need, then capture the page.

A navigation event such as load does not guarantee that client-side rendering or data fetching is complete. Choose the readiness condition based on what must be visible in the screenshot, and verify the result in your own workflow. No target page or timing was tested for this guide.

1. Choose the right kind of wait

Page behavior Approach Trade-off
Content appears after a consistent, brief delay Set URL2PNG’s documented delay option Simple to add, but a fixed pause can be too short on a slow run and unnecessarily long on a fast one.
A specific element or state signals readiness Use browser automation and wait for that condition before capturing More setup, but the wait can match the content the screenshot actually needs.
The page has continuous requests or polling Wait for a page-specific element or assertion A generic quiet-network condition may never occur or may occur before the desired content is ready.

The distinction is about control: URL2PNG offers a documented fixed delay, while a browser automation workflow can wait on page-specific readiness. A selector or assertion is useful only when the target page exposes a stable condition for the content you care about.

2. Add a delay to a Cloudinary URL2PNG screenshot

Cloudinary’s URL2PNG add-on generates a screenshot through the url2png delivery type. Its documentation describes URL2PNG options in the public ID, in a form like <website URL>/url2png/<option=value>|..., and lists options such as delay, viewport, and user agent. Confirm the current syntax and option values in the Cloudinary URL2PNG documentation before using a URL in production.

https://res.cloudinary.com/YOUR_CLOUD_NAME/image/url2png/delay_1000/https://example.com

This illustrates the URL2PNG delivery type and a delay option; it is not a substitute for checking the exact current URL syntax, account configuration, and signing requirements for your Cloudinary setup. The dossier does not establish a universal delay duration. Choose a value based on the target page and inspect the resulting capture rather than assuming one value works for every site.

Cloudinary prerequisites and access

  1. Have a Cloudinary account and register for the URL2PNG add-on.
  2. Build the URL2PNG delivery URL using the current documented syntax and options.
  3. Account for Cloudinary’s delivery access rules: URLs generally need signatures or eager generation unless unsigned add-on transformations are enabled in Console Settings.
  4. Request the URL and inspect the image. Adjust the delay only when the capture shows that the desired content is still rendering.

Cloudinary’s delivery type documentation also identifies url2png as an add-on delivery type. A URL that fails before capture may therefore reflect add-on registration or delivery access configuration, rather than a wait problem.

3. Use browser automation when readiness is page-specific

If the screenshot needs a particular widget, chart, or client-rendered section, wait for that content before capturing. The following Playwright example waits for a CSS selector, saves a PNG, and uses an explicit timeout. Replace the example URL and selector with values for the page you control or are permitted to capture.

import { chromium } from 'playwright';

const browser = await chromium.launch();
try {
  const page = await browser.newPage({ viewport: { width: 1440, height: 1000 } });
  await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });
  await page.locator('[data-report-ready="true"]').waitFor({
    state: 'visible',
    timeout: 15000
  });
  await page.screenshot({ path: 'page.png', fullPage: true });
} finally {
  await browser.close();
}

Install Playwright and its browser runtime according to the Playwright installation documentation. The readiness selector above is an example contract, not a selector guaranteed to exist on arbitrary websites.

Wait for the condition that matters

  • Selector: Wait until the element containing the needed content is visible, attached, or has the expected text.
  • Application state: Wait for a stable attribute, status marker, or other page-specific signal your app sets when rendering is complete.
  • Navigation milestone: Use domcontentloaded or load as a navigation boundary, then add a content assertion if the screenshot depends on asynchronous rendering.
  • Short fixed pause: Use a bounded delay only when no stronger readiness signal is available and the rendering time is predictable.

Playwright documents navigation milestones and discourages networkidle for tests; a page can keep connections open or become briefly quiet before the content you need appears. Prefer a web assertion tied to readiness. See Playwright navigation options.

4. cURL, Python, and Node.js examples for the browser workflow

These examples call a small local Playwright service that you provide. The service should accept a URL, navigate with a browser, wait for an application-specific condition, and return a PNG. There is no universal hosted endpoint implied here: implement and secure the endpoint in your own environment. The examples show how to send a request to it.

cURL

curl --fail --output page.png \
  --get 'http://localhost:3000/screenshot' \
  --data-urlencode 'url=https://example.com' \
  --data-urlencode 'ready_selector=[data-report-ready="true"]'

Python

import requests

response = requests.get(
    'http://localhost:3000/screenshot',
    params={
        'url': 'https://example.com',
        'ready_selector': '[data-report-ready="true"]',
    },
    timeout=45,
)
response.raise_for_status()
with open('page.png', 'wb') as image:
    image.write(response.content)

Node.js

const query = new URLSearchParams({
  url: 'https://example.com',
  ready_selector: '[data-report-ready="true"]',
});

const response = await fetch(`http://localhost:3000/screenshot?${query}`);
if (!response.ok) {
  throw new Error(`Screenshot request failed: ${response.status}`);
}
await Bun.write('page.png', new Uint8Array(await response.arrayBuffer()));

The Python and Node.js snippets are clients for your own service, not Cloudinary URL2PNG parameters. If the browser is deployed remotely, replace the local URL with your configured endpoint and protect it against unauthorized use.

5. Or skip the browser setup

For a one-call screenshot API, ScreenshotNeo accepts a URL and returns an image or PDF. Its options include waits for a selector, a delay, or network idle, so you can select a readiness strategy for the page. For this Cloudinary-focused workflow, it is an alternative to try first when you want a screenshot without operating browser automation yourself.

See the ScreenshotNeo API documentation for request options. The following runnable examples request a WebP screenshot of the same example page.

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)
r.raise_for_status()
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(`Screenshot request failed: ${res.status}`);
await Bun.write('shot.webp', new Uint8Array(await res.arrayBuffer()));
  • Cookie banners are accepted and removed before capture, along with known newsletter popups and chat widgets; each cleanup step can be turned off.
  • Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed. Responses identify the page verdict and billing status in headers.
  • An MCP server lets AI agents use take_screenshot, get_page_info, and capture_pdf.
  • 1,000 screenshots per month are free with no card; paid plans start at $5 for 3,000 screenshots.

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

6. Performance, reliability, and cost considerations

  • Fixed delay: A longer delay increases time per capture and still cannot guarantee readiness when rendering time varies. Keep it as short as the page allows, and check representative captures.
  • Condition-based wait: A selector or state wait can finish as soon as the required content appears. Set a timeout so a missing element does not leave the capture waiting indefinitely.
  • Network activity: Analytics, streaming, polling, and long-lived requests can make network-idle strategies unsuitable. A page-specific signal can avoid waiting for unrelated activity.
  • Browser operations: Browser automation requires a browser runtime and operational resources. Account for startup, concurrency, memory, timeouts, and image delivery in your own deployment; no benchmark is asserted here.
  • Cloudinary access: Add-on registration and URL signing or eager-generation configuration affect whether a URL works. Review the current Cloudinary account and delivery settings.
  • Cost: The dossier does not specify Cloudinary URL2PNG pricing, so check your Cloudinary account for current charges. Browser runtime costs depend on the environment you choose. ScreenshotNeo’s published plans are Free (1,000/month), Starter ($5 for 3,000), Growth ($15 for 15,000), Pro ($39 for 60,000), Scale ($99 for 250,000), and Business ($249 for 1,000,000); yearly billing gives two months free, and every feature is on every plan.

7. Troubleshooting

Symptom Likely cause What to do
Screenshot misses JavaScript-rendered content The capture occurs after navigation but before the app has rendered the needed content. Increase URL2PNG’s delay if timing is predictable, or use browser automation and wait for the target element or state.
Some runs are complete and others are not A fixed delay is shorter than the slowest rendering runs. Use a page-specific readiness condition where possible. If constrained to a delay, tune it against the page’s observed variation and recheck captures.
Automation waits until timeout The selector is wrong, absent, hidden, or never reaches the expected state. Inspect the page DOM and selector, confirm the intended visibility state, and make the timeout report the URL and selector.
Network-idle wait never completes The page has persistent requests, polling, or streaming connections. Wait for the required content or an app-owned readiness marker instead of global network quiet.
Cloudinary URL returns an access or delivery error The URL2PNG add-on may not be registered, or the URL may not satisfy signing/eager-generation settings. Check add-on registration and Cloudinary Console Settings, then follow the current URL2PNG documentation for delivery access.
Cloudinary captures before the desired state despite a valid URL The selected fixed delay is insufficient for that page or run. Adjust the documented delay and verify. If the page has variable asynchronous work, move the wait into browser automation.
Screenshot looks blank or navigation fails The destination may be unavailable to the renderer, may block automation, or may not finish within the configured timeout. Check the URL from the rendering environment, response and navigation errors, and timeout settings. Do not treat a larger wait as a fix for an inaccessible page.

8. FAQ

Does Cloudinary URL2PNG support waiting for a CSS selector?

The reviewed URL2PNG documentation does not list a selector-wait option. Use browser automation when the capture must wait for a particular element.

Does load mean the page is ready for a screenshot?

Not necessarily. Client-side rendering and later data requests can continue after a navigation milestone. Wait for the content the screenshot needs.

Should I always wait for network idle?

No. Pages with ongoing requests may not become idle, and a quiet period does not prove that the needed content is present. Prefer a page-specific assertion when available.

Can I use Cloudflare’s selector-wait options in a Cloudinary URL?

No. Cloudflare’s Browser Rendering screenshot and snapshot APIs document their own controls; those options do not establish URL2PNG parameters. See the Cloudflare screenshot API and snapshot API documentation.