ScreenshotNeo

BlogHow-to

Selenium Screenshot of a Logged-In Page Is Blank After Cookie Consent: Fix

A blank Selenium screenshot after consent can mean missing session state, unfinished page rendering, or a mismatch between the DOM and image. Diagnose it step by step.

By the ScreenshotNeo team4 October 20267 min read

A blank screenshot after cookie consent does not identify one cause by itself. First verify that the browser is still logged in and has the intended consent state in the same browser context; then wait for a page-specific readiness condition and compare the rendered page with its post-script DOM. Run the same test headful and headless with the same viewport. Selenium cookie operations act on the current browsing context, and the browser must be on the cookie’s domain when adding a cookie. Selenium’s cookie documentation explains the relevant behavior.

Consent dismissal and authentication often depend on state attached to a browser context, domain, or application session. Do not assume that clicking an “Accept” button, seeing a familiar cookie name, or reusing a previous run means the current page is authenticated. Verify an account-specific element after navigation, inspect the current URL, and inspect cookies without exposing their values in logs.

If you preload a cookie, navigate to a page on the cookie’s domain first. Selenium documents reading cookies, deleting a named cookie, and deleting all cookies. Cookie presence alone does not establish that the application accepts the session.

2. Wait for useful page content, not just navigation

A navigation milestone does not prove that a client-rendered application has finished loading the content you want to capture. Wait for an observable condition tied to the page: for example, a known account indicator is visible and the main content has text, or a loading indicator is gone. Give the condition a bounded timeout and save diagnostics when it expires. A fixed sleep can be useful during investigation, but should not be the only readiness check.

Selenium exposes page-load and asynchronous-script timeouts; it cannot prescribe one universal readiness condition for every site. See the Selenium Chromium WebDriver reference.

3. Runnable Python diagnostic example

This Selenium 4 example assumes the browser can reach the page and that you can sign in through the site’s normal flow. Replace the URL and the two example selectors with selectors from your application. It records diagnostic evidence without printing cookie contents or credentials.

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

PAGE_URL = "https://example.com/account"
ACCOUNT_SELECTOR = "[data-testid='account-menu']"
CONTENT_SELECTOR = "main"
OUTPUT = Path("selenium-diagnostics")
OUTPUT.mkdir(exist_ok=True)

options = webdriver.ChromeOptions()
# Compare with and without this argument. Keep the viewport the same.
options.add_argument("--headless")
options.add_argument("--window-size=1440,1200")

driver = webdriver.Chrome(options=options)
driver.set_page_load_timeout(45)
driver.set_script_timeout(20)
wait = WebDriverWait(driver, 30)

try:
    driver.get(PAGE_URL)

    # If the site requires login, complete its supported login flow here.
    # Keep credentials out of source control and diagnostic output.

    # If consent is not yet stored, use the site's actual consent control.
    # Example only: replace the selector, and remove this block if consent
    # is already handled by your test setup.
    # consent = wait.until(EC.element_to_be_clickable(
    #     (By.CSS_SELECTOR, "button[data-testid='accept-cookies']")
    # ))
    # consent.click()

    # Verify both the authenticated state and useful page content.
    wait.until(EC.visibility_of_element_located(
        (By.CSS_SELECTOR, ACCOUNT_SELECTOR)
    ))
    content = wait.until(EC.visibility_of_element_located(
        (By.CSS_SELECTOR, CONTENT_SELECTOR)
    ))
    wait.until(lambda d: bool(content.text.strip()))

    print("URL:", driver.current_url)
    print("Title:", driver.title)
    print("Viewport:", driver.get_window_size())
    print("Account element visible:", driver.find_element(
        By.CSS_SELECTOR, ACCOUNT_SELECTOR
    ).is_displayed())
    print("Main text length:", len(content.text))
    print("Cookie names:", sorted(
        cookie["name"] for cookie in driver.get_cookies()
    ))

    driver.save_screenshot(str(OUTPUT / "page.png"))
    (OUTPUT / "page.html").write_text(
        driver.page_source, encoding="utf-8"
    )
except TimeoutException:
    print("Timed out waiting for the expected page state.")
    print("URL:", driver.current_url)
    print("Title:", driver.title)
    print("Viewport:", driver.get_window_size())
    driver.save_screenshot(str(OUTPUT / "timeout.png"))
    (OUTPUT / "timeout.html").write_text(
        driver.page_source, encoding="utf-8"
    )
    raise
