ScreenshotNeo

BlogHow-to

How to Screenshot an Indian Government Website with Playwright

Capture an Indian government page with Playwright, choose the right screenshot mode, and record browser, viewport, and language context.

By the ScreenshotNeo team4 October 202610 min read

Use Playwright to open the public page, wait for the content you need to capture, and save a viewport, element, or full-page screenshot. Record the browser and version, viewport dimensions, and selected page language when they could affect the result. A screenshot documents visual presentation; by itself it does not prove that a site is authentic, that text is accessible, or that the page meets a compliance standard.

The examples below use the Playwright JavaScript library. They capture pages you are authorized to access and do not bypass authentication, CAPTCHA, rate limits, or other access controls. Check the selected site’s terms and access policy before automating requests.

1. Install Playwright and choose a capture

In a new Node.js project, install Playwright and its Chromium browser:

npm init -y
npm install playwright
npx playwright install chromium

Choose the capture target based on what the image needs to show:

Mode Use it for Playwright option
Viewport The visible browser area, such as the first screen of a page Default page screenshot
Element A particular panel, notice, table, or other component locator(...).screenshot()
Full page Content extending below the viewport fullPage: true

Playwright’s screenshot guidance distinguishes visual captures from snapshots used to inspect page structure. Screenshots are for visual review; use an accessibility or text inspection when you need to assess reading order, accessible names, or nonvisual access. See the [Playwright screenshot guidance](https://playwright.dev/mcp/tools/screenshots) and [ARIA snapshot documentation](https://playwright.dev/docs/aria-snapshots).

2. Capture a government page with JavaScript

Save this as screenshot.mjs. Set PAGE_URL to the public page you need to document. The script sets a stable viewport, waits for the page load event and then for fonts, and writes a full-page PNG. For pages whose key content loads later, replace the optional selector with a stable locator from that page.

import { chromium } from 'playwright';

const url = process.env.PAGE_URL ?? 'https://www.india.gov.in/';
const browser = await chromium.launch({ headless: true });
const page = await browser.newPage({
  viewport: { width: 1440, height: 1000 },
  deviceScaleFactor: 1,
  locale: 'en-IN',
});

try {
  const response = await page.goto(url, {
    waitUntil: 'load',
    timeout: 60_000,
  });

  if (!response) {
    throw new Error('Navigation returned no main-document response');
  }
  if (!response.ok()) {
    throw new Error(`Navigation failed: HTTP ${response.status()} ${response.statusText()}`);
  }

  // If the page has a reliable content landmark, wait for it explicitly:
  // await page.locator('main').waitFor({ state: 'visible', timeout: 15_000 });

  await page.evaluate(() => document.fonts.ready);
  await page.screenshot({ path: 'government-page.png', fullPage: true });

  console.log(JSON.stringify({
    url: page.url(),
    title: await page.title(),
    browser: browser.version(),
    viewport: page.viewportSize(),
    locale: 'en-IN',
    status: response.status(),
    screenshot: 'government-page.png',
  }, null, 2));
} finally {
  await browser.close();
}

Run it with:

PAGE_URL='https://www.india.gov.in/' node screenshot.mjs

The example URL is a starting point, not an assertion that it is the page you need or that a particular domain proves authenticity. Choose the intended page yourself and retain its final URL and response status in your capture notes.

3. Choose waits that match the page

Navigation completion is not the same as visual readiness. Government pages may load content, fonts, or images after the main document. Use the least broad wait that ensures the content relevant to your capture is ready:

  • waitUntil: 'domcontentloaded' waits for initial HTML parsing and can be suitable when you then wait for a specific element.
  • waitUntil: 'load' waits for the page load event, including many dependent resources.
  • waitUntil: 'networkidle' waits for a quiet network period. It can be unsuitable for pages with polling, analytics, or long-lived requests; a specific selector is often more reliable.
  • locator(selector).waitFor({ state: 'visible' }) waits for a known target to appear. Prefer a meaningful landmark or the exact component under review.
  • page.waitForTimeout(ms) adds a fixed delay. Use it only when the page has a known delayed render that cannot be observed with a locator; arbitrary sleeps make captures slow and inconsistent.

For a page where the content is rendered after navigation, use a selector wait and preserve a bounded timeout:

await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 60_000 });
await page.locator('main').waitFor({ state: 'visible', timeout: 15_000 });
await page.evaluate(() => document.fonts.ready);
await page.screenshot({ path: 'page.png', fullPage: true });

