Capture a Screenshot of a Logged-In Page with an HTTP Basic Authentication Prompt
Use Playwright to authenticate before navigation, verify the protected page rendered, and capture it. Learn what to do when the prompt is an application login form instead.
To screenshot a page protected by HTTP Basic Authentication, provide the authorized username and password to the browser context before navigating, then save the rendered page. In Playwright, use the context-level httpCredentials option and page.screenshot(). First confirm that the prompt is HTTP Basic Auth: an ordinary login form inside the page needs that site’s application sign-in flow instead.
1. Identify which kind of login you have
HTTP Basic Auth is an HTTP authentication challenge. The browser handles it as part of the request, before it can render the protected page. A website login form is application authentication: it is HTML rendered by the site and may use a username field, password field, redirects, cookies, or multi-factor authentication. Supplying HTTP Basic credentials does not automatically fill out or submit such a form.
If the browser shows its native username-and-password prompt, or the server challenges the request with Basic Auth, use the Playwright workflow below. If navigation instead lands on a sign-in page, use the application’s supported login flow and wait for its authenticated state. This guide covers the Basic Auth case.
2. Capture with Playwright in Node.js
Playwright’s browser context accepts httpCredentials. Set them before opening the protected URL so the browser can answer the challenge during navigation. The following complete example reads secrets from environment variables, checks for a page-specific element, captures the full page, and closes the browser even if navigation or capture fails.
const { chromium } = require('playwright');
async function main() {
const { PROTECTED_URL, BASIC_AUTH_USERNAME, BASIC_AUTH_PASSWORD } = process.env;
if (!PROTECTED_URL || !BASIC_AUTH_USERNAME || !BASIC_AUTH_PASSWORD) {
throw new Error('Set PROTECTED_URL, BASIC_AUTH_USERNAME, and BASIC_AUTH_PASSWORD');
}
const browser = await chromium.launch();
try {
const context = await browser.newContext({
httpCredentials: {
username: BASIC_AUTH_USERNAME,
password: BASIC_AUTH_PASSWORD,
},
});
const page = await context.newPage();
await page.goto(PROTECTED_URL, { waitUntil: 'domcontentloaded' });
// Replace this with a selector that only appears on the expected protected page.
await page.locator('main').waitFor({ state: 'visible', timeout: 15000 });
await page.screenshot({ path: 'protected-page.png', fullPage: true });
await context.close();
} finally {
await browser.close();
}
}
main().catch((error) => {
console.error(error);
process.exitCode = 1;
});
Install Playwright in your project and install its browser binaries using its documented setup instructions. Set PROTECTED_URL, BASIC_AUTH_USERNAME, and BASIC_AUTH_PASSWORD in the process environment before running the script. Keep real credentials out of source control, terminal transcripts, and logs. The example’s main selector is only a placeholder: choose an element or text that indicates the intended authenticated content, because a successful navigation can still show an access-denied or error page.
See Playwright’s primary documentation for HTTP authentication and the Page screenshot API.
3. Choose capture and readiness options
| Need | Playwright approach |
|---|---|
| Current viewport only | Omit fullPage or set it to false. |
| Whole scrollable page | Set fullPage: true. Very long pages may produce large images and use more memory. |
| PNG, JPEG, or WebP | Choose type: 'png', 'jpeg', or 'webp' where supported by the installed Playwright version; JPEG and WebP support quality settings. |
| Image dimensions | Set viewport dimensions when creating the context. Use the screenshot scale option to choose CSS-pixel or device-pixel output. |
| Dynamic content | Wait for a meaningful page-specific selector or state. Use a deliberate timeout rather than assuming navigation completion means rendering is finished. |
For example, to produce a JPEG viewport capture, use await page.screenshot({ path: 'protected-page.jpg', type: 'jpeg', quality: 85 });. For a fixed viewport, create the context with await browser.newContext({ viewport: { width: 1440, height: 900 }, httpCredentials: { username, password } }), substituting variables that hold the credentials. Full-page capture changes the capture area; it does not prove that all lazy-loaded content has appeared. Scroll or wait for the page’s own loading behavior if the content depends on scrolling.
4. Keep credentials and access scoped
- Only capture pages you are authorized to access.
- Use environment variables or a secret manager for credentials; do not commit them or print them in diagnostics.
- Limit the browser context to the intended capture and close it afterward. Avoid sharing a context that carries credentials with unrelated pages.
- Prefer HTTPS so credentials are protected in transit. Avoid embedding
username:password@hostin a URL: URLs can be copied into logs, histories, and monitoring systems. - If the protected host depends on an IP allowlist, VPN, private network, or client certificate, run the browser where that access is available. Authentication credentials alone cannot make an unreachable host accessible.
5. Hosted capture options
If you do not want to manage a browser, hosted browser capture services can accept authentication details. Cloudflare Browser Run documents an authenticate object with a username and password on its screenshot endpoint, along with full-page capture and readiness controls. Its documentation also describes waiting for network-idle states or a selector for JavaScript-heavy pages. The service must still be able to reach the protected host, and credentials must be handled according to the service’s security model. See the Cloudflare Browser Run documentation.
Capture documents a service-specific httpAuth parameter containing a base64url-encoded username:password value. That encoding is not encryption, and the parameter format is specific to Capture; do not copy it into Playwright or another service’s request. See Capture’s authentication documentation.
For a managed option from the publisher, ScreenshotNeo is a website screenshot API and MCP server. Its documented options include custom headers, cookies, and Authorization; use an authentication method supported by the target site. Do not assume HTTP Basic Auth is supported by sending credentials in an unverified parameter. The API returns PNG, JPEG, WebP, or PDF captures. Its API documentation describes the request parameters.
Or skip the browser setup
For a page that ScreenshotNeo can access without additional authentication, one GET request returns the screenshot:
curl -G "https://api.screenshotneo.com/v1/shot" \
-d access_key=YOUR_API_KEY \
--data-urlencode url=https://stripe.com \
-o shot.webp
See the ScreenshotNeo API docs for supported request options. ScreenshotNeo accepts cookie and consent banners like a visitor, then removes more than 60 known consent platforms as well as newsletter popups and chat widgets before capture; each cleanup step can be disabled. 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 server gives AI agents tools to take screenshots, get page information, and capture PDFs. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 screenshots.
Create a free ScreenshotNeo account and get 1,000 screenshots a month with no card.
6. Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| The prompt remains or the page shows unauthorized | Credentials are wrong, not authorized for that path, or the prompt is an application login form. | Verify the credentials and URL with the site owner. Identify whether the response is HTTP Basic Auth or an in-page sign-in flow; use the application’s documented flow for the latter. |
| The screenshot contains an access-denied page | The browser navigated successfully to an error response, or the server has additional access controls. | Assert a page-specific success marker before capture. Check server-side restrictions such as IP access rules with the administrator. |
| The screenshot is blank or only partly rendered | Client-side rendering or remote assets have not finished. | Wait for a stable, page-specific selector or content signal. Avoid relying only on a navigation event. For hosted Cloudflare capture, configure a selector or documented network-idle readiness option as appropriate. |
| Content below the fold is missing | The screenshot uses viewport capture, or content loads only after scrolling. | Set fullPage: true and, for lazy content, scroll through the page and wait for the images or sections before capture. |
| The browser cannot reach the URL | The host is private, blocked by a firewall, or available only through a particular network. | Run the browser from an authorized network or arrange access with the administrator. A hosted capture service cannot reach a private origin unless its network path permits it. |
| Credentials appear in logs | Secrets were embedded in a URL or printed during debugging. | Move them to a secret store or environment variables, redact diagnostic output, and rotate exposed credentials. |
7. Performance, reliability, and cost
A local Playwright capture gives you control over browser placement, context configuration, and page checks, while you operate the browser and its runtime. Capture time depends on the target site’s response, authentication, rendering, and assets; the research sources provide no comparative benchmark. Full-page images consume more memory and storage than viewport captures. For repeatable jobs, use a specific readiness condition, bound waits with timeouts, close contexts, and retry only transient failures. Do not endlessly retry rejected credentials.
Hosted capture moves browser operations to a provider, but the provider must be able to reach the site and handle the chosen authentication method. Compare credential handling, network reachability, capture options, and operational cost before choosing. No pricing or performance comparison for Cloudflare Browser Run and Capture is established here. ScreenshotNeo’s stated plans are Free: 1,000 screenshots/month with no card; Starter: $5 for 3,000; Growth: $15 for 15,000; Pro: $39 for 60,000; Scale: $99 for 250,000; Business: $249 for 1,000,000. Yearly billing gives two months free, and every listed feature is on every plan. For clean-page captures, only clean shots are billed; inspect the response’s verdict and billing headers. These product terms are subject to the current plan and API documentation.
8. FAQ
Can I use this with an ordinary website login page?
Not by setting httpCredentials alone. Use the site’s supported sign-in flow and confirm the authenticated state before capture.
Does a successful screenshot call prove authentication worked?
No. The browser can capture an error, redirect, or login page. Check for content unique to the protected page.
Can I capture a private intranet page with a hosted service?
Only if that service has a permitted network path to the host. A URL and credentials do not bypass firewalls or private-network boundaries.
Should I put Basic Auth credentials in the URL?
No. Keep secrets out of URLs because they can be retained in histories and logs; configure credentials through the browser or service’s documented secure mechanism.


