ScreenshotAPI review for Indian web developers
A practical review of ScreenshotAPI’s API, rendering controls, pricing, and India-specific billing questions, with runnable request examples.
ScreenshotAPI is a hosted website screenshot API: send a POST request with a URL or raw HTML and an API key, then receive image data or a redirect to an image. Its reference documents PNG and JPEG output and controls for viewport, waits, full-page capture, clipping, CSS, popups, and cookie banners. For developers in India, the main caveat is commercial clarity: the pricing page currently contradicts itself about whether the free allowance is 100 or 1,000 screenshots, and the reviewed official pages do not establish INR pricing or India-specific payment support.
This review covers the service at screenshotapi.com, not similarly named screenshot products. It is based on the vendor’s published pages; it does not claim a hands-on test, measured latency, or independent reliability result.
1. What ScreenshotAPI does
The documented endpoint is https://api.screenshotapi.com/take. The reference specifies a POST request, an API key credential named apiKey, and a request body that can contain a page URL or raw HTML. The response can be JSON (metadata and base64 image data) or a redirect to the image. The endpoint reference labels itself v1.0. See the official take-a-screenshot API reference.
In practice, an application can call the endpoint from a backend job, a scheduled capture process, or a server-side feature. Keep the API key on the server. Do not put it in frontend JavaScript, a public repository, or a URL users can inspect.
2. Make a screenshot request
The examples below use the reference’s POST endpoint and its apiKey credential. Install Python’s requests package with python -m pip install requests. The Node.js example uses the built-in fetch available in current Node.js releases.
cURL
curl -X POST "https://api.screenshotapi.com/take?apiKey=$SCREENSHOTAPI_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com",
"responseType": "redirect",
"type": "png",
"viewportWidth": 1280,
"viewportHeight": 720
}' \
-L -o screenshot.png
Set SCREENSHOTAPI_KEY in the shell environment before running the command. -L follows the redirect response; remove it if you want to inspect the redirect behavior yourself. The endpoint reference lists the API key as a query credential and documents redirect and json response types.
Python
import os
import requests
api_key = os.environ["SCREENSHOTAPI_KEY"]
response = requests.post(
"https://api.screenshotapi.com/take",
params={"apiKey": api_key},
json={
"url": "https://example.com",
"responseType": "redirect",
"type": "png",
"viewportWidth": 1280,
"viewportHeight": 720,
},
timeout=90,
allow_redirects=True,
)
response.raise_for_status()
content_type = response.headers.get("content-type", "")
if "image/" not in content_type:
raise RuntimeError(f"Expected an image response, got {content_type!r}")
with open("screenshot.png", "wb") as image_file:
image_file.write(response.content)
Save the key in the SCREENSHOTAPI_KEY environment variable. When using responseType: "json", handle the JSON metadata and base64 image field according to the API response rather than writing the JSON document to an image file.
Node.js
const apiKey = process.env.SCREENSHOTAPI_KEY;
if (!apiKey) throw new Error("Set SCREENSHOTAPI_KEY first");
const response = await fetch(
"https://api.screenshotapi.com/take?apiKey=" + encodeURIComponent(apiKey),
{
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({
url: "https://example.com",
responseType: "redirect",
type: "png",
viewportWidth: 1280,
viewportHeight: 720,
}),
redirect: "follow",
signal: AbortSignal.timeout(90000),
},
);
if (!response.ok) {
throw new Error(`ScreenshotAPI returned HTTP ${response.status}: ${await response.text()}`);
}
const contentType = response.headers.get("content-type") || "";
if (!contentType.includes("image/")) {
throw new Error(`Expected an image response, got ${contentType}`);
}
await Bun.write("screenshot.png", new Uint8Array(await response.arrayBuffer()));
This Node example uses Bun’s file-writing helper. For plain Node.js, replace the final line with import { writeFile } from "node:fs/promises"; at the top and await writeFile("screenshot.png", Buffer.from(await response.arrayBuffer()));.
3. Rendering controls and when to use them
The endpoint reference documents these request body options. Defaults and allowed values below follow that reference; check the current documentation before relying on a particular parameter in a production integration.
| Need | Parameter(s) | Behavior and notes |
|---|---|---|
| Choose input | url, html, markdown |
url is required for a URL capture; the docs also describe raw HTML or Markdown input as alternatives. |
| Choose response | responseType |
json (default) returns metadata and base64; redirect returns the image directly. |
| Choose image format | type, quality |
The endpoint lists png and jpeg; JPEG quality ranges from 0 to 100 and defaults to 100. Quality applies only to JPEG. |
| Set viewport or device | viewportWidth, viewportHeight, viewportDevice |
Width defaults to 1280 px and height to 720 px. A device preset can be selected with viewportDevice; the reference gives ipad_gen_6 as an example. |
| Set pixel density | deviceScaleFactor, scale |
Device scale factor accepts 1–5. scale is css (1x) or device (device pixel ratio, the default). |
| Wait for page readiness | waitUntil, waitForSelector, delay, timeout |
waitUntil accepts load (default), domcontentloaded, networkidle0, or networkidle2. You can wait for a CSS selector, add a delay of 0–20,000 ms, and set a maximum load wait with timeout. |
| Capture beyond the viewport | fullPage, doScroll |
fullPage defaults to false and captures the full scrollable page when enabled. doScroll scrolls before capture to trigger lazy-loaded content. |
| Capture a region | clipX, clipY, clipWidth, clipHeight |
Coordinates are pixel offsets from the top-left; width and height set the clipping region. Ensure the region fits the rendered content. |
| Adjust page content | style, blockPopups, blockCookieBanners |
style injects custom CSS. Popup blocking and cookie-banner dismissal default to true and can be controlled independently. |
| Control cursor and background | caret, omitBackground |
caret accepts hide (default) or initial. omitBackground makes the background transparent and is for PNG output. |
Examples for common capture jobs
For a long page with lazy content, add "fullPage": true and "doScroll": true. For a single-page application, wait for a stable element such as "waitForSelector": "main article", or choose an appropriate navigation event. For a smaller file, use JPEG and choose a quality value that preserves the details your use case needs. For a transparent overlay, request PNG with "omitBackground": true. For a targeted crop, specify all four clip coordinates and dimensions.
Use networkidle0 or networkidle2 only when it fits the page: analytics, polling, and long-lived connections can keep network activity open. A selector wait can be more targeted when a specific element signals that the useful content is ready. The documented delay has a 20-second maximum.
4. Pricing and the India-specific questions
ScreenshotAPI’s pricing page advertises metered usage at $0.001 per screenshot and these prepaid packs: 2,000 for $2, 5,000 for $5, 10,000 for $9, 25,000 for $22, 50,000 for $40, and 100,000 for $80. Larger packs have lower listed unit prices. These are the vendor’s posted dollar figures, not an INR quote. Check the current pricing page before budgeting.
The free quota is internally inconsistent on that page: its headline and main copy say 100 free shots, while a signup call to action and the footer say 1,000. The page also promotes pay-as-you-go with no subscriptions while its FAQ discusses changing plans. Treat the free amount and billing model as unresolved until confirmed in the signup flow or account dashboard.
The pricing FAQ says, “A screenshot is counted when a successful image has been taken.” It also says failed screenshots caused by a server interruption or webpage load failure are not charged against quota. Confirm how the account reports usage and failed attempts before building a high-volume cost forecast.
For Indian developers, the reviewed vendor pages do not establish INR settlement, India-specific payment methods, India eligibility, local support hours, or data residency. The terms identify the provider as a Delaware LLC and say posted prices exclude applicable local taxes. Check checkout’s final amount, applicable taxes, payment options, and any procurement requirements before purchase; do not assume the displayed dollar price is the final landed cost.
5. Performance, reliability, and cost planning
The vendor homepage uses general speed and availability language, but the reviewed official material does not provide a dated benchmark, a numeric SLA, or an India-specific latency measurement. A useful evaluation is to run your own representative URLs from the environment where your application runs. Measure end-to-end response time, successful image delivery, output size, and failures across the page types and viewport settings you actually need. Do not infer production performance from a marketing claim or a single successful request.
- Reduce avoidable work: request only the output dimensions and quality your downstream use needs. JPEG quality affects JPEG only; transparent output requires PNG.
- Choose waits deliberately: waiting for a selector or a specific navigation event may avoid unnecessary delay. Long waits increase the time each job occupies a worker.
- Budget by successful volume and pack: the advertised unit rate is low, but the free allowance is contradictory and larger packs have different effective rates. Reconcile expected monthly successful captures against the account’s actual terms.
- Plan for variable pages: third-party scripts, slow assets, anti-bot interstitials, and pages that change layout can affect output. Keep a record of the URL, settings, response status, and capture time so a bad image can be reproduced.
- Protect credentials and outputs: store the API key in server-side secrets. Treat captured pages as potentially sensitive if they contain account, customer, or internal data.
There is no independent performance or reliability comparison in the reviewed sources. Compare providers using identical representative URLs, viewports, output formats, and wait settings, and verify billing for failed renders rather than assuming their definitions match.
6. Troubleshooting
| Symptom | Likely cause | What to check |
|---|---|---|
| HTTP 400 | Invalid or incompatible request parameters. | Check JSON syntax, parameter spelling and types, allowed enum values, format, dimensions, and clip geometry. The reference lists 400 for invalid parameters. |
| HTTP 401 | Missing or invalid API key. | Confirm the key is passed as the apiKey query credential, that the environment variable is set, and that the key has not been copied with extra whitespace. The reference lists 401 for missing or invalid credentials. |
| JSON saved as an image | The default response type is JSON. | Set responseType to redirect and follow the redirect, or parse JSON and decode its base64 image data. |
| HTML error page saved with a .png suffix | The request returned an error or non-image response. | Check the HTTP status and Content-Type before writing bytes. Log the response body for errors rather than treating every response as an image. |
| Blank or incomplete screenshot | The page had not rendered its content when capture began, or the page itself returned little content. | Wait for a content-specific selector; try a suitable navigation event or a bounded delay. Confirm the target URL loads normally in a browser. |
| Missing images lower down the page | Lazy-loaded assets may not load until scrolled into view. | Try doScroll with fullPage, and compare the result on representative long pages. |
| Capture waits too long | Network-idle may never occur on a page with polling or persistent connections. | Use a selector wait or a different documented waitUntil value; set a suitable timeout and avoid an unnecessarily long delay. |
| Crop is empty or misplaced | Clip coordinates do not correspond to the rendered viewport or content. | Recheck the x/y origin and pixel width/height against the selected viewport and page layout. |
| Transparent background has no effect | Transparent background is documented for PNG only. | Set type to png and omitBackground to true. |
| GIF assumed but unavailable in a workflow | The site advertises GIF, but the endpoint reference enumerates PNG and JPEG. | Confirm GIF support for the specific endpoint and account before depending on it. |
7. Is ScreenshotAPI a fit for Indian web developers?
It is a plausible candidate when you want a hosted capture endpoint, need the rendering controls documented above, and are comfortable evaluating its request behavior and account terms yourself. The endpoint’s POST model and API-key credential are conventional, and its documented controls cover several common capture needs.
The open questions matter for production decisions: the free quota conflicts across the pricing page, the pricing FAQ and primary copy use mixed billing language, and the reviewed sources do not settle India-specific payment, currency, tax totals, latency, or support. Before adopting it, verify current signup terms and checkout details, then run captures on your own dynamic pages and network path.
8. Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server by Yorker Media. Its one-call API handles the hosted browser setup, and the API documentation describes the request options.
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)
open("shot.webp", "wb").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}`);
ScreenshotNeo accepts cookie and consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets before the capture; each cleanup step can be turned off. Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed, and response headers report the page verdict and billing status. An MCP server gives AI agents tools to take screenshots, get page information, and capture PDFs. The free plan includes 1,000 screenshots a month without a card; paid plans start at $5 for 3,000 screenshots. Sign up for 1,000 free screenshots a month with no card.
9. FAQ
How do I take a website screenshot with an API?
Send the target URL and capture settings to a screenshot service’s endpoint, authenticate with its API key, and save or decode the returned image. The cURL, Python, and Node.js requests above show ScreenshotAPI’s documented endpoint shape.
Is ScreenshotAPI free?
The pricing page advertises a free allowance, but conflicts between 100 and 1,000 shots. Verify the amount in the signup flow or account dashboard before relying on it.
Can I use ScreenshotAPI from India?
The published materials reviewed do not confirm or rule out India-specific availability or payment support. Check the signup and checkout flow, tax treatment, and any requirements for your organization.
Does ScreenshotAPI support GIF?
The homepage and pricing FAQ advertise GIF, while the endpoint reference lists PNG and JPEG. Confirm support for the endpoint and account you plan to use.
Can it capture HTML without a public URL?
The API reference documents raw HTML as an alternative to loading a URL, and also lists Markdown input. Review the endpoint’s current request schema for the exact payload you need.
