How to Capture a Webpage with Basic Authentication Using a Screenshot API
Capture pages protected by HTTP Basic Authentication with a screenshot API or Playwright. Learn which credentials go where, how to wait for rendering, and how to troubleshoot failed captures.
To capture a page protected by HTTP Basic Authentication, use a screenshot API that explicitly accepts the target site’s username and password. Cloudflare Browser Run documents this through an authenticate object on its screenshot request. For a self-managed browser, set Playwright’s httpCredentials on the browser context before navigating.
Keep the screenshot provider’s API token separate from the target site’s credentials: the token authorizes your request to the provider; the username and password authorize the browser at the target site. This guide covers HTTP Basic Authentication, not a website’s HTML login form.
1. Confirm the authentication type
HTTP Basic Authentication is the browser-level username/password challenge that appears before a protected page loads. An application login form is part of the website itself and usually requires interacting with the form or supplying a valid session cookie. A bearer token is a third case: it belongs in an authorization header when the rendering service supports custom headers.
If you are unsure, open the page in a browser. A native browser credential prompt usually indicates HTTP authentication; a page with branded username and password fields is an application login. Choose a capture method that supports the mechanism the target uses.
2. Capture with Cloudflare Browser Run
Cloudflare’s screenshot quick action accepts the target URL and an authenticate object. The request’s Authorization: Bearer header is for Cloudflare. The JSON object’s username and password are for the protected target page. See Cloudflare’s screenshot endpoint guide and API reference for current endpoint and request details.
cURL
curl -X POST 'https://api.cloudflare.com/client/v4/accounts/<accountId>/browser-run/screenshot' \
-H 'Authorization: Bearer <cloudflare-api-token>' \
-H 'Content-Type: application/json' \
-d '{
"url": "https://example.com/protected-page",
"authenticate": {
"username": "<target-username>",
"password": "<target-password>"
},
"screenshotOptions": {
"fullPage": true
},
"gotoOptions": {
"waitUntil": "networkidle0",
"timeout": 45000
}
}' \
--output authenticated-screenshot.png
Replace the account ID and API token with your Cloudflare values, and use the target site’s credentials in authenticate. Cloudflare’s guide also documents viewport and screenshot options, selector waits, and other capture controls. Network-idle waits can be useful for pages that finish rendering asynchronously, but pages with persistent connections may never become idle; use a selector wait or a suitable navigation condition for those pages.
Python
This example uses Python’s standard library to send the same JSON request and write the returned image bytes to a file. Put the three secrets in environment variables; do not commit them to source control.
import json
import os
import urllib.request
account_id = os.environ["CLOUDFLARE_ACCOUNT_ID"]
api_token = os.environ["CLOUDFLARE_API_TOKEN"]
body = {
"url": "https://example.com/protected-page",
"authenticate": {
"username": os.environ["TARGET_USERNAME"],
"password": os.environ["TARGET_PASSWORD"],
},
"screenshotOptions": {"fullPage": True},
}
request = urllib.request.Request(
f"https://api.cloudflare.com/client/v4/accounts/{account_id}/browser-run/screenshot",
data=json.dumps(body).encode("utf-8"),
headers={
"Authorization": f"Bearer {api_token}",
"Content-Type": "application/json",
},
method="POST",
)
with urllib.request.urlopen(request, timeout=90) as response:
image = response.read()
with open("authenticated-screenshot.png", "wb") as output:
output.write(image)
Set CLOUDFLARE_ACCOUNT_ID, CLOUDFLARE_API_TOKEN, TARGET_USERNAME, and TARGET_PASSWORD in the process environment before running. A successful HTTP response alone does not prove the intended page was captured: open the image and confirm its content.
Node.js
This uses the built-in fetch and file-system APIs available in current Node.js releases.
import { writeFile } from 'node:fs/promises';
const accountId = process.env.CLOUDFLARE_ACCOUNT_ID;
const apiToken = process.env.CLOUDFLARE_API_TOKEN;
const response = await fetch(
`https://api.cloudflare.com/client/v4/accounts/${accountId}/browser-run/screenshot`,
{
method: 'POST',
headers: {
Authorization: `Bearer ${apiToken}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
url: 'https://example.com/protected-page',
authenticate: {
username: process.env.TARGET_USERNAME,
password: process.env.TARGET_PASSWORD,
},
screenshotOptions: { fullPage: true },
}),
},
);
if (!response.ok) {
throw new Error(`Screenshot request failed: HTTP ${response.status} ${await response.text()}`);
}
await writeFile('authenticated-screenshot.png', Buffer.from(await response.arrayBuffer()));
The screenshot response is binary, so save its bytes rather than trying to parse it as JSON. Check the provider’s current API reference for response format and available capture options.
3. Capture with Playwright when you manage the browser
Playwright lets you configure HTTP credentials on a browser context and use the normal page screenshot method. Install Playwright and its browser binaries according to the official installation guide. The following script uses the documented HTTP authentication and page screenshot APIs.
import { chromium } from 'playwright';
const browser = await chromium.launch();
const context = await browser.newContext({
httpCredentials: {
username: process.env.TARGET_USERNAME,
password: process.env.TARGET_PASSWORD,
},
});
try {
const page = await context.newPage();
await page.goto('https://example.com/protected-page', {
waitUntil: 'domcontentloaded',
timeout: 45_000,
});
await page.screenshot({
path: 'authenticated-screenshot.png',
fullPage: true,
});
} finally {
await context.close();
await browser.close();
}
For a client-rendered page, wait for a meaningful element after navigation, for example await page.locator('main article').waitFor(), before capturing. Use a selector that indicates the actual content is ready, not merely that the document exists.
4. Choose the right capture options
| Need | What to configure | Tradeoff |
|---|---|---|
| Full document | Cloudflare screenshotOptions.fullPage or Playwright fullPage: true |
Long pages can take longer and produce large images. |
| Specific viewport | Set the provider’s viewport options or Playwright context viewport | The page may lay out differently at another width; choose the dimensions that match the use case. |
| Application content loads after navigation | Wait for a stable selector or an appropriate navigation condition | Long fixed delays waste time and may still miss slower content. |
| Session-based page | Supply valid cookies if the provider supports them | Cookies are not interchangeable with HTTP Basic credentials. |
| Bearer-token page | Use a supported custom authorization header | Do not place a bearer token in the Basic Auth username or password fields. |
Cloudflare documents authenticate, cookies, custom headers, gotoOptions, viewport and screenshot controls for Browser Run. Consult its API reference for the exact supported fields and formats for your account and endpoint.
5. Protect credentials and the target
- Use HTTPS for the target and the provider API. RFC 7617 explains that Basic Authentication passes the user ID and password in a form that requires an external secure system such as TLS for protection. See RFC 7617.
- Keep the provider API token and target-site credentials in a secret manager or runtime environment, not source code, command history, screenshots, or logs.
- Limit target credentials to the minimum access needed, and avoid using a personal account for automated captures.
- Do not put credentials in the target URL. URLs can be copied into logs and diagnostics; use the documented credential field or browser context option.
- Remember that a hosted screenshot API receives the target credentials as part of rendering the page. If your policy requires credentials to remain inside your own infrastructure, run the browser yourself.
6. Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| 401 or repeated credential prompt | Incorrect target username/password, wrong auth realm, or target is not using Basic Auth | Verify the credentials in a browser, confirm the page’s auth type, and pass the values to authenticate or httpCredentials. |
| Provider returns an authorization error | The provider API token is missing, invalid, or lacks permission | Check the provider token and account ID separately from the target credentials. Use the required API authorization header and permissions. |
| Image shows a login page | The target uses an HTML form or session authentication instead of HTTP Basic Auth | Use an application-specific login flow or a valid session cookie if supported. Basic credentials alone do not complete a web form. |
| Image shows access denied or a bot challenge | The target rejected the browser request or access policy blocks the capture environment | Check the target’s access rules and permitted network. Do not assume adding credentials resolves a separate challenge. |
| Content is missing or half-rendered | Capture started before client-side rendering or lazy loading completed | Wait for a content selector or suitable load condition; inspect the image to confirm the expected state. |
| Request times out | Slow target, overly strict network-idle wait, or a page with ongoing requests | Set a suitable timeout and wait for a stable selector or a less restrictive navigation state. |
| Saved file is not an image | An error response was saved as though it were a screenshot, or the response format differs | Check HTTP status and response headers before writing the body; inspect the file type and provider response. |
| Screenshot is blurry | Capture scale is low for the chosen viewport or output use | Increase device scale where supported, or choose a suitable viewport and output size. |
7. Performance, reliability, and cost considerations
Capture time depends on the target page, assets, and wait condition. Full-page captures and large viewports can require more rendering and produce larger files. Use the smallest viewport and page area that satisfy your task, and wait for a specific ready state instead of adding an unnecessarily long fixed pause.
For a reliable pipeline, check the HTTP response before saving it, retain enough response information to diagnose failures without recording secrets, and validate a sample of resulting images. Set timeouts appropriate to your target and retry only transient failures; repeated retries will not fix invalid credentials or a login-type mismatch.
The supplied documentation establishes the authentication and capture options, but does not provide a directly comparable price or speed result for this workload. Check the provider’s current pricing and limits before estimating recurring capture costs.
8. Or skip the browser setup
ScreenshotNeo is a screenshot API and MCP server. Its documented API call is one GET request, but the available product facts do not list a target-site HTTP Basic Authentication parameter. Do not send protected-page credentials to this endpoint or assume it can authenticate to that page; use the Cloudflare or Playwright method above for the Basic Auth capture itself.
For pages the endpoint can access, here is the documented one-call pattern. See the ScreenshotNeo API documentation for the API details.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
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, and paid plans start at $5 for 3,000.
Sign up for ScreenshotNeo’s free plan to try it on pages accessible to the endpoint.
FAQ
Can I pass Basic Auth credentials in the page URL?
Use the documented authentication field or browser-context setting instead. URL credentials can leak into logs and are not the documented pattern in these examples.
Does an API key authenticate me to the protected website?
No. The provider API token authorizes the screenshot request; the target credentials authorize access to the protected page.
Will this work with an HTML login form?
Not by itself. A form login requires a site-specific interaction or an authenticated session, such as a supported session cookie.
Should I always wait for network idle?
No. Persistent requests may prevent an idle state. A selector that marks the content you need is often a clearer readiness condition.


