How to Capture Screenshots of Pages Behind a Login with Browserless
Capture authenticated pages with Browserless using a saved profile or live browser session, then diagnose incomplete or blocked screenshots.
To capture a page behind a login with Browserless, first make the authenticated state available to the browser that will take the screenshot. For repeated captures, save a Browserless authenticated profile and pass it to the Screenshot REST API. For a short workflow that must perform sign-in first, use one stateful browser session: log in, open the protected page, and capture it in that same session.
The screenshot request cannot capture content that the browser has not authenticated to see. A saved profile restores cookies, localStorage, and IndexedDB before the page renders. A stateful session retains page and cookie state across successive commands. Choose the method that fits how you sign in and how often you need to reuse the state.
1. Choose a login-state method
| Method | Use it when | What persists |
|---|---|---|
| Authenticated profile | You need repeated captures or want to reuse the same saved account state across later browser sessions. | Browserless restores saved cookies, localStorage, and IndexedDB before rendering the requested page. |
| Stateful browser session | The job must interact with the login form, handle a multistep sign-in, or do other browser work before capture. | State remains in that browser session as you issue successive commands. |
| Explicit cookie reuse | You already have the relevant cookies and can transfer them to a later browser session. | Only the cookies you provide; preserve their original attributes. |
Profiles are convenient for repeat jobs after the sign-in flow has been completed and saved. A live session is the direct choice when the browser must navigate the login flow on each run. Cookie injection can be useful in a custom workflow, but it is easy to omit attributes and accidentally create a cookie the site ignores.
2. Save an authenticated profile for repeat captures
- Start an authenticated-profile session using the profile workflow in the Browserless authenticated profiles documentation.
- Connect to the live browser session and complete the site’s normal login flow. If sign-in includes redirects, a one-time code, or a consent step, finish those steps before saving.
- Save the authenticated profile after confirming that the browser is signed in and the protected page is available.
- On a later request to a supported endpoint, including
/screenshot, supply the saved profile as documented by Browserless. The profile is loaded before the page is rendered.
Do not guess the profile parameter name or profile creation URL: use the current endpoint instructions for your Browserless account and API version. The profile is account state; treat it as a secret like a session cookie or API token. If the profile restores but the target is still a login page, revisit the original login and save process to confirm the required state was present when it was saved.
Direct Screenshot REST API request
Browserless’s Screenshot REST API accepts a POST request with the destination URL, an API token, and screenshot options. This shell example reads the token from an environment variable and saves the returned image. Add the profile field using the exact request shape shown in the authenticated profiles documentation for your endpoint version.
export BROWSERLESS_TOKEN="YOUR_API_TOKEN"
curl -X POST "https://production-sfo.browserless.io/screenshot?token=${BROWSERLESS_TOKEN}" \
-H "Content-Type: application/json" \
--data '{
"url": "https://example.com/account/reports",
"options": {
"fullPage": true
}
}' \
-o authenticated-page.png
The request above illustrates the Screenshot REST API capture shape. A profile-enabled request must include the documented profile parameter for your Browserless configuration; the research materials do not specify a stable parameter name or profile-creation endpoint, so those values should be copied from the current official documentation rather than inferred.
3. Log in and capture in one stateful session
Use a stateful session when the browser needs to sign in interactively before it can reach the target. Keep the same browser session alive for the complete sequence: open the login page, enter credentials and complete any required second step, navigate to the protected URL, wait for the authenticated content, then take the screenshot. Browserless sessions retain the page state left by one command for the next command in that session.
The following is the workflow, not a fabricated endpoint-specific script: use Browserless’s current session connection instructions and browser commands for your account to perform these actions in order.
- Connect to a Browserless stateful browser session.
- Navigate to the site’s login page and submit credentials through the site’s normal sign-in flow.
- Wait until a reliable post-login signal appears, such as a known account element or the protected page itself. Do not treat a successful navigation alone as proof of authentication.
- Navigate to the protected page in the same session.
- Wait for the content needed in the image, then capture. Use full-page capture if the full document is needed.
Prefer a wait tied to the actual page state over a fixed delay when the browser tooling and page allow it. For example, wait for a report heading or account-specific element. If the site renders content after scrolling, scroll before capture so lazy-loaded sections have a chance to appear.
4. Reuse cookies carefully
Browserless can read cookies and add them to a later session. Cookie values alone may not be enough: preserve the cookie fields returned by the browser, especially secure and sameSite. A recreated cookie that drops its original security or same-site attributes may be rejected or ignored.
- Copy cookie data from an authenticated browser context rather than constructing a cookie from only its name and value.
- Keep the cookie’s domain, path, expiry, secure, and same-site properties consistent with the returned cookie information.
- Use cookies only with the intended host and scheme; a cookie restricted to HTTPS or a particular domain will not necessarily apply elsewhere.
- Keep cookie dumps out of source control, logs, and public links. Treat them as credentials.
- When the site rotates or expires sessions, refresh the saved state through the normal login flow.
5. Configure the screenshot and page readiness
After authentication, tune the capture to the page rather than assuming the default viewport and immediate capture will show everything. Browserless’s Screenshot REST API supports full-page capture and screenshot options. Its documentation also describes selector capture and scrolling before capture. BrowserQL screenshot options include full-page capture, a CSS selector, waiting for images, output type, quality, and a screenshot timeout.
| Need | Configuration approach | Watch for |
|---|---|---|
| Entire long page | Set fullPage to true. |
Very long pages can take longer and produce large images. |
| One component | Use the documented selector option to capture a CSS-selected element. | Ensure the selector uniquely identifies an element that exists after login. |
| Lazy-loaded sections | Enable scrollPage before capture; combine with full-page capture when appropriate. |
Lazy content may only load after it scrolls into view. |
| Dynamic content | Wait for a selector or page-specific readiness condition; use a delay only when needed. | Navigation completion does not mean client-rendered content is ready. |
| Images | For BrowserQL, use the documented waitForImages option when image completion matters. |
Third-party images can delay completion or fail independently of authentication. |
| Image format and quality | BrowserQL exposes output type and quality options; use the format and setting appropriate for the consuming system. | Quality applies to supported image output, and format choices may affect size and fidelity. |
| Capture deadline | BrowserQL has a screenshot timeout option; its schema documents a 30-second default. | This is a timeout default, not a promise about page load or capture speed. |
Use the exact option names and request nesting in the endpoint you call. Browserless REST and BrowserQL have different request formats; do not assume an option documented for one surface is accepted unchanged by the other.
6. Do-it-yourself examples in cURL, Python, and Node.js
These examples show the documented direct REST capture request for an already authenticated browser context. They demonstrate full-page output. To use a saved profile, add the profile parameter exactly as specified by Browserless for your account and endpoint. For a login-first job, run the login and capture actions in one stateful browser session instead; a standalone screenshot POST does not itself fill and submit a login form.
cURL
export BROWSERLESS_TOKEN="YOUR_API_TOKEN"
curl -X POST "https://production-sfo.browserless.io/screenshot?token=${BROWSERLESS_TOKEN}" \
-H "Content-Type: application/json" \
--data '{
"url": "https://example.com/account/reports",
"options": {
"fullPage": true
}
}' \
-o report.png
Python
import os
import requests
endpoint = "https://production-sfo.browserless.io/screenshot"
token = os.environ["BROWSERLESS_TOKEN"]
payload = {
"url": "https://example.com/account/reports",
"options": {"fullPage": True},
}
response = requests.post(
endpoint,
params={"token": token},
json=payload,
timeout=90,
)
response.raise_for_status()
with open("report.png", "wb") as image_file:
image_file.write(response.content)
Node.js
const token = process.env.BROWSERLESS_TOKEN;
if (!token) throw new Error("Set BROWSERLESS_TOKEN first");
const response = await fetch(
`https://production-sfo.browserless.io/screenshot?token=${encodeURIComponent(token)}`,
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
url: "https://example.com/account/reports",
options: { fullPage: true },
}),
},
);
if (!response.ok) {
throw new Error(`Browserless returned ${response.status}: ${await response.text()}`);
}
const bytes = new Uint8Array(await response.arrayBuffer());
await import("node:fs/promises").then(({ writeFile }) => writeFile("report.png", bytes));
Do not put a real API token in code committed to a repository. These snippets use an environment variable, check the HTTP status in the language examples, and save the response body as an image. Confirm the response content type and image before relying on an automated pipeline.
7. Check whether the result is truly authenticated
Compare the screenshot with what a regular browser shows for the same account and URL. Look for account-specific content, not merely a page that loaded. A login form, access-denied text, empty content region, or unexpected redirect often means the saved state was missing, expired, or not applied to the browser that rendered the page.
- Confirm login finished before saving a profile or moving on in the live session.
- Check that the profile or cookies are supplied to the same endpoint request that opens the protected URL.
- Confirm the target host, protocol, and account match the scope of the authenticated state.
- Wait for an authenticated page marker before capture and inspect the returned image.
- Separate authentication failures from automation blocking: a CAPTCHA or 403 can indicate the site is blocking automation even when credentials are valid.
8. Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Screenshot shows the login page | The profile was saved before login completed, the profile was not attached to the request, or authentication expired. | Complete sign-in and verify the protected page before saving. Confirm the documented profile parameter is present. Refresh the state if the session expired. |
| Cookie exists but is ignored | Cookie attributes such as secure or sameSite were omitted or altered. |
Reuse the complete cookie object returned by the browser, preserving its original attributes, domain, and path. |
| Screenshot is blank or mostly white | The page may not have rendered, may be waiting on client-side work, or may be blocked. | Wait for a page-specific selector or image readiness, inspect the destination in a regular browser, and determine whether the response is a block page. |
| CAPTCHA appears | The site may be detecting or blocking automated browser traffic. | Do not treat successful authentication as proof the site permits automation. Browserless documents a separate /unblock endpoint for some bot-detection workflows; it is a possible next step, not a guarantee of access. |
| 403 or access-denied page | The site or an upstream service denied the automated request. | Check the account, permissions, target URL, and site access policy. If the page indicates automation blocking, consider the documented unblock path where appropriate; it may still fail. |
| Some sections are missing on a long page | Content loads lazily only when it scrolls into view. | Use scrollPage: true before capture and enable full-page capture if you need the whole page. |
| Top section is present but data is stale or absent | The screenshot ran before a client-rendered request or component finished. | Wait for a stable selector or page-specific condition rather than relying on navigation alone. |
| Request returns an error instead of an image | Token, request shape, endpoint, or option names may be wrong; a timeout may also interrupt the capture. | Check the HTTP status and response body, verify the endpoint’s current schema, confirm token placement, and use the option names for the API surface you called. |
| Image output is unexpectedly large or slow | Full-page dimensions, image-heavy content, or a long wait can increase work. | Capture a selector or smaller viewport if that meets the need, avoid unnecessary waits, and use the documented image format and quality controls where available. |
9. Performance, reliability, and cost considerations
Capture time depends on the protected page, its network activity, dynamic rendering, image loading, and whether the browser must scroll a long page. The BrowserQL schema’s default screenshot timeout is 30 seconds; that is a configured timeout, not a performance benchmark. A full-page image or waiting for all images can increase the amount of work. For repeat captures, a saved profile avoids repeating the interactive login flow, while the page itself still needs to load and render.
For reliability, make readiness explicit, preserve session state securely, handle non-success HTTP responses, and inspect whether the returned body is an image. Authentication state can expire or be rotated, and sites can block automation independently of whether login succeeded. Browserless’s /unblock is a separate tool for some block scenarios, not a universal bypass.
Browserless costs and plan limits are not specified in the research available for this article. Check Browserless’s current pricing and account limits before estimating recurring capture cost. Avoid retries without a limit: a failed capture can otherwise repeat the same login, page-load, or block condition.
Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server. Its single GET request captures a public URL as an image or PDF. It does not take over an account login or access private pages that require your credentials, so use Browserless’s authenticated state workflow when the page is genuinely protected. For pages ScreenshotNeo can reach, the call is:
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 request options. ScreenshotNeo accepts cookie and consent banners like a visitor and 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 are not billed, and response headers say which outcome occurred. Its MCP server provides take_screenshot, get_page_info, and capture_pdf for AI agents. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 screenshots.
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}`);
Start free with 1,000 screenshots a month and no card.
10. FAQ
Can the Screenshot REST API log in to a site by itself?
The direct screenshot request captures a page in the browser state available to it. Use a saved authenticated profile or sign in first in a stateful browser session.
Does a Browserless profile save the password?
The documented benefit is restoration of cookies, localStorage, and IndexedDB from a saved browser state. The workflow described here does not require storing a password in the screenshot request.
Will a profile prevent CAPTCHA or a 403?
No. Authentication state and automation access are separate issues. A site can still show a CAPTCHA or deny automated traffic.
Why did the first screenshot omit content below the fold?
Some page content is lazy-loaded when it scrolls into view. Scroll before capture and wait for the content you need.
Can I share an authenticated screenshot URL publicly?
Do not expose API tokens, session cookies, or private account output in public URLs or logs. Store credentials securely and share captures only with people authorized to see their contents.


