ScreenshotNeo

BlogHow-to

How to Screenshot Multiple Indian Bank Website Pages in One Batch

Capture authorized public bank pages in one repeatable Playwright batch. Choose viewport or full-page screenshots, save them clearly, and protect sensitive images.

By the ScreenshotNeo team4 October 20269 min read

Use a browser automation script to visit each page you are authorized to access and save a separate screenshot for it. Playwright can capture either the visible browser viewport or the full scrollable page. The example below processes a supplied list in sequence, waits for navigation, records failures, and gives each output a descriptive filename.

This guide is for pages you are permitted to view and capture. Bank sites differ in their terms, security controls, and page behavior. Check the specific bank’s current terms; do not try to bypass login protections, bot checks, or other controls. The example is a general Playwright workflow, not a claim that it has been tested against Indian bank websites.

1. Set up Playwright

Use a current Node.js installation. Create a project, install Playwright, and install its Chromium browser:

mkdir bank-page-capture
cd bank-page-capture
npm init -y
npm install playwright
npx playwright install chromium

Create capture.mjs with the following script. Replace the sample public URLs with pages you are authorized to capture. The script uses a fresh browser context, processes pages one by one, waits for the page load event, and writes a result for each URL. A failed URL is reported while the rest of the batch continues.

import { chromium } from 'playwright';
import { mkdir } from 'node:fs/promises';

const urls = [
  'https://www.rbi.org.in/',
  'https://www.example.com/'
];

// Use 'viewport' for the visible screen or 'fullPage' for the whole page.
const captureMode = 'fullPage';
const outputDir = 'captures';

function safeName(value) {
  return value
    .replace(/^https?:\\/\\//, '')
    .replace(/[^a-z0-9.-]+/gi, '-')
    .replace(/-+/g, '-')
    .replace(/^-|-$/g, '')
    .slice(0, 100) || 'page';
}

await mkdir(outputDir, { recursive: true });
const browser = await chromium.launch({ headless: true });
const context = await browser.newContext({ viewport: { width: 1440, height: 1000 } });
const results = [];

try {
  for (const [index, url] of urls.entries()) {
    const page = await context.newPage();
    try {
      const response = await page.goto(url, {
        waitUntil: 'load',
        timeout: 45_000
      });

      // A missing response can occur for some navigations; keep that visible in the report.
      const status = response?.status() ?? 'no response';
      const filename = `${String(index + 1).padStart(2, '0')}-${safeName(new URL(url).hostname + new URL(url).pathname)}.png`;
      const options = captureMode === 'fullPage'
        ? { path: `${outputDir}/${filename}`, fullPage: true }
        : { path: `${outputDir}/${filename}` };

      await page.screenshot(options);
      results.push({ url, status, file: `${outputDir}/${filename}` });
      console.log(`Saved ${url} (${status}) -> ${outputDir}/${filename}`);
    } catch (error) {
      results.push({ url, error: String(error) });
      console.error(`Could not capture ${url}: ${error.message}`);
    } finally {
      await page.close();
    }
  }
} finally {
  await context.close();
  await browser.close();
}

console.log(JSON.stringify(results, null, 2));

Run it with:

node capture.mjs

Each URL produces its own PNG in the captures directory. Review the output and the images: a successful navigation does not guarantee that every part of a dynamic page has finished rendering or that the image contains only the information you intended.

2. Choose viewport, full-page, or element capture

Mode What it captures Use it when
Viewport The currently visible browser area at the configured viewport size. You need a screen-sized record of the initial view or a particular scroll position.
Full page The scrollable page as a tall image. You need below-the-fold content from a long public information page.
Element A selected page element, such as a notice or content section. You need a focused region rather than the entire page.

Playwright documents navigation and screenshots, including the fullPage option and screenshots of a locator. Full-page capture can produce a very tall image, and the actual captured content depends on how the site renders. [Playwright screenshot documentation]

For an element capture, replace the screenshot call after navigation with a locator capture. Use a selector that identifies the intended region on that particular site:

const section = page.locator('main');
await section.screenshot({ path: `${outputDir}/${filename}` });

Selectors vary by site, and a missing or hidden match can cause capture to fail. Inspect the page structure and choose a selector that identifies the intended content.

3. Make page readiness explicit

A page’s load event is a practical starting point, not proof that all asynchronous content is ready. Avoid an arbitrary long wait for every page when a specific readiness signal is available. For a page where the main content appears after navigation, wait for a meaningful selector:

await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 45_000 });
await page.locator('main').waitFor({ state: 'visible', timeout: 15_000 });
await page.screenshot({ path: filename, fullPage: true });

For a site that updates after initial load, wait for the particular content or state needed. A fixed delay can be used only when no better signal exists:

await page.waitForTimeout(2_000);

Do not use automation to defeat a bank’s security prompts or access controls. If the page requires an authenticated session, only proceed where your access and the bank’s terms allow it, and never put passwords, PINs, or OTPs directly into a script or source file.

4. Keep batch output identifiable and controlled

  • Use one file per URL and include a sequence number or hostname in each name.
  • Keep a separate record of URLs and outcomes so a failed capture is not mistaken for a saved image.
  • Start with a small list, inspect results, then expand the batch.
  • Capture only the page area and information you need.
  • Store images in a location you control and inspect them for account identifiers, balances, or other sensitive details before sharing.

These are workflow precautions. The research does not establish a universal permission or compatibility rule for Indian bank websites, nor a performance guarantee for a batch size.

5. cURL, Python, and Node.js for ScreenshotNeo

