How to Capture a Playwright Screenshot of a UPI Payment Webpage
Capture a UPI payment page with Playwright, choose the right screenshot scope, and protect sensitive details before saving or sharing it.
Use Playwright’s page.screenshot() after navigating to the UPI payment page and waiting until it shows the state you need. By default, it captures the visible viewport. Set fullPage: true to capture the scrollable page, or use locator.screenshot() for a specific region. Review the resulting image for transaction-specific or sensitive information before saving or sharing it.
A browser screenshot documents what the webpage displayed. It does not prove that a UPI request was authorized or that money transferred: authorization may happen separately in a UPI app. NPCI advises users not to share their UPI PIN.
1. Set up a Playwright screenshot
The example below uses Playwright’s JavaScript API. Install Playwright and its Chromium browser, then save the script as capture-upi.js. Replace the example URL with a page you are authorized to access. This script captures the page as it appears in the browser; it does not submit a payment.
npm init -y
npm install playwright
npx playwright install chromium
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch({ headless: true });
const page = await browser.newPage({ viewport: { width: 1440, height: 1000 } });
try {
await page.goto('https://example.com/checkout', {
waitUntil: 'domcontentloaded',
timeout: 30_000,
});
// Prefer waiting for a meaningful page element when the page is dynamic.
await page.locator('body').waitFor({ state: 'visible', timeout: 10_000 });
await page.screenshot({ path: 'upi-payment.png' });
} finally {
await browser.close();
}
})();
Run it with node capture-upi.js. Change the URL and, where possible, replace the generic body wait with a locator for the payment summary or other content you intend to document. A locator wait makes the capture depend on a meaningful page state instead of an arbitrary pause.
2. Choose what to capture
Pick the capture scope based on what the screenshot needs to show. The default is the current viewport.
| Need | Playwright call | Consideration |
|---|---|---|
| Visible checkout step | page.screenshot({ path: 'payment.png' }) |
Only what is currently in the viewport is included. |
| Page content below the fold | page.screenshot({ path: 'payment-full.png', fullPage: true }) |
Captures the full scrollable document; resulting images can be tall and larger. |
| One summary or component | page.locator('[data-testid="payment-summary"]').screenshot({ path: 'summary.png' }) |
The selector must match an element that exists and is visible. |
await page.screenshot({ path: 'payment-full.png', fullPage: true });
await page.locator('[data-testid="payment-summary"]').screenshot({
path: 'payment-summary.png',
});
The selector above is an example pattern, not a claim about any particular payment site. Inspect the page or use a stable selector supplied by your own application.
3. Control output, rendering, and sensitive content
File format and scale
Playwright supports PNG, JPEG, and WebP screenshots. Set the file extension to match the intended format, or use the screenshot API’s type option. JPEG quality is configurable; the quality option does not apply to PNG. Use scale: 'css' for one output pixel per CSS pixel, or scale: 'device' to follow the device pixel ratio.
// JPEG with a chosen quality
await page.screenshot({ path: 'payment.jpg', type: 'jpeg', quality: 80 });
// One output pixel per CSS pixel
await page.screenshot({ path: 'payment.png', scale: 'css' });
Higher-resolution output can preserve detail but increase file size. Choose the scale and format for the destination: a review attachment may not need the same detail as a visual regression artifact.
Mask sensitive values
If transaction-specific content must not appear in the artifact, mask the relevant locator. Verify that the locator matches the intended content and inspect the saved image before sharing it.
await page.screenshot({
path: 'payment-redacted.png',
mask: [page.locator('[data-testid="transaction-reference"]')],
});
This selector is illustrative. Masking is only useful if the locator correctly identifies the sensitive element. Do not include a UPI PIN in browser content, screenshots, test fixtures, logs, or shared artifacts. NPCI’s UPI FAQ says: “Please do not share your UPI-PIN with anyone.”
Stabilize dynamic pages
Payment pages may update after navigation, show animations, or render content asynchronously. Wait for the state relevant to your capture. Playwright’s screenshot API also provides animation handling, screenshot styles, and timeout behavior; consult the API reference for details that match the version installed in your project.
// Wait for a page-specific state before capturing
await page.locator('[data-testid="payment-summary"]').waitFor({
state: 'visible',
timeout: 10_000,
});
await page.screenshot({ path: 'payment-ready.png' });
Do not assume that a navigation event alone means the payment content is ready. Conversely, waiting for all network activity to stop can be unsuitable for pages that keep background connections open. A specific visible element is often a more useful readiness condition.
4. Protect payment privacy and interpret the image correctly
- Capture only the viewport, page, or component needed for the task.
- Mask transaction references or other sensitive fields when they are not needed.
- Review the actual image before retaining it, attaching it to a ticket, or sharing it.
- Keep screenshots in access-controlled locations and avoid putting payment data in filenames.
- Never request, record, or share a UPI PIN.
NPCI describes an online merchant flow in which a customer receives a collect request and enters the PIN in the BHIM app. A screenshot of the merchant webpage can show browser content, but it cannot establish that the separate app-side authorization happened or that funds were transferred. For UPI Global Acceptance, NPCI advises reviewing payment details, including the final amount in both currencies and applicable exchange rates or fees, in the UPI-powered application before authorization.
5. Run the capture in a repeatable workflow
- Choose a test or permitted checkout page and establish the browser state you need.
- Navigate with a bounded timeout and wait for a page-specific element.
- Choose viewport, full-page, or locator capture based on the evidence required.
- Set output format and scale for the destination.
- Mask unnecessary sensitive values, then inspect the file before storing or distributing it.
- Close the browser in a
finallyblock so it is released even if navigation or capture fails.
For repeatable visual documentation, keep viewport dimensions, browser version, test data, and page state consistent. This reduces accidental differences caused by layout or content changes. Do not treat visual consistency as proof of a payment outcome.
6. Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Screenshot is blank or missing page content | The page had not rendered the target state when capture ran, or navigation failed. | Check the navigation result and URL; wait for a meaningful visible locator before capture. |
| Navigation times out | The site is slow, unreachable, or waiting for a load condition that does not settle. | Use a realistic bounded timeout and a suitable navigation condition, then wait separately for the needed element. |
| Element screenshot reports no matching element | The selector is wrong, the element is not yet rendered, or it is outside the expected page state. | Confirm the selector against the page and wait for it to become visible before calling screenshot(). |
| Sensitive data remains visible | The mask locator did not match the displayed value or the screenshot was made before the page reached the expected state. | Verify the locator and the image itself; do not distribute the artifact until reviewed. |
| Image has unexpected dimensions or size | Full-page scope, viewport dimensions, device pixel ratio, or output format differs from expectations. | Set the viewport and scale explicitly; choose viewport capture if the full document is unnecessary. |
| Capture varies from run to run | Dynamic content, animations, changing payment data, or inconsistent browser settings. | Use stable test data, wait for the intended state, and use documented screenshot animation or style options where appropriate. |
| Browser cannot launch | The browser binary may not be installed for the Playwright package in use. | Install the required browser with npx playwright install chromium and check the installation output. |
7. Performance, reliability, and cost
Playwright requires a browser process, so account for browser startup, page navigation, rendering, and image encoding in job duration. Reuse a browser for multiple captures in a controlled worker when appropriate, while isolating page state between jobs and closing contexts reliably. Full-page images and device-scale captures can use more memory and produce larger files than viewport captures. JPEG or WebP may reduce image size for suitable uses; preserve PNG when lossless output matters.
Set timeouts for navigation and element waits, handle failures, and close browser resources in cleanup code. A screenshot is an observation of one rendered page state, not a durable record of authorization or settlement. Playwright itself is a browser automation library; this workflow has no per-screenshot service fee, but running it uses your own compute and browser infrastructure.
8. Or skip the browser setup
If you need an API call instead of managing a browser, ScreenshotNeo is a website screenshot API and MCP server for developers. One GET request returns an image or PDF. Its capture can accept cookie and consent banners and remove 60+ known consent platforms, newsletter popups, and chat widgets before the shot; each step can be turned off. Bot checks and CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, and response headers identify the page verdict and billing status. Its MCP tools let AI agents take screenshots, get page information, and capture PDFs. Plans include 1,000 screenshots per month free with no card; paid plans start at $5 for 3,000.
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,
)
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}`);
const bytes = new Uint8Array(await res.arrayBuffer());
await import('node:fs/promises').then(fs => fs.writeFile('shot.webp', bytes));
Use a payment page URL you are authorized to capture, and review the result for sensitive information. Sign up for ScreenshotNeo’s free plan to get 1,000 screenshots a month with no card.
9. Frequently asked questions
Does a screenshot prove that a UPI payment succeeded?
No. It records what the browser displayed. Authorization and payment confirmation may happen in a UPI app or another system.
Can Playwright return screenshot bytes instead of writing a file?
Yes. Omit the path option and the screenshot API returns image bytes that your code can process or store.
Should I capture the payment PIN screen?
No. Do not share or retain a UPI PIN. NPCI advises users not to share it with anyone.


