ScreenshotNeo

BlogHow-to

How to Capture a Webpage Screenshot with a Screenshot API Using cURL

Learn how to request and save a webpage screenshot with cURL, handle image and JSON responses, configure capture options, and troubleshoot common API errors.

By the ScreenshotNeo team4 October 202611 min read

To capture a webpage with cURL, send the target URL and any capture options to a screenshot API’s documented endpoint, authenticate as that provider requires, then save or download the response in the format it actually returns. Screenshot APIs do not share one protocol: some return image bytes, while others return JSON or redirect to an image. Check the provider’s response type before saving the response with an image extension.

This guide shows the general cURL patterns, explains how to adapt them to provider-specific APIs, and covers response handling, options, errors, and a hosted alternative. For a working one-call screenshot endpoint, see ScreenshotNeo.

1. Choose the request pattern your API documents

There is no standard screenshot API endpoint or universal set of parameter names. Before writing the command, find these details in the provider’s documentation:

  • Endpoint and method: Is the request a GET with query parameters, a POST with a JSON body, or something else?
  • Authentication: Does the API accept a bearer token, an API-key header, a query parameter, or another credential?
  • Success response: Does it return image bytes, JSON containing a screenshot URL, or a redirect?
  • Capture parameters: Which names does it use for format, viewport, full-page capture, waits, and other options?

These distinctions determine how you encode the URL, send options, and save the result. For example, Screenshot API’s documentation describes a JSON POST request and a GET response that returns JSON by default, with an option to redirect to the image. OpenGraph.io’s documentation describes a GET route with the target URL encoded in the path and a JSON response containing a screenshot URL. Those are provider-specific behaviors, not shared conventions.

2. Send a GET request with cURL

For APIs that accept the page URL as a GET query parameter, use --get and --data-urlencode. This encodes punctuation in the destination URL, including its own query parameters, so they are not confused with the screenshot API’s parameters.

export SCREENSHOT_API_KEY="YOUR_API_KEY"

curl --fail-with-body --get 'https://PROVIDER.example/v1/screenshot' \
  --header "Authorization: Bearer $SCREENSHOT_API_KEY" \
  --data-urlencode 'url=https://example.com/page?campaign=summer&view=full' \
  --data-urlencode 'format=png' \
  --output response.bin

Replace the example endpoint, authentication, and parameter names with values from your provider’s documentation. The filename is response.bin on purpose: use a neutral extension until you know whether the response is an image or JSON. --fail-with-body makes cURL return a failure status for HTTP error responses while keeping the response body available for inspection; it is available in cURL 7.76 and later.

If the API documents direct image bytes on success, choose a filename and extension matching the requested format, such as shot.png. If it returns JSON, save that response as JSON and extract the image URL or other image data before saving the image.

3. Send a JSON POST request

Use a JSON body when the provider documents POST, particularly when the capture has several options. This is a general pattern; the endpoint, option names, and response type are placeholders and must match the selected API.

export SCREENSHOT_API_KEY="YOUR_API_KEY"

curl --fail-with-body --request POST 'https://PROVIDER.example/v1/screenshot' \
  --header "Authorization: Bearer $SCREENSHOT_API_KEY" \
  --header 'Content-Type: application/json' \
  --data '{
    "url": "https://example.com/",
    "format": "png",
    "fullPage": true
  }' \
  --output response.bin

Do not assume --output screenshot.png is correct just because you requested a PNG. Some APIs return JSON containing a URL, and some return a redirect. Confirm the documented success response or inspect the response headers first.

4. Save the response correctly

The main cURL decision is what to do with the success response. Inspect the provider docs for the response format and, when needed, request headers with --include or --head if supported by that endpoint.

When the API returns image bytes

Save the response directly, using an extension that matches the requested image format and the API’s documented response:

curl --fail-with-body --request POST 'https://PROVIDER.example/v1/screenshot' \
  --header "Authorization: Bearer $SCREENSHOT_API_KEY" \
  --header 'Content-Type: application/json' \
  --data '{"url":"https://example.com/","format":"png"}' \
  --output screenshot.png

When the API returns JSON