If the pages are publicly accessible and you want a screenshot API instead of managing a browser, ScreenshotNeo accepts a URL and returns an image or PDF. Its API documentation describes the request options. For a small batch, repeat one request per authorized URL and save each response under a distinct name. Protect the API key and the resulting files.

cURL

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

Python

import requests

urls = [
    ("rbi-home", "https://www.rbi.org.in/"),
    ("example-home", "https://www.example.com/"),
]

for name, url in urls:
    response = requests.get(
        "https://api.screenshotneo.com/v1/shot",
        params={"access_key": "YOUR_API_KEY", "url": url},
        timeout=90,
    )
    response.raise_for_status()
    with open(f"{name}.webp", "wb") as image_file:
        image_file.write(response.content)
    print(f"Saved {name}.webp")

Node.js

const urls = [
  ['rbi-home', 'https://www.rbi.org.in/'],
  ['example-home', 'https://www.example.com/'],
];

for (const [name, url] of urls) {
  const q = new URLSearchParams({
    access_key: 'YOUR_API_KEY',
    url,
  });
  const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
  if (!res.ok) throw new Error(`Capture failed for ${url}: HTTP ${res.status}`);
  const bytes = await res.arrayBuffer();
  await (await import('node:fs/promises')).writeFile(`${name}.webp`, Buffer.from(bytes));
  console.log(`Saved ${name}.webp`);
}

The ScreenshotNeo examples capture one URL per call; loop over a list for a simple batch. ScreenshotNeo also supports bulk capture of up to 100 URLs per call. Only clean shots are billed: bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, and response headers report the page verdict and billing status. Its plans include 1,000 shots per month free with no card, then paid options from $5 for 3,000; yearly billing gives two months free. Every feature is available on every plan.

Or skip the browser setup

A single ScreenshotNeo request captures a URL:

curl -G "https://api.screenshotneo.com/v1/shot" \
  -d access_key=YOUR_API_KEY \
  --data-urlencode url=https://www.rbi.org.in/ \
  -o rbi-home.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, and paid plans start at $5 for 3,000. For public bank pages this can avoid running a browser locally; it does not grant access to restricted pages or authorize capturing account information. Create a free ScreenshotNeo account.

Performance, reliability, and cost

Playwright batch runs

The sample processes pages sequentially. This is easy to reason about and limits simultaneous browser work, but total runtime grows with each page’s navigation and rendering time. If you increase concurrency, do so gradually and consider the destination site’s terms and load. Long full-page screenshots may take more time and produce larger files than viewport captures. Playwright’s documentation describes the capture options, not bank-site performance or a guaranteed batch rate.

Set navigation and selector timeouts based on your workflow, catch per-page errors, and retain a result record. For repeat runs, consider writing to a dated output directory and avoid silently overwriting a prior batch. These choices make failures and reruns easier to identify.

ScreenshotNeo requests

Each API capture is a separate request unless using its bulk capture feature, which accepts up to 100 URLs per call. The documented pricing is 1,000 shots per month free, 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; annual billing gives two months free. Only clean shots are billed, and response headers identify the verdict and billing outcome. No timing or throughput benchmark is established here.

Protecting output

Bank-related images can reveal sensitive information. RBI digital-banking guidance advises using verified, secure, trusted websites and says, “Never store important banking data in mobile, email or purse.” RBI also cautions customers not to share login details, card information, PINs, passwords, or OTPs with unidentified people or through unverified or unauthorized websites or applications. Treat screenshots as potentially sensitive files: minimize what you capture, review before sharing, and store them carefully. [RBI: Safeguards for Digital Banking] [RBI customer caution]

Troubleshooting

Symptom Likely cause What to do
Navigation times out The site is slow, still loading, or waiting on resources. Check the URL and connectivity, choose an appropriate readiness condition, and adjust the timeout if the page normally needs longer. Do not repeatedly hammer the site.
Screenshot is blank or incomplete The page has not rendered its main content, or content loads asynchronously. Wait for a relevant visible selector or a specific page state before capture; inspect the page manually if needed.
Full-page capture is extremely tall The page contains long content or repeated/lazy-loaded sections. Use viewport or element capture if that is sufficient, and inspect the resulting image before distributing it.
Element selector capture fails The selector does not match, is hidden, or the element has not appeared. Choose a selector present on that page and wait for it to become visible before taking its screenshot.
One URL fails but later pages should still run A navigation or capture error occurred for that page. Keep errors inside the per-URL try/catch as in the example and review the final results list.
Bank page shows a security check or denies access The destination applies its own access or security controls. Stop and use the bank’s permitted access path. Do not attempt to bypass the control.
API response is an error The request may have an invalid key, inaccessible target, or failed capture. Check the key and encoded URL, inspect the response and ScreenshotNeo verdict/billing headers, and consult the API documentation.
Images overwrite earlier output Names are not unique across runs or URLs. Include a sequence, hostname, and optionally a date in filenames; keep each batch in its own directory.

FAQ

Can I batch-capture logged-in bank pages?

Only if your access and the bank’s current terms allow it. The example is scoped to authorized pages and does not automate credentials or bypass controls.

Should I capture the whole page or just the screen?

Use full-page capture when below-the-fold content matters. Use viewport capture for a screen-sized state, or an element capture for a focused region.

Does a successful screenshot prove the page is accurate?

No. It records what the browser rendered at capture time. Review the image and confirm the intended content and page state.

Can I share the screenshots?

Inspect each image first for personal or financial details, and share only when you are authorized to do so.