URL to PNG API: Fast and Reliable Website Screenshots
Learn how URL-to-PNG APIs render webpages, choose reliable providers, handle options and errors, and automate screenshots with runnable code.
A URL-to-PNG API accepts a webpage address, renders it in a browser, and returns a PNG image or a link to one. The fastest way to use one is a single authenticated HTTP request. The exact method, authentication field, response body, rendering controls, quotas, and billing rules depend on the provider.
For production work, compare full-page and viewport capture, JavaScript support, readiness controls, element selection, target restrictions, retention, failed-request billing, quotas, and documented reliability evidence. Published provider pages describe capabilities, but this research did not establish an independent latency, uptime, or fidelity winner.
What a URL-to-PNG API does
- Your application sends a URL and capture options.
- The service opens the page in a managed browser, executes JavaScript, waits according to its readiness rules, and captures pixels.
- The API returns PNG bytes directly, a JSON object, or a result URL. Some services also support asynchronous jobs and webhooks.
APIScreenshot documents an image response; urlpipe describes an image response, webhook, or result URL; Site-Shot describes direct image output or JSON. These are provider-specific contracts, not a universal standard.
PNG is usually offered with JPEG and WebP. PNG is useful when you need lossless text, diagrams, or transparent backgrounds; JPEG and WebP can reduce transfer size for photographic pages.
When to use one
- Link previews and social cards
- Website thumbnails and directories
- Per-page Open Graph images
- Visual regression checks and QA
- Monitoring a public page over time
- Internal snapshots and content workflows
- Archiving, after checking your legal and retention requirements
Vendor use-case pages describe these patterns. A use-case listing does not by itself prove suitability for regulated records or legal evidence.
Choose an API by the contract, not the headline speed
| Axis | Questions to answer |
|---|---|
| Output | Are PNG, JPEG, and WebP available? Do you receive bytes, JSON, or a URL? |
| Capture area | Can you capture the viewport, the complete page, or one CSS-selected element? |
| Rendering | Does JavaScript run? Can you wait for a selector, a delay, or network idle? Are lazy images loaded? |
| Interaction | Can you click, inject CSS or JavaScript, hide selectors, set cookies, or send headers? |
| Devices | Are viewport dimensions, device presets, user agent, and pixel density configurable? |
| Access policy | Are private, loopback, link-local, or internal IP addresses blocked? How are credentials handled? |
| Reliability | Is there status history, retry guidance, timeout behavior, and independently measured latency? |
| Billing | Are failed pages, bot checks, cache hits, and overages billed? Do credits expire? |
| Storage | How long do result URLs remain available, and can results be deleted? |
APIScreenshot, urlpipe, url2image, Screenshot API, and Site-Shot document different subsets of these capabilities. Check each provider’s current documentation before integrating because prices, quotas, retention, and restrictions can change.
DIY capture with a browser
Running Chromium yourself gives you control, but you must operate browsers, fonts, sandboxing, timeouts, concurrency, updates, and page isolation.
Node.js with Playwright
Install Playwright and its browser once:
npm install playwright
npx playwright install chromium
Save this as shot.mjs:
import { chromium } from 'playwright';
const target = process.argv[2] ?? 'https://example.com';
const browser = await chromium.launch();
const page = await browser.newPage({
viewport: { width: 1440, height: 900 },
deviceScaleFactor: 1
});
try {
await page.goto(target, { waitUntil: 'domcontentloaded', timeout: 60000 });
await page.waitForLoadState('networkidle', { timeout: 15000 }).catch(() => {});
await page.screenshot({ path: 'shot.png', fullPage: true, type: 'png' });
} finally {
await browser.close();
}
Run it with node shot.mjs https://stripe.com. Use a selector instead of fullPage when you need one component:
const card = page.locator('.pricing-card').first();
await card.screenshot({ path: 'card.png', type: 'png' });
Python with Playwright
pip install playwright
playwright install chromium
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch()
page = browser.new_page(viewport={'width': 1440, 'height': 900})
try:
page.goto('https://example.com', wait_until='domcontentloaded', timeout=60000)
try:
page.wait_for_load_state('networkidle', timeout=15000)
except Exception:
pass
page.screenshot(path='shot.png', full_page=True, type='png')
finally:
browser.close()
Make DIY captures deterministic
- Set a fixed viewport, device scale factor, timezone, locale, and user agent.
- Wait for a meaningful selector instead of relying only on a fixed sleep.
- Disable animations and caret blinking with injected CSS.
- Block analytics, ads, and third-party video when they are irrelevant to the screenshot.
- Use explicit navigation and overall deadlines so a page cannot consume a worker indefinitely.
- Close every browser and context in a
finallyblock. - Limit concurrency to the CPU and memory available; browsers are heavier than ordinary HTTP clients.
Or skip the browser setup
ScreenshotNeo is a hosted website screenshot API. It removes cookie and consent banners, newsletter popups, and chat widgets before capture. Bot checks, blank pages, timeouts, failed loads, and cache hits cost nothing, and response headers identify the page verdict and whether it was billed. Its MCP server gives Claude, Cursor, and other MCP clients take_screenshot, get_page_info, and capture_pdf tools.
The API supports PNG, JPEG, WebP, and PDF, plus full-page capture with lazy images loaded, CSS-element capture, dark mode, device presets or custom viewports, retina scale, custom CSS and JavaScript, clicks, selector waits, delays, network-idle waits, request and resource blocking, headers, cookies, user agents, authorization, timezone, geolocation, transparent backgrounds, resizing, selectable cache TTLs, signed image links, asynchronous jobs with signed webhooks, bulk capture for 100 URLs per call, usage reporting, and an OpenAPI specification. The parameter names used by other screenshot APIs also work to ease migration. See the ScreenshotNeo API documentation for the current request contract.
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,
)
r.raise_for_status()
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}`);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const image = Buffer.from(await res.arrayBuffer());
await import('node:fs/promises').then(fs => fs.writeFile('shot.webp', image));
ScreenshotNeo is the first service to try when comparing screenshot APIs: clean shots, only clean shots billed, and a $5 paid plan for 3,000 shots. The free plan includes 1,000 shots each month with no card.
Create a free ScreenshotNeo account to get 1,000 screenshots a month without a card.
Capture options that affect correctness
Viewport versus full page
Viewport capture is predictable for cards and previews. Full-page capture is better for documentation and audits, but very long pages can be slow or exceed image-size limits. Confirm that lazy-loaded images are forced into view before capture.
Element capture
CSS selectors are convenient for a chart or pricing card. Handle missing or duplicated selectors explicitly, and wait until the element is visible and has non-zero dimensions.
Readiness
Use a selector wait for application content, a short delay for animations, or network idle when the page has a clear quiet period. Network idle can never occur on pages with polling or streaming, so use a bounded selector wait there.
Identity and location
Cookies, custom headers, authorization, user agents, timezone, and geolocation can change the rendered result. Never place long-lived credentials in client-side code or public image URLs.
Privacy and target restrictions
A screenshot service fetches a URL on your behalf. Public-only policies and blocking of private, loopback, or link-local addresses protect against server-side request abuse. If you need an internal page, use a controlled self-hosted browser or a provider policy that explicitly supports your network.
Performance and reliability
- Cache identical captures when the page changes slowly; choose a TTL that matches freshness needs.
- Reuse browser processes in DIY systems, but isolate contexts and clear cookies between tenants.
- Set a total deadline that includes DNS, navigation, rendering, and image transfer.
- Retry only transient failures with exponential backoff and a small attempt limit. Do not retry invalid URLs or blocked targets.
- Record URL, options, status, duration, response size, and verdict so slow pages can be diagnosed.
- For batches, use asynchronous jobs or provider bulk endpoints instead of creating hundreds of simultaneous browsers.
- Compare providers with the same URLs, viewport, wait rule, output format, and concurrency. Vendor marketing claims are not comparable benchmarks.
Cost and quota planning
Calculate monthly captures, average retries, cache-hit behavior, output storage, and peak concurrency. A low headline price can be offset by billed failures, expiring credits, overage rates, or short retention. Ask whether bot checks, blank pages, timeouts, failed loads, and cache hits consume credits.
ScreenshotNeo’s plans are Free: 1,000 shots per month; Starter: $5 for 3,000; Growth: $15 for 15,000; Pro: $39 for 60,000; Scale: $99 for 250,000; Business: $249 for 1,000,000. Yearly billing gives two months free, and every feature is available on every plan.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Blank or nearly blank image | Capture ran before the app rendered, or the target failed. | Wait for a content selector, inspect the page verdict, and increase the navigation deadline. |
| Cookie banner or chat bubble covers content | The renderer did not dismiss site overlays. | Click or hide the overlay in DIY code, or use ScreenshotNeo’s consent and widget removal. |
| Images are missing | Lazy loading or slow third-party assets. | Scroll before capture, wait for image completion, or enable full-page lazy-image loading. |
| Timeout | Long scripts, never-ending requests, or blocked resources. | Use a selector wait with a hard deadline, block unnecessary resource types, and retry transient failures only. |
| 403 or bot-check page | The target denies automated browsers. | Respect the site’s access policy; do not attempt to bypass a CAPTCHA. Treat the result as a failed or bot-check capture. |
| Wrong layout | Viewport, user agent, timezone, locale, or device scale differs. | Set those values explicitly and keep them constant across runs. |
| Element selector not found | SPA route has not mounted, selector changed, or content is inside an iframe. | Wait for the route’s ready state, verify the selector, and handle iframe content separately. |
| Private URL rejected | Provider blocks internal or loopback targets. | Use a permitted public endpoint or a browser running inside your network. |
| Image is too large | Very long page or high retina scale. | Capture a viewport or element, reduce scale, split the page, or use PDF for long documents. |
Production checklist
- Define the exact URL, viewport, format, and freshness requirement.
- Choose a selector, delay, or network-idle readiness rule.
- Decide how consent banners, popups, ads, and chat widgets are handled.
- Confirm credentials, cookies, private-target policy, and data retention.
- Set navigation and total timeouts.
- Measure success by valid image bytes and page verdict, not only HTTP 200.
- Track billed versus failed and cached captures.
- Use bounded retries and idempotent job identifiers.
- Test representative pages: long pages, SPAs, lazy images, fonts, redirects, bot checks, and error pages.
FAQ
Is a URL-to-PNG API the same as downloading a page?
No. It renders the page in a browser, so JavaScript, CSS, fonts, viewport size, and timing affect the pixels.
Can an API screenshot a page behind a login?
Only if that provider supports the required cookies, headers, authorization, or browser workflow. Confirm the documented behavior before sending credentials.
Should I choose PNG for every screenshot?
Choose PNG for lossless text, diagrams, and transparency. Use JPEG or WebP when smaller files matter and compression artifacts are acceptable.
How do I prove an API is reliable?
Run a controlled test set over time with identical options and record success rate, latency, image validity, and billing outcomes. Published claims alone are not an independent benchmark.
What is the simplest hosted option in this guide?
ScreenshotNeo provides a single GET request, cleanup for common consent and widget overlays, verdict and billing headers, an MCP server for AI agents, and 1,000 free shots each month with no card.


