Use Playwright to complete the application’s normal Okta sign-in flow, verify that the app is authenticated, navigate to the protected page, and then take the screenshot. For repeated captures, save the verified browser storage state and load it in later contexts—but treat that file like a credential. Do not take the screenshot immediately after clicking Sign in: MFA, enrollment, or other policy checks may still be pending.
Before you start
Use an account authorized to access the application and its target page. Okta sign-in can appear on an Okta-hosted page or as an embedded widget inside the application. With the hosted approach, the user is redirected to Okta and then back to the app after authentication. The app’s integration determines which flow you see. Okta Sign-In Widget documentation
Install Playwright for your project and its browser binaries, then adapt the example below to your application’s sign-in route and a stable element that appears only after successful login. The example uses Node.js with Playwright’s documented JavaScript API. Playwright Page API
Sign in and capture the protected page
This runnable script starts at the app’s ordinary sign-in URL, lets the authorized user complete Okta’s prompts in a visible browser, verifies the authenticated app UI, then opens the protected route and writes a full-page PNG. Replace the three example values with your app’s actual URLs and a reliable post-login selector.
#1 Best Overall
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch({ headless: false });
const context = await browser.newContext();
const page = await context.newPage();
try {
await page.goto('https://app.example.com/login', {
waitUntil: 'domcontentloaded',
});
// Complete the normal Okta sign-in flow, including any required
// MFA or enrollment step, in the visible browser.
await page.pause();
// Use a stable element visible only after the app has authenticated.
await page.getByRole('heading', { name: 'Dashboard' }).waitFor({
state: 'visible',
timeout: 120000,
});
await page.goto('https://app.example.com/reports/monthly', {
waitUntil: 'domcontentloaded',
});
await page.getByRole('heading', { name: 'Monthly report' }).waitFor({
state: 'visible',
timeout: 30000,
});
await page.screenshot({ path: 'capture.png', fullPage: true });
await context.storageState({ path: 'playwright/.auth/user.json' });
} finally {
await browser.close();
}
})();
Run it with node capture.js after installing Playwright and its browser. In this interactive version, page.pause() opens Playwright Inspector so you can finish the real sign-in and verification. For a controlled test environment, you can instead automate the visible steps your app actually presents, but keep any MFA or verification step within the organization’s approved process.
Choose a dependable authentication signal
The dashboard heading in the example is illustrative. Replace it with an app-specific URL or visible UI element that cannot appear before authentication, such as an account control or page heading. Playwright recommends checking a final URL or authenticated UI rather than treating a successful button click as proof that login completed. Playwright authentication
Rank #2
Okta policy and app context can require MFA, authenticator enrollment, or additional verification, so allow for those steps before proceeding. Okta Authentication API and Okta MFA
Capture options
page.screenshot() takes the screenshot; fullPage: true asks Playwright to capture the full scrollable page rather than only the visible viewport. Choose a path appropriate to your run and inspect the Page API documentation for the screenshot options and behavior available in your installed Playwright version.
Rank #3
Reuse a successful login for later captures
When repeated runs do not need a fresh interactive login every time, save storage state only after confirming the app is authenticated. The sample script writes it to playwright/.auth/user.json. Add the auth directory to your version-control ignore rules and restrict access to the file: Playwright warns that it may contain cookies and headers capable of impersonating the account. Playwright authentication
For a later run, create the browser context with the saved file, verify that the session remains valid, and then navigate to the protected page:
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch();
const context = await browser.newContext({
storageState: 'playwright/.auth/user.json',
});
const page = await context.newPage();
try {
await page.goto('https://app.example.com/reports/monthly', {
waitUntil: 'domcontentloaded',
});
await page.getByRole('heading', { name: 'Monthly report' }).waitFor({
state: 'visible',
timeout: 30000,
});
await page.screenshot({ path: 'capture.png', fullPage: true });
} finally {
await browser.close();
}
})();
Storage state covers cookies and local storage; Playwright also documents an option for saving IndexedDB state. If the app relies on session storage, it is not included in the ordinary storage-state file, and the authentication guide describes a separate save-and-restore approach. State can expire, so a later run must still verify the authenticated UI and refresh the saved state when required. BrowserContext API and Playwright authentication
Choose between interactive login and saved state
| Workflow | Setup and verification | MFA in the current run | Expiration consideration |
|---|---|---|---|
| Interactive UI sign-in | Complete the app’s ordinary sign-in flow, then verify a final URL or authenticated UI signal. | Complete any policy-required step during that run. | No saved login file is needed for a single run; the session can still require reauthentication. |
| Saved-state reuse | First sign in and save state after authentication; later runs load it into a new context and verify access. | Not necessarily for every run, while the stored session remains valid. | State may expire and must be refreshed; keep the file private. |
Fix common failures
The screenshot shows Okta or returns to the login page
- Confirm that the script opened the intended app sign-in URL and that the full sign-in flow completed.
- Check whether an MFA, enrollment, or other policy prompt is still waiting. Complete permitted prompts rather than bypassing them.
- Wait for a final app URL or authenticated-only UI element before navigating to the target or capturing. A click completing does not establish that authentication succeeded.
Okta requirements can vary with app and policy context. Okta Authentication API
Do these 3 things before closing this tab:
1Fix the driver behind crashes, sound loss and screen glitches2Clear out junk files and repair common Windows errors3Scan for outdated or missing drivers - takes under a minuteThe saved state does not authenticate the target page
- Confirm the file is for the relevant application origin and was written after a verified login.
- Check whether the session has expired; sign in again through the approved flow and save fresh state.
- If authentication depends on IndexedDB, use the documented storage-state option. If it depends on session storage, use Playwright’s separate session-storage save-and-restore approach.
BrowserContext API documents IndexedDB storage state; Playwright authentication covers session storage.
The script times out waiting for the heading
- Make sure the heading name and selector match the actual app UI, including whether the element is rendered only after navigation completes.
- Use a stable authenticated signal rather than a transient loading message or sign-in button.
- Confirm that the protected route is accessible to the account; a valid login does not necessarily grant access to every app page.
Security and policy boundaries
Prefer the application’s user-facing sign-in flow for screenshot work instead of directly calling Okta’s Authentication API. Okta describes the Sign-In Widget as the easier option for basic use cases, while Authentication API behavior can depend on policy and public applications have documented rate limits. Do not attempt to bypass MFA, CAPTCHA, or organization access controls. Complete the permitted verification or ask the administrator for an approved test setup. Okta Sign-In Widget and Okta Authentication API
Or skip the browser setup
ScreenshotNeo offers a screenshot API, but a protected page still requires authorized access; do not send credentials or private session state to a third-party service unless your organization permits it. For pages the service can access, one GET request returns an image or PDF. For example, the API call below captures a public page:
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 documentation for request options. Its captures can accept cookie/consent banners and remove known consent platforms, newsletter popups, and chat widgets before capture; each step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify page verdict and billing status. An MCP server provides screenshot tools for AI agents. The free plan includes 1,000 shots per month with no card; paid plans start at $5 for 3,000 shots.
Sign up for ScreenshotNeo’s free plan to try 1,000 screenshots a month with no card.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