4. Viewport, element, full-page, and output options

Viewport screenshot

Omit fullPage to capture the visible viewport. Set viewport dimensions when layout comparison matters; use the same dimensions for each run.

await page.screenshot({ path: 'viewport.png', type: 'png' });

Element screenshot

Locate a component and screenshot it directly. If the selector matches multiple elements, make the locator specific or select the intended match.

const notice = page.locator('main');
await notice.waitFor({ state: 'visible' });
await notice.screenshot({ path: 'main-content.png' });

Full-page screenshot

fullPage: true captures the page beyond the viewport. Very long pages produce large images and can expose lazy-loading behavior: content that only loads when scrolled into view may not be present until the page is scrolled. For such pages, scroll through the page before capture or capture the relevant sections separately, and check the resulting image.

await page.screenshot({ path: 'full-page.png', fullPage: true });

Image format and scale

Playwright supports PNG and JPEG screenshot output; the file extension and type should agree. JPEG supports a quality setting, while PNG is lossless. scale: 'css' outputs one image pixel per CSS pixel; scale: 'device' uses device pixels and may create a larger image on high-density displays.

await page.screenshot({ path: 'page.jpg', type: 'jpeg', quality: 85, scale: 'css' });

For text-heavy pages, PNG is usually easier to inspect without compression artifacts. Choose scale deliberately if captures will be compared pixel by pixel.

5. Language and rendering context

Indian government pages may be available in English, Hindi, and regional languages, and a page’s layout and fonts can vary with the selected language and browser. GIGW guidance calls for testing Hindi and regional-language fonts across popular browsers and considering browser versions, operating systems, connection speeds, and screen resolutions. That guidance makes capture context useful: record the browser/version, viewport, and page language for captures where those conditions matter. This is a practical documentation recommendation, not a claim that one screenshot covers every user environment.

Set Playwright’s locale when you intend to control browser locale behavior, but also select the site’s actual language using its own language control if needed. The browser locale does not guarantee that a multilingual site will switch content. Verify the visible language before saving.

const page = await browser.newPage({
  viewport: { width: 1365, height: 900 },
  locale: 'hi-IN',
});

For a rendering investigation, repeat the capture under the relevant browser and viewport combinations and keep each file paired with its context. A single desktop capture cannot establish how a page renders on another browser, operating system, resolution, or connection.

GIGW covers government websites and apps at central, state, and local levels and lists gov.in and nic.in as government domain conventions. A domain can provide context, but neither it nor a screenshot alone proves that a page is genuine. GIGW also recommends text alternatives and alternate modes for CAPTCHA; a visual image cannot demonstrate that those alternatives work. Pair a screenshot with keyboard, text, or accessibility inspection when usability or accessibility is the question. See the [GIGW guidelines](https://guidelines.india.gov.in/guidelines/).

6. Record evidence and interpret it carefully

For a reproducible visual record, keep the screenshot with a small capture note containing:

  • Requested URL and final URL after redirects.
  • Capture date and time, with timezone if it matters to the review.
  • Browser name and version, viewport width and height, and device scale factor.
  • Selected site language and browser locale.
  • Capture mode (viewport, element, or full page), output format, and any selector used.
  • Navigation status and any relevant console or page errors.

A screenshot records visible pixels at a moment in a particular environment. It does not prove site ownership, authenticity, source content, accessibility, or legal compliance. For text and page structure, use a text or accessibility inspection as appropriate; for accessibility, test keyboard interaction and nonvisual alternatives as well.

7. cURL, Python, and Node.js with ScreenshotNeo

If you need a screenshot without managing a local browser installation, ScreenshotNeo provides a screenshot API and MCP server for developers. The following API examples request a screenshot of the public page. See the ScreenshotNeo API documentation for parameters and configuration.

cURL

curl -G "https://api.screenshotneo.com/v1/shot" \
  -d access_key=YOUR_API_KEY \
  --data-urlencode url=https://www.india.gov.in/ \
  -o shot.webp

Python

import requests

r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={"access_key": "YOUR_API_KEY", "url": "https://www.india.gov.in/"},
    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://www.india.gov.in/',
});
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()))
);

