Fix Playwright Screenshots of an Indian Bank Portal That Show the Session Timeout Page
Diagnose why a Playwright screenshot shows an Indian bank portal’s session timeout page, then verify authentication and page readiness safely before capture.
If a Playwright screenshot shows a bank portal’s session timeout page, first check the page URL and a stable, authorized signal that confirms the expected authenticated page immediately before capture. A screenshot records what the browser rendered; it does not tell you whether authentication expired, a redirect happened, or the test captured too early. Use a fresh, permitted test session, wait for the expected page state, and inspect a trace around the capture.
This guide applies to an unspecified Indian bank portal. Its timeout duration, routes, authentication mechanism, and approved test procedure are portal-specific. The examples use placeholder routes and selectors: adapt them only in an authorized test environment. Do not bypass the timeout or reuse another person’s credentials or cookies.
1. Confirm whether the page is actually timed out
Record the current URL and assert a distinctive page signal just before taking the screenshot. If the URL has changed to a login or timeout route, investigate authentication and redirects. If the URL is still the expected one but the visible content is wrong, inspect the page state and network activity. Do not log credentials, cookies, authorization headers, or storage-state contents.
import { test, expect } from '@playwright/test';
test('capture the authorized account overview', async ({ page }) => {
await page.goto('https://test-bank.example/account', {
waitUntil: 'domcontentloaded',
});
// Replace these with a legitimate route and stable page signal
// from your approved test environment.
await expect(page).toHaveURL(/account|dashboard/i);
await expect(
page.getByRole('heading', { name: 'Account overview' })
).toBeVisible();
const currentUrl = page.url();
console.info(`Capture URL: ${new URL(currentUrl).pathname}`);
await page.screenshot({ path: 'account-overview.png', fullPage: true });
});
The example uses Playwright Test’s expect assertions. If you use the Playwright library without its test runner, use locator waits such as page.getByRole(...).waitFor({ state: 'visible' }), followed by an explicit check of the URL or expected page content. Playwright’s Page API supports URL waits, and its locator guidance describes automatic waiting for actionable and visible elements. Prefer these meaningful conditions to a fixed sleep.
2. Check how the test gets its authenticated session
A saved Playwright storage-state file can let a new browser context start with authentication data from an earlier login. That state can expire. Playwright recommends deleting expired state and keeping state files out of source control: they may contain cookies and headers that could impersonate the user. Follow the portal’s approved test login process to create a fresh state when needed.
Save state only after the approved login reaches the expected page
import { chromium, expect } from '@playwright/test';
const browser = await chromium.launch();
const context = await browser.newContext();
const page = await context.newPage();
await page.goto('https://test-bank.example/login');
// Complete login only through the authorized test flow.
// Supply credentials through your approved secret manager or CI mechanism;
// do not hard-code them or print them in logs.
await page.getByLabel('User ID').fill(process.env.TEST_BANK_USER ?? '');
await page.getByLabel('Password').fill(process.env.TEST_BANK_PASSWORD ?? '');
await page.getByRole('button', { name: 'Sign in' }).click();
await expect(page).toHaveURL(/account|dashboard/i);
await expect(
page.getByRole('heading', { name: 'Account overview' })
).toBeVisible();
await context.storageState({ path: 'playwright/.auth/bank-test.json' });
await browser.close();
Use the saved state in the test context, and refresh it through the approved login setup when it expires. Add the auth directory to .gitignore, restrict access to CI artifacts, and avoid printing state or secrets during debugging. See Playwright’s Authentication guide for storage-state setup and its security considerations.
import { test, expect } from '@playwright/test';
test.use({
storageState: 'playwright/.auth/bank-test.json',
});
test('capture a fresh authenticated page', async ({ page }) => {
await page.goto('https://test-bank.example/account');
// Fail with a useful diagnosis before saving a misleading screenshot.
await expect(page).toHaveURL(/account|dashboard/i);
await expect(
page.getByRole('heading', { name: 'Account overview' })
).toBeVisible();
await page.screenshot({ path: 'account-overview.png' });
});
Storage state does not cover every possible application mechanism. In particular, Playwright’s auth guide explains that sessionStorage is specific to a domain, is not persisted across page loads, and has no built-in persistence API in that guide. Do not assume the portal uses it. First establish the mechanism from your authorized application behavior or test setup. If the approved test application requires session storage, use Playwright’s documented save-and-restore pattern for the correct origin and test account. Never transplant a real user’s session.
3. Wait for the intended page condition, not an arbitrary delay
A fixed delay may make a flaky test slower without fixing an expired session or redirect. Wait for an expected URL when navigation is the condition, and for a meaningful UI signal when page readiness is the condition. If a particular action is expected to navigate, arm the URL wait before the action:
const expectedNavigation = page.waitForURL(/account|dashboard/i);
await page.getByRole('button', { name: 'Continue' }).click();
await expectedNavigation;
await expect(
page.getByRole('heading', { name: 'Account overview' })
).toBeVisible();
await page.screenshot({ path: 'account-overview.png' });
Use the real route pattern and page signal for the test environment. A broad regular expression can accidentally accept an unrelated page; strengthen it when the application has a reliable, specific route. A successful navigation alone also does not prove the user is authenticated, so assert the expected content too.
4. Use a trace to find what happened before capture
A Playwright trace can show the action timeline, DOM snapshots, screenshots, and network activity around a failing capture. Those records help distinguish an expired or rejected session, a redirect, a missing application response, and a screenshot taken before the expected UI appeared. Playwright recommends traces for CI debugging, including capturing on the first retry.
With Playwright Test, enable tracing for a failing run or the first retry in the project configuration:
import { defineConfig } from '@playwright/test';
export default defineConfig({
use: {
trace: 'on-first-retry',
},
});
Open the resulting trace with Playwright’s Trace Viewer. Inspect the events immediately before the screenshot: navigation, relevant requests and responses, DOM snapshots, and the visible page. Traces can contain sensitive information. Review and protect them as you would authentication state, and sanitize them before sharing.
5. Diagnose by evidence
| What you observe | Likely area to investigate | Next step |
|---|---|---|
| The URL changes to a login or timeout route | Expired state, a rejected request, or an application redirect | Check the approved login setup, state freshness, and trace network events. Reauthenticate through the authorized flow. |
| The URL is expected, but a timeout message is visible | Application state or content rendered inside the expected route | Assert the expected page heading or other stable signal; inspect DOM snapshots and relevant requests in the trace. |
| The expected page appears only after the screenshot | Capture readiness condition is too weak or missing | Wait for the specific locator or expected navigation before capture; avoid a blind delay. |
| Some content is missing, but authentication is valid | Application rendering, a failed resource, or environment variation | Review trace network activity and page state. Compare browser version, operating system, settings, hardware, and headless mode if the difference is visual. |
| The problem appears only on later runs | Reused authentication state may have expired | Refresh state through the approved test login setup and confirm it reaches the authenticated page before saving. |
Playwright notes that operating system, browser version, settings, hardware, and headless mode can affect screenshot rendering. Those differences may explain visual variation, but they do not by themselves explain why an actual timeout page appeared.
6. Keep the bank’s session controls intact
Do not fix the screenshot by disabling the portal timeout, suppressing its redirect, replaying another user’s cookies, or extending a real session outside the approved test setup. Use an authorized test account and reauthenticate through the permitted test flow, or ask the bank for a test session suited to the work. The Indian Bank cyber-security audit RFP dated 24 July 2024 includes checks for session termination after a relative timeout and cookie controls. It is an audit checklist for that procurement, not evidence of a universal timeout duration or the configuration of every Indian bank portal.
7. Common errors and fixes
The saved state works once, then the test shows the timeout page
Cause: Authentication state may have expired or been invalidated. The lifetime is specific to the portal; there is no universal duration to assume.
Fix: Regenerate state using the approved test login flow, confirm the authenticated page before saving it, and use the new state. Do not log the state contents.
The URL assertion passes, but the screenshot is still wrong
Cause: The URL pattern may be broad, or the expected route can render an error or timeout state within the page.
Fix: Assert a stable authenticated-page signal, such as a distinctive heading or account overview element, in addition to the URL. Choose a signal that is appropriate for the authorized test environment.
A timeout from Playwright is mistaken for a bank session timeout
Cause: An assertion or locator wait can time out because its condition never became true. That is different from the bank rendering its own session timeout page.
Fix: Read the failed assertion and inspect the trace. Check whether the page redirected, whether the locator exists in the DOM snapshot, and whether the relevant network request succeeded. Name assertions clearly so CI output identifies the condition that failed.
Login succeeded in one context but not in another
Cause: The test may not be loading the intended state file, may be using a different origin, or the portal may rely on storage beyond the saved state.
Fix: Verify which state file the test context loads and which origin the portal uses. Establish whether the approved application flow relies on cookies, local storage, IndexedDB, or session storage before changing setup.
The trace shows a rejected request or redirect loop
Cause: Authentication may be stale, or the portal may have rejected a request during navigation.
Fix: Use trace network events to identify the sequence, then refresh authentication only through the approved test flow. Do not replay captured requests with real customer credentials as a workaround.
Trace files or debug logs expose secrets
Cause: Authentication state, headers, URLs, page content, or trace artifacts can contain sensitive data.
Fix: Restrict access and retention, keep auth files out of source control, avoid printing secrets, and review or sanitize artifacts before sharing. Treat a trace as sensitive until checked.
8. Reliability, performance, and cost
- Reliability: Assert both the expected route and a page-specific signal. This prevents a timeout page from being silently accepted as a successful screenshot.
- Readiness: Locator and URL conditions describe what the test needs. A blind sleep adds elapsed time and can still capture the wrong state.
- Debugging: Keep traces for failures or first retries where practical, and protect them as sensitive artifacts.
- Environment: Keep browser and host configuration consistent when comparing visual output. Environment differences affect rendering but do not establish the cause of a session redirect.
- Cost: Playwright is a browser automation library; this diagnosis itself does not imply a paid screenshot service. Account for your own browser, CI, storage, and artifact-retention costs. The dossier does not establish prices for those resources.
9. Or skip the browser setup
If your goal is to capture a public page rather than validate an authenticated bank session, ScreenshotNeo can return a screenshot from one API request. It cannot replace an authorized login flow for a private banking page. See the ScreenshotNeo API documentation for request options.
curl -G "https://api.screenshotneo.com/v1/shot" \
-d access_key=YOUR_API_KEY \
--data-urlencode url=https://stripe.com \
-o shot.webp
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
timeout=90,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({
access_key: 'YOUR_API_KEY',
url: 'https://stripe.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(async (fs) => {
await fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer()));
});
ScreenshotNeo accepts cookie and consent banners like a visitor, then removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each step can be turned off. Bot checks, blank pages, failed loads, timeouts, and cache hits cost nothing, and response headers report the page verdict and billing status. Its MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. The free plan includes 1,000 screenshots per 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.
FAQ
Can I tell the exact timeout duration from the screenshot?
No. The page alone does not establish the portal’s configured timeout. Check the authorized test setup or ask the bank’s test-environment owner.
Does a successful Playwright navigation prove I am authenticated?
No. A route may load while showing a login, timeout, or error state. Check a reliable page-specific signal as well.
Can I share a trace to ask for help?
Only after reviewing it for sensitive state, headers, page content, and other private information. Protect the original trace as a sensitive artifact.