Save the JSON response first. Read the provider’s schema to find the screenshot URL or encoded image field, then use the documented method to retrieve or decode it. A JSON response saved as .png is still JSON and cannot be opened as an image.

curl --fail-with-body --get 'https://PROVIDER.example/v1/screenshot' \
  --data-urlencode 'url=https://example.com/' \
  --output response.json

OpenGraph.io documents a JSON response with a screenshotUrl; its documentation says screenshot URLs expire after 24 hours. Download the file while the URL is valid if you need to retain it longer. Screenshot API documents JSON as its default GET response and offers a redirect option for image or PDF delivery. Check the current vendor documentation for the exact field names and redirect behavior.

When the API returns a redirect

If the endpoint responds with a redirect to the image, follow it with cURL’s --location option, if that matches the provider’s documented flow:

curl --fail-with-body --location --get 'https://PROVIDER.example/v1/screenshot' \
  --data-urlencode 'url=https://example.com/' \
  --output screenshot.png

Some APIs require authentication on the initial request, the redirected request, or both. Verify the provider’s redirect and credential guidance before forwarding sensitive headers across hosts.

5. Set capture options using the provider’s names

Capture options are not standardized. Confirm each option’s spelling, accepted values, default, and supported request method in the API reference. The following are common needs, with examples of how documented APIs may express them:

Need What to verify
Image format Supported formats such as PNG, JPEG, or WebP; whether PDF is a separate output mode.
Viewport Width and height, device presets, and whether dimensions describe a viewport or final image.
Full-page capture The provider’s flag and any maximum page or image dimensions.
Element capture Whether a CSS selector can target one element, and what happens if it is missing or matches multiple elements.
Wait behavior Supported delay, selector wait, or network-idle option; navigation timeout and maximum wait.
Rendering controls Dark mode, custom CSS or JavaScript, hidden selectors, ad blocking, and resource blocking, if available.
PDF output Paper size, margins, orientation, page ranges, and whether PDF options require POST.

For example, Screenshot API documents POST options including fullPage, viewport, selector, delay, and PDF settings; its advanced controls include CSS and JavaScript. OpenGraph.io documents options such as full_page, dimensions, selector, format, and capture delay. The names differ even when the goal is similar. Do not copy options between providers without checking their references.

6. Authenticate and protect API keys

Prefer an authorization header when the provider supports it, and keep the key in an environment variable or a secret manager rather than committing it to source control. A bearer-header example is:

export SCREENSHOT_API_KEY="YOUR_API_KEY"
curl --header "Authorization: Bearer $SCREENSHOT_API_KEY" ...

Some services accept an X-API-Key header instead. Use the exact header documented by that service. A query-string key may be supported for convenience, but URLs can be recorded in shell history, proxy logs, or monitoring systems. Avoid putting a live secret in a URL unless the provider requires it and you have accounted for those logs.

7. Complete ScreenshotNeo cURL example

ScreenshotNeo accepts a GET request to its screenshot endpoint. The following command saves a WebP screenshot of Stripe’s homepage:

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 the endpoint and available parameters. ScreenshotNeo’s documented product behavior is to return a screenshot or PDF from one GET request with a URL. Its options include PNG, JPEG, and WebP; full-page and selector capture; viewport and device settings; waits; custom headers and cookies; CSS and JavaScript; and PDF configuration.

For a script, keep the key out of committed source and supply it from an environment variable or secret store. The quick example above uses the specified cURL request shape; replace the example target URL as needed.

8. Python and Node.js examples

