How to Capture a Playwright Screenshot of an Indian Ecommerce Product Page
Capture an ecommerce product page with Playwright using an India-oriented browser context, reliable content waits, and viewport, full-page, or element screenshots.
Use Playwright’s page.screenshot() after navigating to the product page and waiting for the content you need to appear. Set a fixed viewport and, when appropriate, an India-oriented locale (en-IN) and timezone (Asia/Kolkata). Those browser settings do not guarantee that a retailer will show an India-specific price, currency, or delivery location: the site may require its own location selector, account setting, cookie, or postal code.
The examples below use placeholder URLs and product selectors. Replace them with the product page and a locator that matches its actual markup. Playwright’s screenshot guide documents page and element screenshots; its Page API describes screenshot options.
1. Install Playwright and choose a browser
This walkthrough uses JavaScript with Chromium. In a new project, install Playwright and its browser:
npm init -y
npm install playwright
npx playwright install chromium
Save the script below as screenshot-product.mjs and run it with node screenshot-product.mjs. Use a URL you are authorized to access, and follow the retailer’s terms and applicable policies.
2. Capture the product page with an India-oriented context
This runnable example waits for a product heading, then saves a viewport screenshot. The heading locator is intentionally generic: adapt it to the page’s accessible name or stable test attribute.
import { chromium } from 'playwright';
const url = 'https://example.in/product-page';
const browser = await chromium.launch();
try {
const context = await browser.newContext({
viewport: { width: 1365, height: 900 },
locale: 'en-IN',
timezoneId: 'Asia/Kolkata',
});
const page = await context.newPage();
await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 45_000 });
// Replace this accessible name pattern with the real product title or locator.
await page.getByRole('heading', { name: /product name/i })
.waitFor({ state: 'visible', timeout: 20_000 });
await page.screenshot({ path: 'product-page.png' });
await context.close();
} finally {
await browser.close();
}
page.screenshot() captures the current viewport by default. The explicit try/finally ensures the browser is closed even if navigation or capture fails.
3. Pick the screenshot scope
Current viewport
Use the basic call when the visible product summary is all you need:
await page.screenshot({ path: 'product-page.png' });
Full scrollable page
Set fullPage: true to capture the full document rather than only the visible viewport:
await page.screenshot({ path: 'product-page-full.png', fullPage: true });
Long product pages can produce very tall images and may take longer to render or process. If only the details panel matters, an element screenshot can be smaller and easier to compare.
One product element
Use a stable locator for the product details, gallery, or price panel. This selector is an example, not a claim about any particular retailer’s HTML:
const details = page.locator('[data-testid="product-details"]');
await details.waitFor({ state: 'visible' });
await details.screenshot({ path: 'product-details.png' });
An element screenshot captures the element’s rendered area; for a scrollable element, the screenshot may show only the portion currently in view. Scroll the element or its container to the desired position before capture if necessary.
4. Configure locale, timezone, device size, and location
Browser context options let you set viewport, locale, timezone, and device parameters. Use settings that match the rendering you are trying to reproduce, and keep them fixed when comparing screenshots. See Playwright’s emulation guide and browser context API.
| Setting | Example | What it affects |
|---|---|---|
| Viewport | { width: 1365, height: 900 } |
Available page layout area and responsive breakpoints. |
| Locale | en-IN |
Browser locale signals and locale-sensitive page behavior. |
| Timezone | Asia/Kolkata |
Timezone used by browser date and time behavior. |
| Geolocation | Coordinates for the test location | Browser location, only if the page uses it and permission is granted. |
| Device profile | A Playwright device descriptor | Device-related settings; use a device profile when mobile rendering is the target. |
For browser geolocation, provide coordinates and grant permission for the target origin. Choose coordinates relevant to the test; none are supplied here because the right location depends on the task.
const context = await browser.newContext({
viewport: { width: 1365, height: 900 },
locale: 'en-IN',
timezoneId: 'Asia/Kolkata',
geolocation: { latitude: 19.0760, longitude: 72.8777 },
permissions: ['geolocation'],
});
The coordinates above are an example location in Mumbai, not a default for all India-oriented captures. Browser geolocation is separate from a merchant’s delivery location. If the page depends on a pincode or saved address, set it using the site’s own supported flow and verify the resulting page state.
5. Wait for the content that belongs in the image
A successful navigation does not mean that product details, images, or price have finished rendering. Wait for a meaningful page-specific signal, such as the product title or main image, before taking the screenshot.
await page.goto(url, { waitUntil: 'domcontentloaded' });
await page.getByRole('heading', { name: /product name/i })
.waitFor({ state: 'visible' });
await page.screenshot({ path: 'product-page.png' });
Playwright discourages using networkidle as a universal readiness condition. Ecommerce pages can keep analytics, recommendations, or other connections active. Prefer an assertion or locator that corresponds to the content you need; see the navigation API for navigation wait options.
For lazy-loaded images, scroll the relevant area into view and wait for the image to load before capture. The exact condition is page-specific:
const mainImage = page.locator('[data-testid="main-product-image"]');
await mainImage.scrollIntoViewIfNeeded();
await mainImage.waitFor({ state: 'visible' });
await page.waitForFunction((selector) => {
const image = document.querySelector(selector);
return image instanceof HTMLImageElement && image.complete && image.naturalWidth > 0;
}, '[data-testid="main-product-image"]');
await page.screenshot({ path: 'product-page.png' });
Replace the selector with the actual image element. If the image is rendered as a CSS background or inside a gallery component, use a readiness check that matches that implementation.
6. Make captures easier to reproduce
- Keep the URL, browser engine, viewport, locale, timezone, and capture scope constant.
- Record whether the page used a logged-in account, cookies, selected pincode, or another location setting.
- Wait for the same product title, image, or other page state each run.
- Disable animations in the screenshot options when motion makes the captured frame inconsistent.
- Record the capture time if prices, stock, or promotions may change.
await page.screenshot({
path: 'product-page.png',
animations: 'disabled',
});
Playwright supports screenshot output options such as format, quality where applicable, animation handling, and full-page capture. Check the screenshot API for the options supported by your installed version. Use a PNG for lossless visual comparisons; JPEG or WebP can reduce file size when your workflow accepts lossy output.
7. Troubleshoot common capture problems
| Symptom | Likely cause | Fix |
|---|---|---|
| Heading wait times out | The placeholder name or selector does not match, the page has not reached that state, or the product is unavailable. | Inspect the actual accessible heading and page state; choose a stable locator and handle unavailable-product states explicitly. |
| Screenshot shows a loading shell | Navigation finished before the product content rendered. | Wait for a product-specific locator or image readiness condition rather than relying on navigation alone. |
| Wrong currency, price, or delivery region | Locale or geolocation did not set the merchant’s delivery location; the site may use a pincode, cookie, or account preference. | Set location through the retailer’s own flow and verify the displayed state before capture. |
| Product image is missing | The image is lazy-loaded, blocked, or not yet complete. | Scroll it into view, wait for its load state, and check for access restrictions or failed requests. |
| Full-page screenshot is unexpectedly tall | The page includes long reviews, recommendations, or other content below the product. | Capture a stable product element or viewport, or use a page-specific clip if only a region is needed. |
| Mobile layout differs between runs | Viewport or device settings differ, or page state is not consistent. | Use the same viewport or device profile, locale, timezone, and page readiness condition every time. |
| Browser launch fails | The Playwright browser binary may not be installed for the package version. | Run npx playwright install chromium and check the installation instructions for your operating system. |
8. Performance, reliability, and cost
Playwright runs a browser process, so startup, page loading, image rendering, and full-page capture all contribute to runtime. Reuse a browser for multiple pages in a controlled job when appropriate, while giving each independent capture its own page or context as needed. Keep timeouts finite and close contexts and browsers in cleanup code.
Reliability depends on the target site and its state: network conditions, changing product availability, consent dialogs, bot checks, login requirements, and dynamic content can all change the result. A screenshot that saved successfully is not proof that it contains the intended product state. Check a meaningful locator and, for automated workflows, validate the output or record page state alongside it.
Playwright is open-source software; the capture itself does not have a per-screenshot ScreenshotNeo fee. Your operating costs come from the machine, browser runtime, storage, and network usage. Hosted browser infrastructure or other services may have separate charges.
9. Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server for developers. Its API takes a URL and returns an image or PDF. The call below uses the documented pattern; replace the URL and API key. See the ScreenshotNeo API 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://example.in/product-page -o shot.webp
Python
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://example.in/product-page"},
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.in/product-page',
});
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())));
ScreenshotNeo removes cookie banners, newsletter popups, and chat widgets before capture; bot checks, blank pages, failed loads, and cache hits are not billed. Its 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 required.
10. Frequently asked questions
Will en-IN make every retailer show Indian rupees?
No. It sets a browser locale signal. A retailer can choose currency and delivery options from its own account, cookie, or location controls.
Should I use geolocation or set a pincode?
Use browser geolocation only when the page asks for browser location. Use the retailer’s own location flow when delivery eligibility or pricing depends on a postal code.
What should I save to compare screenshots later?
Save the URL, time, browser engine, viewport or device profile, locale, timezone, location state, and whether you captured the viewport, full page, or an element.


