How to Capture a Webpage Screenshot with an API in India
Send a URL to a browser-rendering API, configure the capture, and save the image. Learn how to handle India-specific region, privacy, and reliability requirements.
To capture a webpage screenshot with an API, send the target URL and authentication to a browser-rendering service, choose the viewport, format, and wait behavior, then save the returned image bytes. The capture runs wherever that service runs. An application making the request from India does not establish that the browser or stored image is in India.
This guide uses Cloudflare Browser Rendering as a documented do-it-yourself example. Its REST screenshot endpoint accepts a URL or HTML, renders HTML and JavaScript, and supports options such as full-page capture, viewport, output type, and wait conditions. Check the Cloudflare screenshot endpoint documentation for the current request contract and limits.
1. Decide what “in India” means for your screenshot workflow
“Use an API in India” can describe different requirements. Decide which one you mean before selecting a provider:
- Your application runs in India: the caller is hosted or operated in India. This alone says nothing about the remote browser or image storage.
- The target page should see an Indian visitor: the browser’s egress location may affect geolocation, regional content, pricing, language, or access controls.
- The browser must execute in India: the service must confirm the execution region for your account and request type.
- Screenshot data must be processed or stored in India: confirm the browser location, intermediate processing, storage region, retention period, and any subprocessors with the vendor.
AWS documents the Asia Pacific (Mumbai) Region and says customers choose the AWS region where they store content. That describes AWS-hosted content; it does not show that an independent screenshot API uses Mumbai. Ask the screenshot provider for its own region and retention details. See AWS India data protection information.
If screenshots may include personal data, review the service’s processing terms, access controls, retention, and actual processing location for your use case. India’s Press Information Bureau announced the DPDP Rules, 2025 on 14 November 2025; this is a technical guide, not a legal compliance determination. See the PIB announcement. For government websites, also check the applicable GIGW scope and objectives; that guidance concerns government organizations, not every private website.
2. Configure credentials and a safe request
Create an API token with the permission the provider requires. For Cloudflare’s REST endpoint, the documented permission is Browser Rendering Write. Keep the token on a server, in a secret manager or environment variable. Do not embed it in browser JavaScript, commit it to source control, or log authorization headers.
For repeatable captures, fix the target URL, viewport, output format, and wait strategy. Encode URL query strings using a JSON library or URL encoder rather than assembling a request string by hand.
3. Capture a screenshot with Cloudflare Browser Rendering
The following examples send a URL and request a full-page PNG. Set the account ID and token in your environment. The endpoint returns screenshot content; --output saves it as a file.
cURL
export CF_ACCOUNT_ID="YOUR_ACCOUNT_ID"
export CF_API_TOKEN="YOUR_API_TOKEN"
curl --fail-with-body --silent --show-error \
"https://api.cloudflare.com/client/v4/accounts/${CF_ACCOUNT_ID}/browser-rendering/screenshot" \
-H "Authorization: Bearer ${CF_API_TOKEN}" \
-H "Content-Type: application/json" \
--data '{
"url": "https://example.com",
"screenshotOptions": {
"type": "png",
"fullPage": true,
"viewport": { "width": 1440, "height": 900 }
}
}' \
--output screenshot.png
See the ScreenshotNeo docs for ScreenshotNeo API options and the Cloudflare endpoint docs above for Cloudflare request details.
Python
import os
import requests
account_id = os.environ["CF_ACCOUNT_ID"]
token = os.environ["CF_API_TOKEN"]
endpoint = (
f"https://api.cloudflare.com/client/v4/accounts/{account_id}"
"/browser-rendering/screenshot"
)
payload = {
"url": "https://example.com",
"screenshotOptions": {
"type": "png",
"fullPage": True,
"viewport": {"width": 1440, "height": 900},
},
}
with requests.post(
endpoint,
headers={"Authorization": f"Bearer {token}"},
json=payload,
timeout=120,
stream=True,
) as response:
response.raise_for_status()
with open("screenshot.png", "wb") as image_file:
for chunk in response.iter_content(chunk_size=1024 * 64):
if chunk:
image_file.write(chunk)
Node.js
import { createWriteStream } from "node:fs";
import { pipeline } from "node:stream/promises";
const accountId = process.env.CF_ACCOUNT_ID;
const token = process.env.CF_API_TOKEN;
if (!accountId || !token) throw new Error("Set CF_ACCOUNT_ID and CF_API_TOKEN");
const endpoint = `https://api.cloudflare.com/client/v4/accounts/${accountId}/browser-rendering/screenshot`;
const response = await fetch(endpoint, {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
url: "https://example.com",
screenshotOptions: {
type: "png",
fullPage: true,
viewport: { width: 1440, height: 900 },
},
}),
signal: AbortSignal.timeout(120_000),
});
if (!response.ok) {
throw new Error(`Screenshot request failed: ${response.status} ${await response.text()}`);
}
await pipeline(response.body, createWriteStream("screenshot.png"));
The examples use a full-page capture. For a quick preview, set fullPage to false. In production, also validate the response content type and image format before treating a response as a successful capture.
4. Choose capture options that match the page
| Choice | When to use it | Things to check |
|---|---|---|
| Viewport or full page | Viewport for previews and above-the-fold checks; full page for reports or page audits. | Long or endless pages can produce very tall images and higher processing or transfer cost. Sticky headers and lazy-loaded sections can affect results. |
| Viewport dimensions | Match a target desktop or mobile layout. | Responsive breakpoints change layout. Record width and height with each capture so comparisons are meaningful. |
| Image type | PNG for crisp text and visual comparison; JPEG or WebP when supported and smaller files matter. | Confirm the chosen format is supported by the endpoint and your downstream image tools. |
| Wait behavior | Wait for a known selector or page state when content appears after initial navigation. | Choose a condition tied to the required content. A long fixed delay increases latency without guaranteeing readiness. |
| Clip or selector | Capture a region when the workflow needs a component instead of the whole page. | Check selector existence, dimensions, and whether the element is inside a frame or shadow root. |
| HTML input | Render a known HTML fragment or generated document rather than navigating to a URL. | Relative assets and scripts may need absolute URLs or explicit setup. |
Cloudflare documents controls including url or html, viewport, fullPage, clip, selector, output type, quality, background handling, JavaScript, extra HTTP headers, navigation settings, and wait options. Not every provider exposes the same controls or names. Read the current endpoint schema before relying on an option.
5. Make captures reliable in automated jobs
- Use deterministic inputs. Fix viewport, locale or timezone when available, target URL, and capture options. Avoid depending on changing ads, feeds, or personalized content in visual regression runs.
- Wait for the content you need. Prefer a meaningful selector or readiness signal over an arbitrary sleep. Some pages report navigation complete before client-side rendering finishes.
- Set finite timeouts. Bound connection and total request time. Keep timeout limits aligned with your queue and user-facing latency budget.
- Retry selectively. A transient network or provider error may merit a retry with backoff. Do not blindly retry authentication failures, invalid URLs, or pages that consistently block automation.
- Make job processing idempotent. If a client retries after a network interruption, avoid creating duplicate downstream records. Use a stable job identifier if the provider supports one.
- Check outputs. Verify HTTP status, content type, and that the saved file is non-empty and decodable. A response body may contain structured error details rather than image bytes.
- Keep sensitive captures private. Avoid public result URLs for pages containing private information. Set retention and access policies appropriate to the data.
For bulk workflows, bound concurrency to the provider’s documented limits, queue work during spikes, and monitor failures by status and target domain. A successful HTTP request does not prove the screenshot shows the intended state; inspect representative outputs and track capture quality.
6. India-specific deployment and privacy checklist
- Ask where the rendering browser executes for your account and whether you can select an Indian region.
- Ask where screenshots, logs, and temporary files are processed and stored, and how long they persist.
- Determine whether the target site must be reached from an Indian IP address. Verify this with the vendor rather than inferring it from your application’s location.
- Check whether the target page includes personal, account, health, financial, or otherwise confidential information. Minimize capture scope and avoid sending secrets in URLs.
- Confirm how credentials, custom headers, cookies, and returned image URLs are protected.
- Test regional content and access behavior from the actual capture environment. Language, consent prompts, bot challenges, and content can vary by location.
- For government site work, determine the applicable GIGW requirements within their stated government scope.
7. Performance, reliability, and cost
Every capture requires remote page loading and rendering, so total time depends on page complexity, network behavior, scripts, assets, and the chosen wait condition. Full-page images contain more pixels than viewport captures; larger output can take longer to produce, transfer, store, and compare. Limit image dimensions and concurrency to what the workflow needs.
Estimate spend using your expected capture volume, provider pricing, and the actual billable-event definition. Compare included quotas, rate limits, full-page or format restrictions, caching behavior, async and batch support, result retention, and overage terms. The reviewed provider documentation does not establish comparable current pricing or service-level guarantees across vendors, so verify those terms directly before launch.
For reliability, capture and log request IDs where available, response status, elapsed time, output dimensions, and provider error details. Avoid logging tokens, cookies, or screenshot contents. Keep a small set of representative pages for smoke checks and re-run them after changing the URL, viewport, wait logic, or provider configuration.
8. Troubleshooting common screenshot API errors
| Symptom | Likely cause | Fix |
|---|---|---|
| 401 or 403 response | Missing, invalid, expired, or insufficiently privileged token. | Check the authorization header, token scope, account ID, and required Browser Rendering permission. Keep secrets out of source and logs. |
| 400 response | Malformed JSON, missing URL/HTML, invalid option, or incorrectly typed value. | Validate JSON and compare each field with the provider’s current schema. Send either the documented URL or HTML input. |
| Timeout | Slow navigation, blocked assets, heavy scripts, or a wait condition that never becomes true. | Use a more targeted readiness condition, review navigation behavior, and set a finite action timeout. Do not just increase the timeout indefinitely. |
| Screenshot is blank or incomplete | Capture occurred before client rendering, an app requires interaction, or content is lazy-loaded. | Wait for a content-specific selector or supported readiness signal; check whether the page requires a session or user action. |
| Wrong regional content | The browser’s egress location, language, cookies, or account session differs from the intended visitor. | Confirm the provider’s execution geography and configure supported locale, timezone, headers, or cookies. Test from the real capture environment. |
| Bot check or CAPTCHA | The target site challenges automated or remote browsers. | Do not assume an API can bypass the challenge. Use an authorized access path or obtain permission from the site owner. |
| Output file is JSON or unreadable | The endpoint returned an error response, but the client saved it as an image. | Check HTTP status and content type before saving; surface the response body as an error. |
| Image differs between runs | Dynamic content, animation, ads, fonts, timestamps, or responsive layout changed. | Stabilize the page where possible, use fixed dimensions and waits, and mask or exclude volatile regions in downstream comparisons. |
9. Or skip the browser setup
ScreenshotNeo turns a URL into a PNG, JPEG, WebP, or PDF with one GET request. It is a website screenshot API and MCP server for developers, made by Yorker Media. Its clean-capture steps accept cookie or consent banners like a visitor and remove 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 and MCP clients.
One cURL request:
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 import('node:fs/promises').then(({ writeFile }) => writeFile('shot.webp', Buffer.from(await res.arrayBuffer())));
See the ScreenshotNeo API documentation for authentication and options. Its 63 options include full-page capture with lazy images loaded, CSS-selector element capture, dark mode, 12 device presets or a custom viewport, retina scale, PDF page settings, custom CSS and JavaScript, click and hide selectors, selector/delay/network-idle waits, request and resource blocking, custom headers, cookies, user agent and authorization, timezone and geolocation, transparent backgrounds, resizing, configurable cache TTL, signed image links, async jobs with signed webhooks, bulk capture of 100 URLs per call, a usage API, and an OpenAPI spec. Parameter names used by other screenshot APIs also work to make switching easier.
There is no card requirement for 1,000 screenshots per month. Paid plans start at $5 for 3,000; higher plans are $15 for 15,000, $39 for 60,000, $99 for 250,000, and $249 for 1,000,000. Yearly billing gives two months free, and every feature is on every plan. Check whether the service meets your execution-region and data-residency needs directly; the product facts here do not establish an India-region guarantee. Learn about ScreenshotNeo.
Sign up for free and get 1,000 screenshots a month with no card.
10. FAQ
Can an API screenshot a page that requires login?
Sometimes, if the provider supports sending the required cookies or headers and the site permits the access. Treat session credentials as secrets, and confirm the vendor’s handling and retention before sending them.
Does a full-page screenshot include content loaded only after scrolling?
Not necessarily. Full-page capture describes the image extent; lazy-loaded content may need scrolling or a provider-supported lazy-image behavior before capture.
Can I use a screenshot API for visual regression testing?
Yes. Keep the browser dimensions and capture state consistent, then account for changing content and rendering differences in your comparison process.
Does an API request from India guarantee Indian data residency?
No. Caller location, browser execution, image processing, and storage are separate locations. Confirm each with the provider.