Keep the API key out of browser-side code and source control. An API screenshot is useful for routine capture, while a local Playwright run gives you direct control over the installed browser environment and capture context.

Or skip the browser setup

Make one GET request through ScreenshotNeo for the capture. Cookie banners are accepted like a visitor, and 60+ known consent platforms, newsletter popups, and chat widgets are removed before the shot; each cleanup step can be turned off. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, and response headers report the page verdict and whether the request was billed. Its MCP server provides take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 screenshots.

curl -G "https://api.screenshotneo.com/v1/shot" \
  -d access_key=YOUR_API_KEY \
  --data-urlencode url=https://www.india.gov.in/ \
  -o shot.webp

Sign up for 1,000 free screenshots a month, with no card required.

Troubleshooting

Symptom Likely cause Fix
Navigation times out The site is slow, a resource remains active, or the chosen wait condition is too broad. Check the URL and access policy, use a bounded timeout, and wait for a specific visible element after domcontentloaded when suitable. Do not attempt to defeat access controls.
Screenshot is blank or missing expected content The capture happened before the content rendered, or the site presents a bot check or error page. Check the final URL and response status, wait for the relevant locator, and inspect the page. Do not bypass CAPTCHA or bot checks.
Text or regional-language glyphs look wrong Fonts may not have loaded, or rendering differs by browser, operating system, locale, or viewport. Wait for document.fonts.ready, verify the site language selection, and capture the relevant browser and resolution combinations.
Element locator times out The selector is wrong, not unique, or the target is hidden or in a frame. Inspect the page structure, use a stable locator, wait for visible state, and account for frames where the target lives in one.
Full-page image omits lower-page content Content may be lazy-loaded only after scrolling, or the page may load sections dynamically. Scroll through the page before capture, wait for the target sections, or capture specific elements separately.
Large image or slow capture A very long page, large viewport, or device-pixel scale increases captured pixels. Use CSS scale, capture only the relevant element, or use a viewport capture when below-the-fold content is not needed.
HTTP error from the page The site returned an error, redirected unexpectedly, or rejected the request. Check the status and final URL, confirm the page is publicly accessible, and follow the site’s published access rules.

Performance, reliability, and cost

For local Playwright, browser installation and launch add setup and runtime overhead. Reuse a browser process for multiple pages when running a capture batch, close pages and browsers in cleanup code, and avoid capturing more pixels than the task needs. A fixed viewport and explicit waits make runs easier to compare; a broad network-idle wait can make dynamic pages slower or cause avoidable timeouts.

Page content can change between captures, and rendering depends on browser version, fonts, viewport, language, and network conditions. Save the context with the image and rerun captures when a result is unexpected. Screenshot output is visual evidence, not an archival guarantee or authentication mechanism.

Playwright is an open-source browser automation library; local capture costs depend on the machine and infrastructure you run it on. ScreenshotNeo offers 1,000 shots per month free with no card; paid plans are Starter $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. Yearly billing gives two months free, and every feature is available on every plan. Only clean shots are billed, with response headers indicating the page verdict and billed status.

Frequently asked questions

Does a screenshot prove that a government page is authentic?

No. A domain convention can help provide context, but the image itself does not verify ownership or authenticity. Check the source independently.

Can a screenshot establish accessibility?

No. It shows visual presentation. Use keyboard checks, text inspection, and accessibility structure checks for the questions an image cannot answer.

Should I use a full-page screenshot for every review?

No. Use it when below-the-fold layout matters. Viewport or element captures are smaller and can make a specific visual issue easier to inspect.

Does setting locale: 'hi-IN' switch the site to Hindi?

Not necessarily. It sets browser locale behavior; use the page’s own language control and confirm the rendered content.