ScreenshotNeo

BlogGuides

Website Screenshot API: Capture Pages as Images or PDFs

Capture a rendered web page as a PNG, JPEG, WebP, or PDF. Compare a hosted screenshot API with Playwright, and learn how to handle capture options and failures.

By the ScreenshotNeo team4 October 202610 min read

A website screenshot API takes a page URL, renders it in a browser, and returns an image or PDF. Use a hosted API when you want to avoid operating browsers; use Playwright when you need direct control and can maintain the browser capture flow yourself. A screenshot is a rendered browser view, not a copy of the page’s raw HTML.

This guide shows a local Playwright implementation, explains the capture choices that affect output, and covers how to evaluate a hosted service. For a managed option, ScreenshotNeo provides URL-based image and PDF capture through an API and an MCP server.

1. Choose a capture approach

Approach What you operate Useful when
ScreenshotNeo API Your request and output handling You want a URL-based capture, configurable browser options, and clean screenshots without running browser infrastructure.
Playwright in your environment The browser, code, storage, retries, and failure handling You need browser-level control and can own the capture service operationally.
Another managed API Your request and output handling Evaluate the provider’s specific capture modes, interaction support, quota, cache, authentication, data controls, and support terms.

Playwright documents navigation followed by screenshot or PDF generation. Microlink documents a managed REST API for URL-derived screenshots and PDFs; ScreenshotCenter documents scripted actions for PDF capture. These are provider-documented capabilities, not a comparative performance ranking. Choose based on required output, capture scope, viewport, interactions, authentication, caching, quotas, and how failures are reported. See the Playwright Page API, Microlink API documentation, and ScreenshotCenter PDF API.

2. Run a local capture with Playwright

The following Node.js example uses Playwright and Chromium to save a full-page PNG. Install Playwright and its browser first:

npm init -y
npm install playwright
npx playwright install chromium

Save this as capture.mjs:

import { chromium } from 'playwright';

const url = process.argv[2] ?? 'https://example.com';
const browser = await chromium.launch({ headless: true });

try {
  const page = await browser.newPage({
    viewport: { width: 1440, height: 900 },
    deviceScaleFactor: 1,
  });
  const response = await page.goto(url, {
    waitUntil: 'networkidle',
    timeout: 30_000,
  });

  if (!response) {
    throw new Error('Navigation returned no main-resource response');
  }
  if (!response.ok()) {
    throw new Error(`Page returned HTTP ${response.status()}`);
  }

  await page.screenshot({ path: 'page.png', fullPage: true });
  console.log(`Saved page.png (${response.status()})`);
} finally {
  await browser.close();
}

Run it with:

node capture.mjs https://example.com

The example waits for network idle, which can be unsuitable for pages that keep connections open. For those pages, use waitUntil: 'domcontentloaded' or 'load', then wait for a page-specific selector or a short, bounded delay. A successful navigation response does not guarantee that a client-rendered application has finished drawing its important content.

Capture one viewport or a full page

By default, page.screenshot() captures the visible viewport. Set fullPage: true to capture the scrollable page as if it were displayed on a very tall screen. Very long pages can create large images and consume substantial memory. For a single component, target its locator:

const card = page.locator('.report-card');
await card.screenshot({ path: 'report-card.png' });

Wait for the target to exist and be visible first. If the selector matches multiple elements, choose one explicitly, for example page.locator('.report-card').first(). A selector that is absent or hidden will fail rather than produce the intended component image.

Choose image type and scale

Playwright supports PNG, JPEG, and WebP screenshot output, with format-specific options such as JPEG quality. Its scale setting controls whether output dimensions follow CSS pixels or device pixels. Device-pixel output can increase image dimensions and file size. Use PNG for sharp text and interfaces, JPEG for photographic content where lossy compression is acceptable, and WebP when your downstream tools support it. Check the current screenshot options for the exact option names supported by your Playwright version.

await page.screenshot({ path: 'page.webp', type: 'webp' });
await page.screenshot({ path: 'page.jpg', type: 'jpeg', quality: 82 });

Generate a PDF

Playwright’s page.pdf() generates PDF using print CSS media by default. That can change colors, hide content, or apply print-specific styles. To render screen styles instead, emulate screen media before generating the PDF:

