How to Capture Screenshots of an Indian Ecommerce Website with Playwright
Capture an Indian ecommerce page with Playwright as a viewport, full-page image, or individual element, with practical device, locale, and troubleshooting guidance.
Use Playwright’s page.screenshot() after navigating to the ecommerce page. It captures the visible viewport by default. Set fullPage: true to capture the scrollable page, or use locator.screenshot() to capture one element such as a product card. Playwright can emulate a mobile device and configure browser locale and timezone, but those settings do not establish a visitor’s physical location in India or guarantee the site will render identically to a real phone.
1. Install Playwright and prepare a capture script
The examples use Node.js and Playwright’s library API. In a new project, install Playwright and its Chromium browser:
npm init -y
npm install playwright
npx playwright install chromium
Save the following as capture.mjs. Replace the example URL with the page you are authorized to capture. It writes a full-page PNG.
import { chromium } from 'playwright';
const url = process.argv[2] ?? 'https://example.com';
const browser = await chromium.launch();
try {
const page = await browser.newPage({
viewport: { width: 1440, height: 1000 },
});
await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 30_000 });
await page.screenshot({ path: 'page.png', fullPage: true });
} finally {
await browser.close();
}
Run it with node capture.mjs https://example.com. The sample demonstrates the documented API; it does not claim a particular Indian ecommerce site was tested. Check the chosen site’s current access terms and automation rules before automating it.
2. Choose viewport, full-page, or element capture
| Need | Playwright call | What it captures |
|---|---|---|
| Visible view | page.screenshot({ path: 'page.png' }) |
The current viewport. |
| Everything below the fold | page.screenshot({ path: 'page.png', fullPage: true }) |
The full scrollable page as a tall image. |
| One component | page.locator('selector').screenshot({ path: 'element.png' }) |
The selected element, such as a product tile or header. |
Viewport screenshot
Omit fullPage to capture the current viewport. Set the viewport before navigation when you want the page to lay out at the intended dimensions:
const page = await browser.newPage({ viewport: { width: 1365, height: 900 } });
await page.goto(url, { waitUntil: 'domcontentloaded' });
await page.screenshot({ path: 'viewport.png' });
Full-page screenshot
await page.screenshot({ path: 'full-page.png', fullPage: true });
A full-page capture is useful for a long listing or product detail page. It can create a very tall image and may not represent how a browser’s sticky or fixed elements look during ordinary scrolling. Pages that load content only when scrolled may need an explicit scroll-and-wait step before capture; see the reliability section.
Element screenshot
const product = page.locator('[data-testid="product-card"]').first();
await product.waitFor({ state: 'visible', timeout: 10_000 });
await product.screenshot({ path: 'product-card.png' });
Replace the selector with one that exists on the target site. A locator screenshot waits for the target to be actionable/visible according to the locator screenshot behavior; explicitly waiting makes the intended condition clear. If the page has no stable test ID, use a CSS selector grounded in the page’s current markup and verify it identifies the intended item.
3. Choose image format, scale, and clipping
Playwright supports PNG, JPEG, and WebP screenshots. The format can be inferred from the filename extension; choose an extension that matches the intended output. PNG is a sensible default for crisp interface text. JPEG or WebP can reduce file size, with image-quality tradeoffs for JPEG.
await page.screenshot({ path: 'page.webp', type: 'webp' });
await page.screenshot({ path: 'page.jpg', type: 'jpeg', quality: 80 });
quality applies to JPEG and WebP; it is an integer from 0 to 100. For pixel dimensions, scale: 'css' emits one output pixel per CSS pixel, while scale: 'device' uses device pixel density and can produce a larger image. A clip rectangle captures a precise page region:
await page.screenshot({
path: 'region.png',
clip: { x: 0, y: 0, width: 800, height: 600 },
scale: 'css',
});
Use clipping when a viewport-sized region is more useful than the entire page. The clip must describe a valid, non-empty rectangle within the page.
4. Capture a mobile or localized browser view
Playwright’s device registry provides presets for browser properties such as user agent, screen size, viewport, and touch support. A preset emulates browser settings; it does not prove the result matches a physical phone or a person located in India. Context options can also set locale and timezone. Choose values to represent the scenario you need to document.
import { chromium, devices } from 'playwright';
const browser = await chromium.launch();
try {
const context = await browser.newContext({
...devices['Pixel 7'],
locale: 'en-IN',
timezoneId: 'Asia/Kolkata',
});
const page = await context.newPage();
await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });
await page.screenshot({ path: 'mobile.png', fullPage: true });
} finally {
await browser.close();
}
Use a device preset from the installed Playwright version’s device registry, or specify a viewport directly. Locale and timezone configure browser behavior; they do not select a shipping address, currency, storefront, or account region on the ecommerce site. Those may depend on site state, cookies, account settings, or the URL.
5. Make captures more reliable on dynamic pages
Ecommerce pages can render content after initial navigation, load images lazily, or show consent and promotional overlays. Pick a readiness condition that matches what you need to capture rather than assuming navigation alone means the page is visually complete.
Wait for a useful page condition
await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 30_000 });
await page.locator('main').waitFor({ state: 'visible', timeout: 15_000 });
await page.screenshot({ path: 'page.png', fullPage: true });
Replace main with a selector present on the target. For a product detail page, waiting for a product title or image can be more meaningful than waiting for a generic container. Avoid treating a fixed sleep as proof that all content has loaded.
Scroll to trigger lazy-loaded content
Some pages request images or products as the reader scrolls. A full-page screenshot changes the capture area, but it does not guarantee every site’s scroll-triggered application logic has run. One practical approach is to scroll in increments, allow the page to update, then return to the top and capture:
await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 30_000 });
await page.locator('main').waitFor({ state: 'visible', timeout: 15_000 });
await page.evaluate(async () => {
const step = Math.max(400, window.innerHeight);
for (let y = 0; y < document.body.scrollHeight; y += step) {
window.scrollTo(0, y);
await new Promise(resolve => setTimeout(resolve, 150));
}
window.scrollTo(0, 0);
});
await page.screenshot({ path: 'full-page.png', fullPage: true });
The brief pauses are a site-dependent heuristic, not a guarantee. For repeatable work, wait for a known image or content selector and confirm that the page has finished updating.
Consent and overlays
A consent banner, newsletter modal, or chat panel may cover content. If the capture should show the site as presented to a visitor, interact with the banner only as appropriate for your purpose and the site’s rules. Do not silently bypass access controls or consent requirements. If you need a clean visual artifact without operating a browser, ScreenshotNeo’s capture flow accepts the consent banner like a visitor and removes 60+ known consent platforms, newsletter popups, and chat widgets; each step can be turned off. Its product details and parameters are in the ScreenshotNeo documentation.
6. Common errors and fixes
| Symptom | Likely cause | Fix |
|---|---|---|
| Browser executable missing | Playwright package is installed but its browser binary is not. | Run npx playwright install chromium in the project environment. |
| Navigation times out | The site is slow, keeps connections open, or the selected load condition never occurs. | Set a reasonable explicit timeout and use a readiness signal such as a visible page selector. Try domcontentloaded when waiting for full network idle is unsuitable. |
| Blank, partial, or old content | The capture happened before client-side rendering or lazy loading completed. | Wait for the specific content you need, scroll to trigger lazy loading if relevant, then capture. |
| Element screenshot fails | The selector matches nothing, matches a hidden element, or the target is not ready. | Check the selector against the current page, use count() while debugging, and wait for the intended element to become visible. |
| Unexpected storefront or locale | Locale/timezone are being mistaken for site region, or storefront state is stored elsewhere. | Set the site’s intended URL and permitted cookies/account state explicitly. Browser locale alone does not set delivery location or currency. |
| Screenshot file is unexpectedly large | Full-page capture, device-pixel scale, or a lossless format creates many pixels. | Capture only the needed area, use scale: 'css', or choose JPEG/WebP when lossy compression is acceptable. |
| Consent dialog obscures the page | The site presents a banner or modal during this session. | Handle it in a way consistent with the purpose and site rules, or use a capture workflow that can accept and remove supported overlays. |
7. Performance, reliability, and cost
Local Playwright avoids per-screenshot API charges, but you operate the browser, runtime, storage, retries, and any scheduled jobs. A viewport capture generally produces less output than a tall full-page image. Device scale increases pixel count; image format and quality affect file size. Element captures can reduce the artifact to the component needed for review.
For reliable batches, use explicit timeouts and readiness conditions, record which URL and viewport produced each file, and retry only failures that are plausibly transient. Keep browser cleanup in a finally block so failed navigation does not leave processes running. Site-side bot checks, rate limits, and access terms still apply; this guide does not establish the rules for any unnamed ecommerce domain.
If you prefer a managed call, ScreenshotNeo is a website screenshot API and MCP server: one GET request returns PNG, JPEG, WebP, or PDF. Its clean-shot billing rules mean bot checks/CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, and each response identifies the page verdict and billing status in headers. Plans include 1,000 free shots per month with no card, then paid options from $5 for 3,000 shots; every feature is on every plan. Yearly billing gives two months free.
Or skip the browser setup
Send one GET request to ScreenshotNeo; see the API documentation for options and formats.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com -o shot.webp
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://example.com"},
timeout=90,
)
open("shot.webp", "wb").write(r.content)
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(fs => fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer())));
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. You get 1,000 screenshots a month free with no card; paid plans start at $5 for 3,000.
Sign up for ScreenshotNeo’s free 1,000 screenshots a month, with no card required.
FAQ
Does setting en-IN make the website show its Indian store?
Not necessarily. It sets the browser locale. Storefront selection can depend on the site URL, cookies, account, or delivery settings.
Can I capture only the product image?
Yes. Use page.locator('selector').screenshot() with a selector that identifies the image or its containing element.
Does a full-page screenshot include content that has not loaded yet?
Not reliably. Wait for the site’s content and trigger any scroll-based loading before taking the screenshot.
Can the capture prove what a shopper in India saw?
No. A browser screenshot documents a particular browser configuration and page state. Device emulation, locale, and timezone alone do not prove a real visitor’s physical location or experience.


