How to Generate Product Page Screenshots with a Screenshot API for an Indian Online Store
Capture Indian ecommerce product pages with the right viewport, locale, and wait conditions. Includes runnable API and Playwright examples, troubleshooting, and scaling guidance.
To generate product page screenshots for an Indian online store, send the product URL to a screenshot API, set the viewport and output format, and wait for a page element that confirms the product has rendered. For a mobile storefront view, use a mobile preset or mobile viewport; set language, timezone, or location only when relevant, then inspect the actual result because those settings do not guarantee that a store will localize its page.
This guide shows a self-managed Playwright option and a hosted API option, including runnable cURL, Python, and Node.js calls. It also covers full-page captures, India-oriented rendering, batching, failure handling, and repeatable validation.
1. Decide what the screenshot needs to show
Before choosing a capture method, define the intended evidence or asset. A catalog thumbnail may need only the product image and title; a QA record may need the price, variant selector, stock status, delivery message, and viewport context. Capture a representative product URL first and check the image before automating a catalog.
| Decision | Practical starting point |
|---|---|
| Page input | A publicly reachable product URL. Use supplied HTML only when you control the template and do not need the live store page. |
| Viewport | Use a mobile preset or mobile dimensions to represent a phone; use a desktop viewport for desktop review. |
| Capture area | Viewport for the first screen; full page when below-the-fold content matters. |
| Readiness | Wait for a product-specific selector such as the product title or gallery, rather than assuming navigation alone means the page is ready. |
| Locale | Set language, timezone, or geolocation only to match the test scenario, then verify what the store actually rendered. |
| Output | PNG for lossless detail; JPEG or WebP when smaller files suit the downstream use. |
A screenshot is a record of one rendered state. It does not prove that the displayed price, availability, or delivery promise applies to every shopper. Store personalization, location prompts, cookies, and selected variants can change what appears.
2. Use Playwright when you want to manage the browser
Playwright is a self-managed browser automation option. It gives your application control over navigation, viewport, interactions, waiting, and capture. You are responsible for installing and operating the browser runtime and handling your own queue, retries, and storage. The official Page API documentation describes screenshot options including full-page capture, image type, scale, masking, and screenshot styles.
Runnable Node.js example
Install Playwright and its Chromium browser in a Node.js project:
npm install playwright
npx playwright install chromium
Save this as capture-product.mjs. Replace the URL and selector with the product page and a selector that exists on that store. The script saves both viewport and full-page PNG files and closes the browser even if navigation or capture fails.
import { chromium } from 'playwright';
const url = process.argv[2] ?? 'https://example.com/product/example-item';
const browser = await chromium.launch({ headless: true });
try {
const context = await browser.newContext({
viewport: { width: 390, height: 844 },
deviceScaleFactor: 2,
isMobile: true,
hasTouch: true,
locale: 'en-IN',
timezoneId: 'Asia/Kolkata'
});
const page = await context.newPage();
await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 45000 });
await page.locator('h1').first().waitFor({ state: 'visible', timeout: 20000 });
await page.screenshot({ path: 'product-mobile.png', type: 'png' });
await page.screenshot({ path: 'product-full.png', type: 'png', fullPage: true });
} finally {
await browser.close();
}
Run it with node capture-product.mjs https://store.example/products/item. The sample uses h1 as a simple readiness condition; real stores may require a more specific title, price, or gallery selector. If the page hydrates asynchronously, wait for the relevant selector and, where needed, a short bounded delay after it appears.
Playwright choices that affect the result
- Viewport and device emulation: configure width and height in CSS pixels. Set mobile mode and touch when the mobile layout or interactions depend on them. A device scale factor of 2 produces a higher pixel-density image and a larger file.
- Wait condition:
domcontentloadedcan return before client-rendered product details appear. Waiting for a visible product selector is more specific. Network-idle waits can be unsuitable for pages with ongoing analytics or long polling; use the condition that reflects page readiness. - Full-page capture:
fullPage: truecaptures the scrollable document. Lazy-loaded images may not load merely because the final image is tall; scroll the page in steps and wait for images or content when that is required. - Image settings: Playwright supports PNG, JPEG, and WebP screenshot types, with quality settings for lossy formats. Its
scaleoption chooses CSS-pixel or device-pixel output. - Masking and styles: screenshot options can mask selected locators or apply a stylesheet for repeatable captures. Masking obscures data; it is not a substitute for access controls or safe storage.
- Cookies and interaction: create a context with the cookies or authentication your authorized test requires, and perform variant selection or consent actions before capture. Do not include secrets in saved logs or public screenshot URLs.
For a page where the product must be selected before capture, use a locator action before the screenshot. For example, click a known color swatch, then wait for the selected state or updated image. Avoid assuming the first variant is the desired one.
3. Choose India-oriented rendering deliberately
“Indian audience” can mean a mobile viewport, an Indian language preference, India-local time, or a location-sensitive delivery and inventory view. These are separate inputs. Configure only the ones needed for the test, and record them with the screenshot so another person can reproduce the scenario.
- Language: send an
Accept-Languagepreference such asen-INif the site uses request language negotiation. A language header does not force a store to translate its interface. - Timezone: use the IANA timezone
Asia/Kolkataif time-dependent content should reflect Indian Standard Time. - Geolocation: provide latitude and longitude only when the page uses browser geolocation. It does not change the visitor’s network location or guarantee that a store will accept the coordinates.
- Currency and delivery: verify the rendered price, currency, delivery estimate, and product availability on the actual page. Locale parameters do not prove that the store will show INR or an India-specific shipping promise.
- Consent and personalization: decide whether the screenshot should show the consent prompt, a post-consent view, or a clean page with common overlays removed. Keep this consistent across captures.
Use the same URL, viewport, language, timezone, cookies, and interaction sequence when comparing screenshots over time. Otherwise, a difference may reflect capture context rather than a store change.
4. Capture a product page with ScreenshotNeo
ScreenshotNeo is a managed website screenshot API and MCP server. Its API documentation describes URL or HTML input and PNG, JPEG, WebP, and PDF output. A GET request is enough for a basic URL capture; add parameters for viewport, readiness, full-page output, or regional context.
cURL: mobile product screenshot
This request captures a mobile-sized WebP after the product title selector appears. Substitute your API key, target URL, and selector as appropriate.
curl -G "https://api.screenshotneo.com/v1/shot" \
-d access_key=YOUR_API_KEY \
--data-urlencode url=https://store.example/products/item \
-d format=webp \
-d width=390 \
-d height=844 \
-d mobile=true \
-d touch=true \
-d scale=2 \
-d accept_language=en-IN \
-d timezone=Asia/Kolkata \
--data-urlencode 'wait_for=h1' \
-o product.webp
Python: save the returned image
import requests
url = 'https://store.example/products/item'
params = {
'access_key': 'YOUR_API_KEY',
'url': url,
'format': 'webp',
'width': 390,
'height': 844,
'mobile': 'true',
'touch': 'true',
'scale': 2,
'accept_language': 'en-IN',
'timezone': 'Asia/Kolkata',
'wait_for': 'h1',
}
response = requests.get(
'https://api.screenshotneo.com/v1/shot', params=params, timeout=90
)
response.raise_for_status()
content_type = response.headers.get('Content-Type', '')
if not content_type.startswith('image/'):
raise RuntimeError(f'Expected an image, received {content_type!r}')
with open('product.webp', 'wb') as image_file:
image_file.write(response.content)
print('verdict:', response.headers.get('X-Page-Verdict'))
print('billed:', response.headers.get('X-Billed'))
Node.js: save the returned image
import { writeFile } from 'node:fs/promises';
const q = new URLSearchParams({
access_key: 'YOUR_API_KEY',
url: 'https://store.example/products/item',
format: 'webp',
width: '390',
height: '844',
mobile: 'true',
touch: 'true',
scale: '2',
accept_language: 'en-IN',
timezone: 'Asia/Kolkata',
wait_for: 'h1'
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot API returned HTTP ${res.status}`);
const contentType = res.headers.get('content-type') ?? '';
if (!contentType.startsWith('image/')) {
throw new Error(`Expected an image, received ${contentType}`);
}
await writeFile('product.webp', Buffer.from(await res.arrayBuffer()));
console.log('verdict:', res.headers.get('x-page-verdict'));
console.log('billed:', res.headers.get('x-billed'));
The API accepts aliases for several familiar parameter names; consult the docs for the accepted names and bounds. For example, viewport width and height can also be expressed as viewport_width and viewport_height, and wait_for is an alias for wait_for_selector.
Useful capture options
| Need | Parameters or approach | Things to check |
|---|---|---|
| Whole product page | full_page=true; scrolling before capture is enabled with full-page scrolling. |
Very long pages can be capped with full_page_max_height. Check that lazy images and below-the-fold sections loaded. |
| Only the product card or gallery | selector with a CSS selector. |
The selector must exist and match the intended element. A missing selector is a capture failure rather than a useful partial image. |
| Wait for dynamic product data | wait_for / wait_for_selector, wait_until, optional delay. |
Prefer a meaningful selector. A delay alone is less reliable and adds time to every capture. |
| Use a device preset | device preset or explicit width, height, mobile, touch, and scale. |
Viewport dimensions affect responsive layout. Retina scale increases output pixels and file size. |
| Hide a page element or inject CSS | hide_selectors or custom styles. |
Use only for deliberate presentation or test normalization; do not hide content that the capture is meant to verify. |
| Choose page state | click, cookies, headers, authorization, or scripts where required. |
Use only authorized access. Treat keys, cookies, and private page data as secrets. |
| Block unwanted requests | Block matching request patterns or resource types. | Blocking images, scripts, or stylesheets can remove the very product content under review. |
| Repeat captures efficiently | Cache with a chosen TTL, or use asynchronous jobs and bulk capture. | A cache hit is useful for previews but unsuitable when you require a fresh visual record. |
ScreenshotNeo documents 12 device presets, full-page capture, element capture, PDF, HTML-to-image, CSS and JavaScript injection, request controls, signed links, asynchronous jobs, and bulk capture of up to 100 URLs per request. See the parameter reference for exact names, ranges, and endpoint behavior.
5. Validate one page before capturing a catalog
- Pick representative pages: include a short title, a long title, multiple images, a product with variants, and a page with below-the-fold details.
- Set the scenario: record URL, viewport dimensions, scale, locale, timezone, cookies, and any variant or consent interaction.
- Choose a readiness signal: wait for the product title, price, or gallery rather than a generic navigation event alone.
- Inspect the output: verify the intended product, correct price and variant, loaded images, no accidental overlays, and expected page length.
- Check file properties: confirm format, pixel dimensions, and file size against the system that will display or store it.
- Repeat the capture: determine whether differences come from animation, rotating promotions, personalization, or actual page changes.
- Scale gradually: begin with a small batch, track failures and response headers, then expand concurrency within the service’s documented limits.
For comparison or audit work, keep a manifest next to the image with the capture timestamp, source URL, viewport, locale, variant, output format, and whether the result came from cache. Avoid treating a cache-served image as evidence of the current page state.
6. Batch capture and operational considerations
For a few pages or interactive scenarios, synchronous requests are straightforward. For a large catalog, a single long-running request can tie up a worker and make retries awkward. ScreenshotNeo documents bulk capture for up to 100 URLs per call, asynchronous jobs with polling, and signed webhook delivery. Treat each URL as an independently fallible job and retain its URL and result status in your own manifest.
- Rate and concurrency: respect the current plan’s per-minute and concurrent-render limits. Use a bounded queue rather than launching every product URL at once. The pricing page lists limits and explains that excess requests can receive HTTP 429.
- Retries: retry transient network and rate-limit failures with backoff, honoring
Retry-Afterwhere supplied. Do not retry permanent invalid-URL or selector errors without changing the request. - Idempotency: identify each capture by normalized URL plus capture settings. A changed viewport or locale is a different desired artifact.
- Storage: store images only as long as the workflow requires, restrict access, and avoid embedding keys or private customer data in filenames or logs.
- Freshness: cache when repeated identical previews are acceptable. Request a fresh capture for monitoring or time-sensitive comparisons.
- Cost: estimate clean captures per month, including recaptures and the number of viewport variants. ScreenshotNeo lists Free at 1,000 per month with no card; Starter is $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. Prices are in USD; the dossier does not establish an India-specific final INR charge.
ScreenshotNeo says only clean shots are billed; bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing. Responses include X-Page-Verdict and X-Billed headers so a pipeline can distinguish a useful image from a failed or unbilled result. Review the API response and plan details in the pricing information before estimating production cost.
7. Troubleshooting common problems
| Symptom | Likely cause | Fix |
|---|---|---|
| The title or price is missing | Capture happened before client rendering, or the selector does not match this store’s markup. | Inspect the page DOM, use a product-specific selector that becomes visible, and allow a bounded wait. Test multiple product templates. |
| Product images are blank in a full-page shot | Images load lazily, require scrolling, or are served from a delayed image endpoint. | Enable full-page scrolling or explicitly scroll in Playwright; wait for the relevant image to load and confirm the source is reachable. |
| The page is in the wrong language or currency | The store ignores the language header, uses a saved cookie, IP-derived region, account setting, or a location prompt. | Set the intended supported context, clear or supply the right cookies, and verify the rendered currency and language. Do not assume a locale parameter forces localization. |
| Delivery details differ from the intended city | The store needs a postal code, address, consent, or an explicit delivery-location interaction; browser geolocation alone is not enough. | Reproduce the store’s actual supported selection flow, if authorized, and record the selected location in the capture metadata. |
| A cookie banner, popup, or chat widget covers the product | The overlay is part of the current page state or was not handled by the capture workflow. | For a clean view, use the API’s overlay handling or hide a known selector; for consent QA, deliberately preserve the prompt. Check that removing an overlay does not discard relevant evidence. |
| The image is the wrong size or layout | Viewport, mobile mode, or device scale differs from the intended scenario. | Set explicit viewport dimensions and mobile/touch behavior; inspect pixel dimensions separately from CSS viewport dimensions. |
| The result is unexpectedly old | A cached response was returned. | Disable or bypass caching, or use a suitable TTL for the task. Check cache-related response information before treating it as current. |
| HTTP 429 / rate limit | Request rate or simultaneous renders exceeded the plan’s limits. | Reduce concurrency, queue work, wait according to response guidance, and use async or bulk workflows for larger jobs. |
| HTTP 402 / quota reached | The account reached its monthly clean-shot quota. | Check usage and reset timing, reduce unnecessary recaptures, or change the plan. |
| Timeout or failed load | The page is slow, blocked, unstable, or never reached the requested readiness condition. | Use a suitable timeout, inspect the target URL independently, simplify the wait condition, and retry only transient cases. A longer timeout cannot fix a selector that never exists. |
| Saved file is not an image | The response may contain an API error instead of image bytes, or the client saved an HTTP error body. | Check HTTP status and Content-Type before writing the body; log a concise error response safely and do not label it as an image. |
| Playwright full-page capture is too tall | The product page has a long recommendation feed or effectively endless content. | Capture a selector or viewport, or define a controlled scroll region and height. Avoid using full-page output when the entire feed is irrelevant. |
8. Or skip the browser setup
With ScreenshotNeo, one GET request captures a product URL; the docs list the viewport, wait, format, and locale parameters.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
Cookie banners, popups, and chat widgets are removed before the shot. Bot checks, blank pages, and failed loads are never billed. An MCP server lets AI agents take screenshots. 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.
9. FAQ
Should I use a mobile preset or specify dimensions?
Use a preset when it matches the device scenario you need. Specify dimensions and mobile behavior directly when you need a reproducible custom viewport. In either case, record the settings because responsive breakpoints change the rendered page.
Can an API screenshot prove what every Indian shopper sees?
No. It documents one URL and one capture context. Account state, cookies, selected location, inventory, and personalization can change the page for another shopper.
Is a full-page screenshot always better for a product listing?
No. It can include irrelevant recommendations and make comparisons harder. Capture the viewport or a product element when that is the actual requirement; use full-page output for content whose below-the-fold state matters.
What should I record alongside a screenshot?
At minimum, save the source URL, capture time, viewport, output format, locale or location context, selected variant, and whether the result was cached. That context makes later review more useful.
Sources: ScreenshotNeo API documentation, ScreenshotNeo pricing, and Playwright Page API.