await page.emulateMedia({ media: 'screen' });
await page.pdf({
  path: 'page.pdf',
  format: 'A4',
  printBackground: true,
  margin: { top: '12mm', right: '12mm', bottom: '12mm', left: '12mm' },
});

Use format or explicit page dimensions, and set margins and landscape orientation as required. If the PDF is unexpectedly missing backgrounds or uses a different layout, check print CSS behavior and printBackground. Refer to the Playwright PDF documentation for available options.

Wait for application content

Prefer a condition that represents the content you need over an arbitrary long sleep. For example:

await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 30_000 });
await page.locator('[data-ready="true"]').waitFor({ state: 'visible', timeout: 10_000 });
await page.screenshot({ path: 'ready.png', fullPage: true });

For lazy-loaded images, a full-page capture may not cause every image to load. If image completeness matters, scroll through the page in controlled increments and wait for image loading before capture, or use a capture API that explicitly supports loading lazy images. Avoid unbounded scrolling on pages with infinite feeds.

3. Use a hosted screenshot API

A managed API accepts a URL and returns the resulting asset or image bytes. It removes the need to install and operate a browser for each capture, but you still need to handle API keys, timeouts, output storage, retries, and the provider’s documented quotas and behavior.

ScreenshotNeo’s API base is https://api.screenshotneo.com/v1/shot. The following requests use the provided API examples and save the returned bytes. See the ScreenshotNeo documentation for parameters and response details.

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()
with open("shot.webp", "wb") as f:
    f.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(`Screenshot request failed: ${res.status}`);
await Bun.write('shot.webp', res);

In Node.js environments without Bun, replace the final line with:

import { writeFile } from 'node:fs/promises';
await writeFile('shot.webp', Buffer.from(await res.arrayBuffer()));

Configure the capture

ScreenshotNeo offers options for common capture needs. Consult its documentation for exact parameter names and accepted values before adding them to a request.

Need Available options Considerations
Control capture area Full page, one element by CSS selector, viewport sizing Full-page output can be large; element capture depends on a stable selector.
Match a display 12 device presets, arbitrary viewport, retina scale, dark mode Specify viewport and scale consistently when comparing captures over time.
Choose output PNG, JPEG, WebP, or PDF; PDF paper size, margins, landscape, and page ranges PDF layout may differ from screen styling; confirm the desired print behavior.
Prepare page content Load lazy images, custom CSS or JavaScript, click an element, hide selectors Use narrowly scoped scripts and selectors; page changes can invalidate them.
Control readiness Wait for a selector, a delay, or network idle Network idle may never arrive on pages with persistent connections; use a bounded selector wait or delay.
Reduce unwanted content or requests Remove consent banners, newsletter popups, and chat widgets; block ads, trackers, requests, or resource types Each clean-up step can be turned off. Blocking resources can also remove content the page needs.
Access a protected or localized page Custom headers, cookies, user agent, Authorization, timezone, geolocation Treat credentials and private page content as sensitive; send only the access needed for the capture.
Control delivery and reuse Transparent background, image resizing, chosen cache TTL, signed links for public image tags Choose cache duration based on how quickly the source changes and whether the result is safe to share.
Scale workflows Async jobs with signed webhooks, bulk capture up to 100 URLs per call, usage API, OpenAPI spec For asynchronous work, make webhook processing idempotent and verify signatures.

ScreenshotNeo also accepts parameter names used by other screenshot APIs, which can make migration easier. Confirm each option and output format in the API docs before switching; matching parameter names do not by themselves guarantee identical rendering behavior.

4. Or skip the browser setup

One GET request sends a URL and returns a rendered screenshot. This example saves a WebP response:

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

See the ScreenshotNeo API documentation for output and capture options. Before capture, cookie and consent banners are accepted and removed, along with more than 60 known consent platforms, newsletter popups, and chat widgets; each step can be turned off. Bot checks and CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, and response headers report the page verdict and billing status. An MCP server provides take_screenshot, get_page_info, and capture_pdf tools for AI agents. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 screenshots.

Sign up for 1,000 free screenshots a month, with no card required.

5. Reliability, performance, and cost

