Puppeteer Screenshots with Basic Authentication: Set a Username and Password
Use Puppeteer’s page.authenticate() before navigating to an HTTP-authenticated page, then capture a viewport, full page, or element safely.
To take a Puppeteer screenshot of a page protected by HTTP authentication, call await page.authenticate({ username, password }) before navigating to the page. Then wait for the page state you need and call page.screenshot(). Puppeteer documents Page.authenticate() for HTTP authentication; it enables request interception behind the scenes, which may affect performance. Puppeteer Page.authenticate() documentation
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch();
try {
const page = await browser.newPage();
await page.authenticate({
username: process.env.BASIC_AUTH_USERNAME,
password: process.env.BASIC_AUTH_PASSWORD,
});
await page.goto('https://example.com/protected', {
waitUntil: 'networkidle2',
});
await page.screenshot({ path: 'screenshot.png', fullPage: true });
} finally {
await browser.close();
}
This example uses environment variables so the credentials are not embedded in source. The credentials and URL are placeholders; provide credentials authorized for the page you are capturing.
1. Install Puppeteer and provide credentials
In a Node.js project, install Puppeteer and save the code as an ES module, for example screenshot.mjs:
npm install puppeteer
Set the credentials in the process environment. For example, in a Unix-like shell:
export BASIC_AUTH_USERNAME='your-username'
export BASIC_AUTH_PASSWORD='your-password'
node screenshot.mjs
Use your deployment platform’s secret store in production. Do not commit real credentials, print them in logs, or put them in a screenshot or published example. Puppeteer accepts a credentials object or null; passing null disables authentication. See the API contract.
2. Authenticate before navigation
Create a page, await page.authenticate(), and only then navigate to the protected address. The call provides credentials for HTTP authentication challenges. If the page redirects, test the actual redirect chain and challenge behavior in the browser and Puppeteer version you deploy; do not assume every multi-step authentication setup behaves identically.
This method is for HTTP authentication, such as a server challenge that produces an authentication prompt. It is not a way to fill in an ordinary website login form. A form-based login usually requires navigating to the login page, entering credentials into its fields, and submitting the form, or using an authorized session cookie. Those are separate authentication flows.
3. Choose when the page is ready
The example uses waitUntil: 'networkidle2', also shown in Puppeteer’s screenshots guide. It is one readiness choice, not a guarantee that every application has finished rendering. Puppeteer screenshots guide
domcontentloaded: useful when the document has been parsed and the page does not need all resources to finish before capture.load: waits for the page load event and its dependent resources.networkidle2: can suit pages that settle after network activity, but persistent requests may prevent it from completing.- Wait for a page-specific selector when the screenshot depends on a known element becoming available.
For example, replace the navigation and add a selector wait if the application renders its main content asynchronously:
await page.goto('https://example.com/protected', {
waitUntil: 'domcontentloaded',
timeout: 60_000,
});
await page.waitForSelector('main .report', { timeout: 30_000 });
await page.screenshot({ path: 'report.png', fullPage: true });
Choose a selector that indicates useful content is present, not merely that the document exists. Increase or set timeouts based on the site’s expected response time. Do not treat a longer timeout as a fix for invalid credentials or a page that never reaches the expected state.
4. Select the screenshot scope and output
By default, page.screenshot() captures the viewport. Use fullPage: true for the full document, or clip to capture a specified region. Puppeteer’s screenshot options also support choosing an output type and path; a file extension can determine the image type when saving to a path. ScreenshotOptions reference
| Need | Option or API | Example |
|---|---|---|
| Visible viewport | Default screenshot behavior | await page.screenshot({ path: 'view.png' }) |
| Entire page | fullPage: true |
await page.screenshot({ path: 'full.png', fullPage: true }) |
| A specific element | ElementHandle.screenshot() |
const el = await page.waitForSelector('main'); await el.screenshot({ path: 'main.png' }) |
| Clipped region | clip |
{ clip: { x: 0, y: 0, width: 800, height: 600 } } |
| JPEG or WebP output | type and, for lossy formats, quality |
{ type: 'jpeg', quality: 85 } |
| Transparent background | omitBackground: true |
await page.screenshot({ path: 'transparent.png', omitBackground: true }) |
Screenshot options include path, fullPage, clip, type, quality, encoding, omitBackground, and captureBeyondViewport. PNG is the default type; quality applies to formats other than PNG. Without a path, the screenshot data is returned instead of being written to disk. Check the API reference for the current option details and supported types.
Capture one element
const report = await page.waitForSelector('main .report');
if (!report) throw new Error('Report element was not found');
await report.screenshot({ path: 'report.png' });
Puppeteer’s screenshots guide notes that an element screenshot attempts to scroll a hidden element into view. Element screenshot guidance
Return bytes instead of saving a file
const image = await page.screenshot({ type: 'png', fullPage: true });
// `image` contains the screenshot bytes; send or store it with your own code.
5. Basic authentication caveats
- Confirm the authentication type.
page.authenticate()supplies HTTP-auth credentials; a normal HTML sign-in page is a different mechanism. - Validate both credentials and target. An authentication error page can mean the credentials are wrong, the target requires another authentication method, or a proxy/server challenge is involved.
- Check redirects and multiple origins. A redirect may lead to a different protected host or another challenge. Verify the resulting URL and page content rather than assuming the first response is the final page.
- Consider protocol and deployment differences. The Chrome DevTools Protocol describes authorization challenges for HTTP 401 or 407 responses and includes Basic and Digest schemes, but exact behavior can depend on Puppeteer version, browser, protocol mode, proxy, server, and redirects. Chrome DevTools Protocol Fetch domain
- Remember interception overhead. Puppeteer says authentication enables request interception internally and may affect performance. The documentation does not quantify the impact.
- Always close the browser. A
try/finallyblock closes it even if navigation or capture throws, which matters for repeated jobs and long-running processes.
6. Troubleshooting
| Symptom | Likely cause | What to check |
|---|---|---|
| Screenshot shows an authentication error | Credentials are missing or invalid, or the page uses another login flow. | Confirm the endpoint presents an HTTP authentication challenge and that both environment variables are set correctly. Inspect the final URL and visible page content. |
| Browser still shows a username/password prompt | Authentication was not configured before the challenge, or the server/proxy setup differs from the expected flow. | Await page.authenticate() before page.goto(). Confirm whether the challenge comes from the origin or a proxy and test the deployed browser configuration. |
| Navigation times out | The selected lifecycle event may never occur, the site may be slow, or it may keep network requests open. | Try an appropriate readiness event such as domcontentloaded, then wait for a meaningful selector. Adjust the timeout only when the page is expected to need more time. |
| Capture is blank or missing content | The page may not have authenticated successfully, or client-side content may not yet be rendered. | Check the page URL and expected selector before capturing. Wait for the relevant content and inspect the page state in a controlled run. |
| Screenshot is only the visible area | Full-page capture is off by default. | Set fullPage: true, or capture the target element. |
| Image format or quality is unexpected | Output type may be inferred from the path, PNG is the default, or quality does not apply to PNG. | Set type explicitly when needed, use a matching extension, and set quality only for supported lossy formats. |
| Browser process remains after an error | The close call was skipped on an exceptional path. | Put browser work in try/finally and call await browser.close() in the finalizer. |
7. Performance, reliability, and cost
page.authenticate() turns on request interception behind the scenes, and Puppeteer warns that this might affect performance. The source does not publish a quantified overhead, so measure the effect in your own workload if capture latency matters. Reuse a browser for a controlled batch where appropriate, but keep page state and credentials isolated according to your application’s security needs.
Navigation readiness is a reliability choice: waiting for a network-idle condition can be useful on some pages, while persistent connections can make it unsuitable. A selector wait is often a more direct signal when you know which content must appear. Use timeouts and always close the browser after failures so a stalled capture does not leave a browser process behind.
The dossier provides no Puppeteer price or benchmark figures. Your operating cost depends on where and how you run the browser, the resources your jobs consume, and your own infrastructure. Keep credentials in a secret store and avoid logging them; treat captured images as potentially sensitive if the protected page contains private information.
Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server from Yorker Media. It can capture a URL with one request; its API documentation covers the available parameters. For example, cURL:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
Python:
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)
Node.js:
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
ScreenshotNeo removes cookie banners, popups, and chat widgets before the shot. Bot checks, blank pages, and failed loads are never billed. Its MCP server lets AI agents take screenshots. The Free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. Sign up free for 1,000 screenshots a month, with no card.
FAQ
Does Puppeteer’s authenticate method work with a regular website login form?
No. It supplies credentials for HTTP authentication challenges. A form-based sign-in needs a form interaction or another supported session mechanism.
Can I disable authentication later?
Yes. Puppeteer documents passing null to page.authenticate() to disable authentication.
Does fullPage: true change how authentication works?
No. Authentication happens during page requests; fullPage controls the screenshot area after navigation.
Is networkidle2 always the best wait option?
No. It is one available choice. Use a readiness condition that matches the page, and wait for a specific selector when that is the clearest signal that required content is ready.


