Capture a Logged-In Website Screenshot with Selenium When Login Uses SSO
Use Selenium to complete an authorized SSO login, confirm the app is ready, and capture the right page—even when authentication opens another tab.
To capture a page after SSO login, use Selenium in an authorized browser session, follow the application’s normal sign-in flow, switch to the tab or window that returns to the app if needed, and wait for a stable authenticated page element before saving the screenshot. A completed navigation alone does not guarantee that a JavaScript-rendered page is ready.
This guide uses Python. The same sequence applies to other Selenium bindings: start at the app’s sign-in page, complete the configured SSO flow, confirm the target page is authenticated and rendered, capture it, and close the browser cleanly. SSO details vary by application and identity-provider configuration; this example does not assume a particular provider or protocol.
1. Set up Selenium and a browser
Install Selenium and make a browser available in your environment. Selenium’s driver setup depends on the browser and environment; consult its official WebDriver documentation and browser options guide for the supported browser and driver configuration.
python -m pip install selenium
Set the application entry point and the selectors for your own site. Use an authorized test account and a sign-in route approved by your organization. Do not put passwords, API keys, or other secrets directly in a script committed to source control.
2. Complete SSO, verify the app, and save the screenshot
The example below starts at the application’s sign-in entry point. It waits for an app-specific control that appears only after successful authentication. If the SSO flow opens another window, it checks the available handles and switches to the one containing that authenticated marker. Replace the sample URLs and selectors with values from your application.
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
APP_SIGN_IN_URL = os.environ["APP_SIGN_IN_URL"]
# An app-specific element visible only after authentication.
AUTHENTICATED_MARKER = (By.CSS_SELECTOR, "[data-testid='account-menu']")
# The content that must be present in the screenshot.
TARGET_CONTENT = (By.CSS_SELECTOR, "main h1")
OUTPUT_PATH = Path("artifacts/account-page.png")
options = webdriver.ChromeOptions()
# Uncomment for a headless run in a suitable environment.
# options.add_argument("--headless=new")
# Selenium Manager can configure a compatible driver in supported setups.
driver = webdriver.Chrome(options=options)
wait = WebDriverWait(driver, 30)
try:
driver.get(APP_SIGN_IN_URL)
original_handles = set(driver.window_handles)
# Complete the site's normal SSO interaction here. For an interactive
# flow, this may mean completing sign-in in the browser yourself. For an
# approved test flow, use the site's documented test identity and steps.
# Do not automate around MFA or conditional-access requirements.
# If the identity provider opened another tab/window, inspect handles
# and switch to a context where the authenticated app marker is present.
def authenticated_context(d):
handles = list(d.window_handles)
new_handles = [h for h in handles if h not in original_handles]
candidates = new_handles + [h for h in handles if h not in new_handles]
for handle in candidates:
d.switch_to.window(handle)
try:
if d.find_elements(*AUTHENTICATED_MARKER):
return handle
except Exception:
# A context may be navigating; try the remaining handles.
continue
return False
wait.until(authenticated_context)
wait.until(EC.visibility_of_element_located(AUTHENTICATED_MARKER))
# Navigate to the target only after the app is authenticated, if required.
# For an app route, use the app's normal URL here:
# driver.get("https://app.example.test/account")
wait.until(EC.visibility_of_element_located(TARGET_CONTENT))
OUTPUT_PATH.parent.mkdir(parents=True, exist_ok=True)
if not driver.save_screenshot(str(OUTPUT_PATH)):
raise RuntimeError("WebDriver could not save the screenshot")
print(f"Saved screenshot to {OUTPUT_PATH.resolve()}")
finally:
driver.quit()
The placeholder interaction is deliberate: SSO pages differ, and the correct steps depend on your application’s configuration. For a fully unattended run, follow your organization’s documented test identity and identity-provider setup. When policy requires an interactive MFA checkpoint, complete that approved checkpoint; Selenium is not a way to defeat MFA.
3. Handle SSO redirects and extra windows
In an authorization-code flow, the user-agent is redirected to an authorization server for authentication and then back to the client with an authorization code. OpenID Connect adds identity and authentication semantics on top of OAuth 2.0. The actual pages, redirects, and window behavior depend on the relying-party and identity-provider configuration. See RFC 6749 and OpenID Connect Core.
Selenium screenshots apply to the current browsing context. If the flow creates a new tab or window, inspect driver.window_handles, switch with driver.switch_to.window(handle), and verify the destination with an app-specific element. Handle order has no reliable meaning, so do not assume the last handle is always the correct one.
# Inspect handles while diagnosing a flow.
for handle in driver.window_handles:
driver.switch_to.window(handle)
print(handle, driver.current_url, driver.title)
For a flow that leaves the original tab open and returns there, the new-window check may not be needed. Keep the authenticated-marker wait: it establishes that the browser reached the app, regardless of how the flow used tabs.
4. Wait for the right screenshot state
WebDriver’s navigation completion is based on document readiness. A JavaScript-heavy application may render the target content afterward. Wait for the content that matters to the screenshot, not an arbitrary pause. Selenium recommends explicit waits for conditions and cautions against mixing implicit and explicit waits because timing can become unpredictable. See Selenium waiting strategies.
| Wait for | Use when |
|---|---|
| Authenticated marker | You need to prove the app, rather than the identity provider or sign-in page, is active. |
| Target element visible | The screenshot must include a particular panel, heading, or result. |
| Element text or state | The element exists before it has the final content or state. |
| Known application condition | The page exposes a specific, stable signal that rendering or loading is complete. |
If content appears only after scrolling, scroll to the relevant area and wait for it before capturing. If an animation or delayed chart affects the result, wait for the application’s completion signal or a specific rendered state rather than relying on a fixed sleep.
5. Choose viewport or element capture
driver.save_screenshot("path.png") captures the current browser window. Use it for the visible viewport. To capture a focused component, use an element screenshot; Selenium’s screenshot documentation includes both browser and element examples. See WebDriver screenshots.
# Viewport screenshot
assert driver.save_screenshot("artifacts/viewport.png")
# Focused element screenshot
panel = wait.until(EC.visibility_of_element_located(
(By.CSS_SELECTOR, "[data-testid='report-panel']")
))
panel.screenshot("artifacts/report-panel.png")
An element screenshot is useful when the full browser chrome or surrounding page is irrelevant. Check the resulting dimensions and clipping behavior in your browser setup if the element extends beyond the viewport.
6. Protect the authenticated session and screenshot
- Use an authorized test identity with only the access needed for the capture.
- Store credentials in an approved secret store or environment variables; do not print them or include them in logs.
- Save images to a controlled location. Screenshots can contain personal, account, or business data.
- Close the WebDriver session in a
finallyblock so the browser does not remain open after an error. - Do not copy session tokens or inject cookies as a generic SSO shortcut. Cookie state can be domain-bound and may not represent the server-side state or policy checks required by the application. Selenium cookie operations are scoped to browser context and domain; see Selenium cookie documentation.
Authentication and MFA policies are determined by the application and organization. Use documented test IdP settings or an approved interactive checkpoint when required. OWASP’s Authentication Cheat Sheet provides broader authentication guidance.
Or skip the browser setup
If the page is publicly accessible or you have an authorized way to provide its access context, ScreenshotNeo can capture it through a screenshot API. It does not complete an interactive SSO flow; Selenium remains the fit when the capture depends on that browser-mediated sign-in. ScreenshotNeo supports custom cookies and Authorization, but use those only through an access method approved for the target site.
One GET request returns the screenshot. See the ScreenshotNeo API documentation for request options.
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}`);
await Bun.write('shot.webp', res);
ScreenshotNeo removes cookie and consent banners, newsletter popups, and chat widgets before capture; each step can be turned off. Bot checks, blank pages, failed loads, timeouts, and cache hits cost nothing, and response headers report the page verdict and billing status. Its MCP server lets AI agents use screenshot tools. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000.
Sign up for 1,000 free screenshots a month, with no card.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Screenshot shows the identity provider or sign-in page | The callback has not completed, the wrong handle is active, or the app marker is not present. | Print current URLs and handles during diagnosis; switch to the app context and wait for its authenticated marker. |
| Unexpected tab or window | The SSO flow opened a new context, or returned to an existing one. | Compare handles before and after starting the flow. Inspect each destination and select it by checking a page-specific element, not by handle order. |
| Page loads but content is missing | Document readiness occurred before asynchronous app rendering. | Use an explicit wait for the target content or a stable application-ready signal. Avoid adding a fixed sleep as the only readiness check. |
| Element wait times out | The selector is wrong, the element is in a different context, authentication failed, or the content never rendered. | Check the current URL, handle, selector, and authentication state. Confirm the expected element manually in the same environment. |
| Cookie shortcut does not authenticate | SSO can involve multiple domains, cookies, server state, and policy checks. | Use the normal authorized SSO flow or an organization-approved test setup; do not treat token copying as a generic bypass. |
| MFA prompt blocks automation | The organization requires an interactive checkpoint or another approved test path. | Use a documented test identity or approved interactive step. Do not attempt to bypass MFA or conditional access. |
| Screenshot file is missing or empty | The destination directory does not exist, saving failed, or the driver exited too early. | Create the directory, check the boolean return from save_screenshot, and keep capture inside the driver’s lifetime. |
| Driver startup fails | The browser, driver, or runtime configuration is unavailable or incompatible. | Check the installed browser and Selenium setup against the official driver and browser-options documentation. |
Performance, reliability, and cost
SSO adds redirects and sometimes human interaction, so end-to-end capture time depends on the identity provider, application, and rendering work. Prefer a specific readiness condition over a long global delay. Reuse a browser session only when the test design and security policy allow it; otherwise, a fresh session gives a clearer authentication boundary but requires the sign-in flow each run.
For reliable automation, use stable app-specific selectors, log URLs and window handles without logging secrets, and fail clearly when authentication or page readiness times out. Keep screenshot output controlled and clean up the browser even after exceptions. Selenium itself does not price screenshots; browser compute, test infrastructure, and any services used by the application determine the run cost. ScreenshotNeo pricing and the verdict and billing headers apply to its API captures, not to this Selenium flow.
FAQ
Can Selenium log in through any SSO provider?
Selenium drives browser interactions, but the flow and permitted automation depend on the application’s identity-provider configuration and organization policy. This guide intentionally does not assume a particular provider.
Does driver.get() mean the page is ready for a screenshot?
It means navigation reached the configured document readiness point. Dynamic content may still be loading, so wait for the content that must appear in the image.
Can ScreenshotNeo take a screenshot after an interactive SSO login?
ScreenshotNeo is a screenshot API, not an interactive SSO browser flow. Use Selenium when the page requires completing that flow; use ScreenshotNeo for a page reachable through an authorized request context.
Should I save the browser profile to avoid signing in again?
Only if your organization approves persistent authenticated profiles for this purpose. A saved profile contains sensitive session state and should be protected and managed like a credential.