Reliability

  • Set an explicit navigation or request timeout. Pages can hang on scripts, third-party resources, or persistent network activity.
  • Check the main navigation status and verify the expected page content before saving a file. A browser can render an error page successfully.
  • Retry only transient failures, with a bounded attempt count and backoff. Do not retry a deterministic 404 or invalid URL indefinitely.
  • For asynchronous jobs and webhooks, store a job identifier, verify signed callbacks, and make result handling safe to repeat.
  • Keep credentials out of source control and avoid logging authorization headers, cookies, or sensitive URLs.

Performance and output size

Capture time depends on page behavior, network conditions, readiness criteria, and rendering work. A full-page, high-scale capture can require more memory and produce a larger asset than a viewport shot. Capture only the region you need, use an appropriate scale and format, and choose a finite readiness condition. Cache results when the page can tolerate reuse; choose the TTL based on how often the source changes.

Cost and operating effort

With self-managed Playwright, account for the engineering and infrastructure needed to install browsers, run jobs, store results, isolate captures, and recover from failures. With a hosted API, compare published quotas, pricing, cache behavior, authentication controls, support, and data handling against your workload. The research snapshot reported Microlink’s displayed Free and Pro plan figures as of 2026-10-03: 25 requests per day on Free, and $49 per month for about 46,000 requests on Pro, with a vendor-stated 99.9% uptime SLA on paid plans. These are Microlink-published plan claims and may change; verify the current Microlink API page before relying on them.

ScreenshotNeo’s stated plans are Free for 1,000 shots/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 available on every plan. Clean shots alone are billed; the API response includes page-verdict and billing headers.

6. Troubleshooting

Symptom Likely cause Fix
Navigation timeout The page is slow, keeps connections open, or waits on third-party resources. Use a bounded timeout and a more suitable readiness condition such as DOM content loaded, followed by a selector wait.
Screenshot is blank or incomplete The app renders after navigation, content is below the fold and lazy-loaded, or a required resource was blocked. Wait for a meaningful selector, scroll in bounded increments for lazy content, and review blocked request rules.
Cookie dialog or popup covers the page The capture begins before the overlay is handled. In Playwright, explicitly handle the site’s consent flow or hide a known overlay when permitted. ScreenshotNeo removes supported consent banners, newsletter popups, and chat widgets before capture; these steps are configurable.
Full-page image is huge or fails The page is exceptionally long, infinite-scrolling, or rendered at a large device scale. Capture a viewport or element, constrain the target page, reduce scale, or load only a bounded part of the page.
Element capture cannot find selector The selector changed, is not yet rendered, or matches no visible element. Wait for the selector, validate it against the current page, and choose a specific match.
PDF looks different from the browser Print CSS is active, backgrounds are omitted, or page dimensions and margins differ. For Playwright, emulate screen media if needed, enable print backgrounds, and set the intended paper size and margins.
API returns an error or unexpected asset Invalid key, malformed URL, unsupported option, blocked page, or failed navigation. Check the status and response headers, confirm query encoding and documented parameter values, and inspect the page-verdict and billing headers where available.
Repeated captures show stale content A cache entry is being reused. Adjust or disable caching using the documented cache controls and choose a TTL that fits the freshness requirement.
Local browser will not launch The browser binary is not installed for the selected engine or the runtime lacks required dependencies. Install the matching Playwright browser with its install command and confirm the deployment environment supports it.

7. Frequently asked questions

Does a screenshot API fetch HTML or render the page?

It renders the URL in a browser. That allows JavaScript-driven pages to appear in the capture, subject to page readiness and resource loading.

Can I use screenshots in an HTML image tag?

Yes, if the provider supports a public image URL suitable for embedding. ScreenshotNeo supports signed links for public <img> tags; follow its documentation for link creation and access controls.

Can an AI agent request screenshots?

ScreenshotNeo provides an MCP server with tools for screenshots, page information, and PDF capture. It can be used by Claude, Cursor, and MCP clients.

Should I use PDF or an image for archiving?

Use PDF when page-oriented output, paper dimensions, or a document workflow matters. Use an image when you need a visual snapshot for a card, report, or image pipeline. Neither format alone guarantees an immutable or legally authoritative record; define retention and evidence requirements separately.