ScreenshotNeo

BlogHow-to

How to Screenshot a Website That Requires Login with Python Selenium

Log in with Selenium, wait for protected content, and save a reliable screenshot. Includes cookie reuse, full-page options, troubleshooting, and an API alternative.

By the ScreenshotNeo team4 October 20269 min read

Use Selenium to open the site’s login page, submit credentials through its normal form, wait for a site-specific sign that authentication succeeded, then navigate to the protected page and call driver.save_screenshot("screenshot.png"). Selenium cannot supply universal login selectors: each site has its own form, redirects, and authentication requirements. The example below uses placeholders that you must adapt to a site and account you are authorized to access.

1. Install Selenium and prepare credentials

Install Selenium in your Python environment. Selenium’s getting-started guide shows creating a Chrome WebDriver, navigating, locating controls, and closing the session. See the Selenium Python getting-started guide and waits documentation.

python -m pip install selenium

Provide credentials at runtime using the secret-management mechanism for your environment. Do not commit passwords or session cookies to source control, print them in logs, or place them in a screenshot or shared artifact.

2. Log in, wait for the protected page, and capture it

This runnable script uses environment variables for credentials, explicit waits for both authentication and target content, a bounded timeout, and a finally block to close the browser. Replace the example URLs and selectors with the real site’s values. The selector [data-account-home] is only an example of an authenticated-state marker; it is not a selector that works on every site.

import os
from pathlib import Path

from selenium import webdriver
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait

username = os.environ["SITE_USERNAME"]
password = os.environ["SITE_PASSWORD"]
login_url = "https://example.com/login"
target_url = "https://example.com/account/report"
output_path = Path("screenshot.png")

driver = webdriver.Chrome()
try:
    wait = WebDriverWait(driver, 20)
    driver.get(login_url)

    wait.until(EC.visibility_of_element_located((By.NAME, "username"))).send_keys(username)
    driver.find_element(By.NAME, "password").send_keys(password)
    driver.find_element(By.CSS_SELECTOR, "button[type='submit']").click()

    # Replace this with an element that appears only after successful login.
    wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, "[data-account-home]")))

    driver.get(target_url)
    # Replace main with a selector for the content you actually need to capture.
    wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, "main")))

    if not driver.save_screenshot(str(output_path)):
        raise OSError(f"Could not write screenshot to {output_path}")
    print(f"Saved {output_path.resolve()}")
except TimeoutException as exc:
    raise RuntimeError(
        "Timed out waiting for the login success marker or target content. "
        "Check the selectors, authentication flow, and page state."
    ) from exc
finally:
    driver.quit()

The login success marker should distinguish the authenticated application from a still-loading page, a rejected login, or a redirect back to the login form. If the site sends users directly to the target after login, the extra driver.get(target_url) is still generally useful for making the intended destination explicit, but adapt the sequence to the site’s supported flow.

3. Choose the right waits and selectors

Selenium navigation waits for a configured document readyState (by default, complete), but a JavaScript application can continue changing after that point. Selenium describes races between browser state and automation commands as a common cause of flaky scripts, and recommends waiting for a condition tied to the state the script needs. See Selenium’s wait guidance.

  • After submitting the form: wait for an account-specific element, authenticated navigation, or another reliable success condition.
  • Before capture: wait for the protected content itself to be visible. If a specific chart or report matters, wait for that element rather than a generic page container.
  • For asynchronous updates: choose a condition that represents the final content state, such as a loading indicator disappearing or a result element appearing.
  • Use a bounded timeout: if the condition does not occur, fail with an actionable error rather than waiting forever.

A fixed sleep may waste time when a page is fast and still be too short when it is slow. A condition-based wait ties progress to an observable page state. Selenium does not know the correct success selector for an unspecified site; inspect the page and choose one that is specific to the workflow.

4. Understand screenshot size and output

driver.save_screenshot("screenshot.png") saves the current browser window as a PNG and returns a Boolean indicating whether the file was written successfully. Check the result and choose a path the process can write. The standard current-window capture should not be assumed to include the full document below the viewport.

If your next step needs image data rather than a file, Selenium’s Python WebDriver API also documents get_screenshot_as_png(), which returns PNG bytes, and get_screenshot_as_base64(), which returns a base64 string. See the Selenium Python WebDriver API.

# Write PNG bytes yourself, for example when passing them to another function.
png_bytes = driver.get_screenshot_as_png()
Path("screenshot.png").write_bytes(png_bytes)

# Base64 representation for a consumer that specifically needs it.
png_base64 = driver.get_screenshot_as_base64()

For full-document capture, support depends on browser and driver. The Selenium Firefox Python API documents full-page screenshot methods such as save_full_page_screenshot; confirm support and behavior for the browser and driver version used by your project. See the Firefox WebDriver API. For long pages, also consider whether a single tall image is usable by your downstream system and whether lazy-loaded sections need to be brought into view before capture.

5. Reuse an authenticated session with cookies

When the site permits it, reusing an existing session cookie can avoid submitting the login form on every run. WebDriver requires the browser to be on a domain where the cookie is valid before adding it. Cookie domain, path, security settings, expiration, and the site’s authentication design can all affect whether reuse works; adding a cookie alone does not guarantee an authenticated session. See Selenium’s cookie documentation.

from selenium import webdriver
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait

# Obtain this cookie securely from an authorized source; never hard-code it.
auth_cookie = {
    "name": "session",
    "value": "LOAD_FROM_SECURE_RUNTIME_STORAGE",
    "domain": "example.com",
    "path": "/",
    "secure": True,
    "httpOnly": True,
}

driver = webdriver.Chrome()
try:
    # First visit the cookie's domain before adding it.
    driver.get("https://example.com/")
    driver.add_cookie(auth_cookie)
    driver.get("https://example.com/account/report")
    WebDriverWait(driver, 20).until(
        EC.visibility_of_element_located((By.CSS_SELECTOR, "main"))
    )
    if not driver.save_screenshot("report.png"):
        raise OSError("Could not write report.png")
finally:
    driver.quit()

Do not log or share cookie values: a session cookie can grant account access. If the site uses additional checks, short-lived tokens, or a different authentication mechanism, use its supported login flow instead.

6. Handle special login flows and sensitive output

  • Multi-factor authentication: follow the site’s supported process and wait for a clear post-authentication marker. Do not assume form submission alone means the session is ready.
  • Redirects: verify whether login lands on the target, an account dashboard, or a consent/interstitial page; navigate to the target only after the authenticated state is established.
  • Lazy content: if a section loads only when scrolled into view, bring it into view and wait for its content before capturing. A viewport screenshot only shows the current window.
  • Sensitive pages: screenshots may contain personal, confidential, or regulated data. Store them in a protected location and restrict access and retention.
  • Authorization: automate only accounts and pages you are permitted to access, and follow the target site’s applicable terms and rules.

7. Troubleshoot common failures

Symptom Likely cause Fix
Timeout waiting for username or password field The selector differs, the form is inside an iframe, or the page has not rendered the form. Inspect the page’s actual markup, use the correct selector, wait for the form, and switch to the relevant iframe when necessary.
Timeout waiting for authenticated marker Login failed, a redirect or MFA step is pending, or the example marker does not exist on this site. Check the resulting URL and visible page state, handle the supported authentication steps, and select a marker unique to a successful login.
Screenshot shows login page The script captured before authentication succeeded or the target redirected the session. Wait for an authenticated-state condition, then verify the target content is visible immediately before capture.
Screenshot is blank or content is missing The page or a client-rendered component is still loading, or the selected area is lazy-loaded. Wait for the specific content, bring lazy sections into view when needed, and confirm the browser is on the expected URL.
Screenshot file is not created The process cannot write to the path, or save_screenshot returned False. Use a writable absolute or project-relative path, check the Boolean result, and ensure the parent directory exists.
Cookie addition fails or does not log in The browser is not on the cookie’s domain, cookie scope or expiry is wrong, or the site needs additional authentication state. Visit the valid domain first, verify cookie scope and freshness securely, or use the site’s normal login flow.
Capture is only the visible viewport Current-window capture does not promise a full-document image. Use a browser-specific full-page method supported by the chosen setup, or capture the required sections separately.

8. Performance, reliability, and cost

A WebDriver run starts and controls a browser, so it is useful when the workflow depends on interacting with a login form or an already authorized browser session. Keep waits bounded, reuse a browser session for multiple pages when appropriate, and always quit the driver so browser processes do not accumulate after failures. Browser, driver, Selenium version, headless/display setup, and site behavior can affect results; confirm current browser-specific support before depending on a particular capture mode.

There is no universal runtime or cost figure for this workflow: the target site, browser environment, login steps, and infrastructure determine both. Account for the cost of running browser processes and securely handling credentials and output in your own environment. The Selenium references describe API behavior and synchronization, not a benchmark for a particular site.

Or skip the browser setup

If you do not need to automate an interactive login flow, ScreenshotNeo is a website screenshot API and MCP server. Its one-call capture can be useful for public pages: cookie banners, newsletter popups, and chat widgets are removed before the shot; bot checks, blank pages, and failed loads are never billed. An MCP server lets AI agents use take_screenshot, get_page_info, and capture_pdf. It offers 1,000 screenshots a month free with no card, and paid plans start at $5 for 3,000.

ScreenshotNeo is not a substitute for Selenium when the target requires signing in with your credentials: use it only for pages it can access without your private browser session. Its API supports a single GET request for a URL, with PNG, JPEG, WebP, or PDF output. See the ScreenshotNeo API documentation.

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,
)
r.raise_for_status()
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}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
const image = Buffer.from(await res.arrayBuffer());
await import('node:fs/promises').then(fs => fs.writeFile('shot.webp', image));

Sign up for ScreenshotNeo’s free plan: 1,000 screenshots a month, no card required.

FAQ

Can Selenium log in to any website with the same code?

No. Form selectors, redirects, and authentication steps are site-specific. Adapt the example to the site’s supported flow and choose a success condition that exists on that site.

Does a successful page load prove that login worked?

No. A browser can finish navigation while the application is still changing, or land back on a login page. Wait for an authenticated-state marker and the target content.

Can ScreenshotNeo capture a page behind my login?

The one-call example is for a URL ScreenshotNeo can access. Use Selenium for a workflow that depends on your private authenticated browser session.

Does Selenium save a full-page screenshot by default?

The documented save_screenshot method captures the current window. Full-document capture depends on browser and driver support; check the API for the browser you use.