The same ScreenshotNeo endpoint can be called from application code. These examples save the response body; choose a filename that matches the output format you request.

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}`);
const bytes = Buffer.from(await res.arrayBuffer());
await import('node:fs/promises').then(fs => fs.writeFile('shot.webp', bytes));

ScreenshotNeo cURL, Python, and Node.js at a glance

Client Request behavior
cURL GET request with the access key and URL; save response with -o.
Python GET request with query parameters and a 90-second timeout; write response bytes.
Node.js GET request using URLSearchParams; write the response bytes.

9. Or skip the browser setup

With ScreenshotNeo, one GET request takes the screenshot; you do not need to install or manage a browser for this capture.

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

Cookie and consent banners are accepted like a visitor and removed before capture, along with 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 are not billed, and response headers identify the page verdict and billing status. 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 screenshots per month with no card; paid plans start at $5 for 3,000 screenshots. Every feature is available on every plan.

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

10. Common errors and fixes

Symptom Likely cause What to do
401 or 403 response Missing, invalid, expired, or incorrectly placed credential; insufficient permission. Check the provider’s required authentication scheme and header name, confirm the key is active, and verify account permissions.
400 response Invalid URL, malformed JSON, unsupported option, or wrong parameter name. Check JSON quoting, URL encoding, required fields, and the exact documented option names.
429 response Rate limit or quota reached. Check the provider’s rate and quota headers or dashboard; reduce request concurrency and retry according to documented limits.
502 or render failure The API could not render the destination, or the page failed to load in its browser. Try the page URL directly, check for access restrictions, and adjust documented wait or timeout settings. Do not assume a failed render produced an image.
Output file is JSON, not an image The endpoint returned metadata or an error document. Save as JSON, inspect the body and Content-Type, then follow the returned URL or documented redirect flow.
Image is empty or incomplete The page had not finished rendering, lazy content had not loaded, or the API captured only the viewport. Use the provider’s full-page and wait controls; wait for a meaningful selector when supported.
Element selector error The selector does not exist at capture time or is unsupported. Check selector spelling and timing; test the element in the page and use the provider’s documented missing-selector behavior.
Nested URL parameters disappear The target URL’s & or other punctuation was interpreted as an API parameter. Use --data-urlencode for a query parameter, or the provider’s documented JSON or encoded-path form.
cURL reports an unknown option The installed cURL version lacks that option, such as --fail-with-body. Check curl --version; upgrade cURL or use the available failure handling supported by your version.

Screenshot API documents errors including 401 authentication failures, 400 invalid requests, 429 rate or quota limits, and 502 render failures. These status codes and meanings are provider-specific; check the selected provider’s current reference rather than assuming all services use the same mapping.

11. Performance, reliability, and cost

Performance

  • For many captures, reuse connections where your HTTP client supports it, limit concurrency to the provider’s documented rate, and avoid retrying immediately in a tight loop.
  • Wait only as long as needed. A fixed delay can waste time; a selector wait or network-idle condition may better fit a page, if the API supports it.
  • Full-page rendering and large viewports can produce larger outputs and require more rendering work. Request only the dimensions and content your workflow needs.
  • Use a provider’s cache deliberately if available. Confirm its cache-key behavior and whether a cached response counts against quota or billing.

Reliability

  • Set a client-side timeout appropriate to the provider’s render time and your workflow; do not let a stalled request wait forever.
  • Check the HTTP status and content type before treating bytes as an image. Preserve error bodies for diagnosis.
  • Retry transient failures with bounded exponential backoff and jitter, but do not retry malformed requests or authentication failures without fixing them.
  • For bulk workflows, consider asynchronous jobs or webhooks if the provider offers them, and record request identifiers and outcomes.

Cost

  • Compare billing units, included quota, overage rules, and whether failed renders, cache hits, or redirects are billable. Do not infer these from another provider’s behavior.
  • Screenshot API’s documentation states its own current free-plan and rate limits; these are vendor-specific and should be rechecked before relying on them.
  • ScreenshotNeo states that only clean shots are billed; bot checks/CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing. Its Free plan includes 1,000 shots per month without a card. Paid plans are 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.

12. FAQ

How do I take a screenshot of a webpage using an API and cURL?

Use the API’s documented method and endpoint, send the page URL in its required form, authenticate, and save or process the response according to its content type.

How do I save a website screenshot from a cURL API request?

Use --output with an image filename only when the API returns image bytes or when a documented redirect leads to them. For JSON, save and parse the JSON, then download the image URL it provides.

Can I use one set of cURL parameters with every screenshot API?

No. Request methods, authentication, parameter names, and response formats vary. Follow the selected vendor’s API reference.

Can cURL capture a page by itself?

cURL sends HTTP requests; it does not render a webpage. The screenshot API performs the browser rendering and returns the result.

Sources