finally:
    driver.quit()

To compare headful and headless, remove the --headless argument and keep the same browser and driver versions, account, URL, viewport, and wait condition. Use a test account and keep session cookies, authorization headers, and other secrets out of source control and bug reports.

4. Compare the DOM with the screenshot

Capture the screenshot and inspect the page source at the same point in the run. Chrome’s headless --dump-dom mode executes page scripts before serializing the DOM, so it can help distinguish a page that lacks content from an image that fails to reflect content. Chrome’s headless documentation also shows setting a screenshot window size.

  • Expected content is missing from the DOM: investigate navigation, authentication, consent flow, application errors, and network failures first.
  • Expected content exists in the DOM but not in the image: investigate capture timing, viewport and responsive layout, overlays, visibility, and rendering.
  • Headful works but headless does not: the difference narrows the investigation to runtime or rendering conditions. It does not, by itself, prove a browser defect.

These are diagnostic branches, not guaranteed root causes. Record console errors and relevant failed network requests alongside the DOM and image so the evidence points to the failing layer.

5. Troubleshooting common failures

Symptom Likely area to inspect Next step
Account indicator never appears Session missing, expired, rejected, or redirected Check the final URL and login flow; verify state in the same browser context. Inspect cookie names and domains without logging values.
Consent banner returns on every run Consent state is not persisted or is scoped differently Inspect cookies and other site state after accepting consent. Confirm the capture uses the same profile/context and domain.
Wait times out although navigation completed Application content is still rendering, selector is wrong, or the page reached an error state Save the timeout DOM and screenshot, confirm the selector against the actual page, and inspect console and network errors.
Screenshot is blank but page source contains content Timing, viewport, overlay, visibility, or rendering mismatch Compare headful/headless runs with a fixed viewport; inspect element visibility and overlays at capture time.
Headless run differs from headful Different runtime, dimensions, or rendering conditions Match browser/driver versions, viewport, account, network, and readiness condition; change one variable at a time.
Cookie add operation fails Browser is not currently on the cookie’s domain, or cookie attributes are incompatible Navigate to the appropriate domain before adding it and confirm the cookie attributes. Prefer the site’s login flow when possible.
Screenshot captures a loading shell Capture happens before the application’s useful content is ready Wait for a page-specific visible element and meaningful content with a finite timeout; save evidence on timeout.

6. Make the reproduction actionable

Record the Selenium, browser, and driver versions; operating system or container; headless arguments; viewport; page URL with secrets removed; readiness condition; and the screenshot, DOM, console errors, and relevant network failures. Change one variable at a time. Never include cookies, access tokens, or session storage values in shared logs or bug reports.

Performance, reliability, and cost

Use explicit waits for the condition the screenshot depends on, with a bounded timeout. This avoids capturing too early while keeping failures diagnosable instead of allowing an unbounded wait. A fixed viewport makes comparisons more reliable when the application has responsive breakpoints. Reusing a browser session can avoid repeating login and consent flows in a test suite, but only when the session lifecycle and isolation are intentional; stale or cross-test state can make results misleading.

For cost, account for the browser, driver, and execution environment you operate. This diagnostic article has no benchmark or cost figure for Selenium runs. If you use a screenshot API instead, check that service’s billing rules and whether unsuccessful captures are charged.

Or skip the browser setup

If the goal is a screenshot rather than browser automation, ScreenshotNeo is a website screenshot API and MCP server. Its API accepts a URL in one GET request and can return an image or PDF. For authenticated pages, its custom cookies, headers, and Authorization options may be relevant; follow the ScreenshotNeo API documentation and provide only credentials you are authorized to use.

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)
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}`);

ScreenshotNeo removes cookie banners, popups, and chat widgets before capture. 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 for free and get 1,000 screenshots a month with no card.

FAQ

No. Check the resulting browser state and whether the site remembers it in the context and domain used for capture.

No. Verify an account-specific page element and the final URL; the application still has to accept the session.

Should I increase the timeout until the screenshot works?

Only if evidence shows the page needs more time. First confirm the expected condition and inspect the timeout DOM so a wrong selector or failed login does not become a slower silent failure.