How to screenshot a logged-in page when the site opens a new tab
Capture the page a site opens in a new tab, check that it is signed in, and save a viewport, full-page, or element screenshot with Playwright.
Direct answer: In Playwright, start waiting for the popup before clicking the link or button that opens the new tab. Await the popup page, verify that the expected signed-in content loaded, then call screenshot() on that page. For a manual capture in Firefox, switch to the new tab and use Take Screenshot or Ctrl+Shift+S on Windows/Linux and Command+Shift+S on macOS.
A new tab is a separate page. Capturing the original page will not capture the page opened in the new tab. Also, a popup event does not prove that authentication carried over: that depends on the site, so check the actual page content before saving.
Capture the new tab manually in Firefox
- On the signed-in page, activate the link or button that opens the page in a new tab.
- Switch to the new tab and confirm the expected account or private content is visible.
- Right-click an empty part of the page and choose Take Screenshot, or use Ctrl+Shift+S on Windows/Linux or Command+Shift+S on macOS.
- Choose the visible area for the current viewport, or Save full page to include below-the-fold content.
These menu labels and shortcuts are Firefox-specific. For a different browser, use its own screenshot feature or automate capture with the browser’s supported tooling. See Mozilla’s Firefox screenshot instructions.
Capture a popup with Playwright in JavaScript
Install Playwright and its browser binaries using the official installation instructions. The example below assumes you have a signed-in browser context and a source page where the target control is available. Replace the selector and readiness check with ones that match your application.
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch({ headless: true });
const context = await browser.newContext({
// For an existing signed-in session, load a saved storage state:
// storageState: 'playwright/.auth/user.json',
});
const page = await context.newPage();
try {
await page.goto('https://example.com/account', {
waitUntil: 'domcontentloaded',
});
// Register the popup wait before the click so the event is not missed.
const popupPromise = page.waitForEvent('popup');
await page.getByRole('link', { name: 'Open account report' }).click();
const popup = await popupPromise;
await popup.waitForLoadState('domcontentloaded');
// Use a site-specific assertion or locator to confirm signed-in content.
await popup.getByText('Account report', { exact: true }).waitFor({
state: 'visible',
});
// Viewport screenshot. Set fullPage: true to capture the full scrollable page.
await popup.screenshot({ path: 'logged-in-page.png', fullPage: true });
} finally {
await context.close();
await browser.close();
}
})();
The example saves a full-page PNG. Remove fullPage: true to capture the current viewport. For an element capture, use a locator screenshot such as await popup.locator('[data-testid="report"]').screenshot({ path: 'report.png' }). Playwright documents viewport, full-page, and locator screenshots in its screenshot guide.
Use a saved signed-in session when needed
Playwright does not sign in to your application merely because a new tab opened. If your workflow needs an existing authenticated session, use a browser context configured with valid storage state, or perform your normal sign-in flow before triggering the popup. Treat saved authentication state as a secret: do not commit it to source control or share it in logs. Whatever method you use, verify the expected account content in the popup before capturing.
Handle newly created pages from the browser context
If the new tab is not clearly a popup associated with the source page, listen for the browser context’s page event before performing the action. This handles pages created in the context, including links using target="_blank".
const newPagePromise = context.waitForEvent('page');
await page.getByRole('link', { name: 'Open account report' }).click();
const newPage = await newPagePromise;
await newPage.waitForLoadState('domcontentloaded');
await newPage.screenshot({ path: 'new-tab.png' });
Use the popup event when the new page belongs to a particular source page; use the context event when you need to observe a page created anywhere in that browser context. Start the wait before the action in either case. See the Playwright Page API and Playwright pages guide.
Choose what to capture
| Goal | Playwright capture | What it includes |
|---|---|---|
| What is visible now | await popup.screenshot({ path: 'view.png' }) |
The current viewport, by default. |
| Everything below the fold | await popup.screenshot({ path: 'full.png', fullPage: true }) |
The full scrollable page as a tall image. |
| One panel or control | await popup.locator('.report').screenshot({ path: 'panel.png' }) |
The selected element. |
Full-page capture can produce a large image on long pages. Use a locator screenshot when only one region matters. Firefox’s manual tool also offers visible-area and full-page choices.
Readiness, authentication, and reliability
- Wait for the right event: create the popup or context page wait before clicking. Otherwise, a fast popup can open before the listener is registered.
- Wait for a useful state:
domcontentloadedis a synchronization point, not proof that the page is ready for your screenshot. Wait for a page-specific element that indicates the needed content is visible. - Do not assume sign-in carried over: the cited popup and screenshot documentation does not establish how any particular site handles authentication in a new tab. Check the content, and handle redirects or sign-in screens explicitly.
- Avoid treating network idle as universal readiness: pages with ongoing requests may never become idle, and Playwright’s API documentation discourages relying on that state as a general testing signal.
- Keep capture deterministic: use stable locators and explicit content checks. If the page renders data asynchronously, wait for the relevant content rather than adding an arbitrary delay.
Common problems and fixes
| Problem | Likely cause | Fix |
|---|---|---|
| Popup wait times out | The action did not open a new page, the selector clicked the wrong control, or the listener started too late. | Register waitForEvent('popup') before clicking. Confirm the control’s behavior; if a page is created at context scope, wait for the context page event instead. |
| Screenshot shows the original page | The screenshot was called on the source page. |
Call screenshot() on the returned popup or new page object. |
| Screenshot shows a sign-in screen | The new page is not authenticated, the session expired, or the site requires a separate sign-in step. | Inspect the popup URL and content, establish a valid session using your normal workflow, and assert a signed-in element before capture. |
| Screenshot is blank or incomplete | The initial navigation began, but the content you need has not appeared yet. | Wait for a locator that represents the finished content. Use the site’s actual readiness signal instead of assuming navigation alone is enough. |
| Full-page image is unexpectedly large | The page is long or contains large regions. | Capture only the viewport or a specific locator if the whole document is unnecessary. |
| Network-idle wait hangs or is unreliable | The site maintains background requests or the state does not match the content you need. | Wait for a meaningful page element or application-specific completion signal. |
Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server. Its one-request API captures a URL as PNG, JPEG, WebP, or PDF. For the page opened in a new tab, pass the target URL directly. A URL-only request does not reproduce a browser session that requires authentication; use it only when the page is publicly accessible or otherwise reachable without your private session.
See the ScreenshotNeo API documentation for authentication and 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,
)
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 require('node:fs/promises').writeFile('shot.webp', Buffer.from(await res.arrayBuffer()));
- Cookie and consent banners, newsletter popups, and chat widgets from 60+ known platforms are removed before capture; each cleanup step can be turned off.
- Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed. Response headers report the page verdict and billing status.
- An MCP server gives Claude, Cursor, and other MCP clients tools to take screenshots, get page information, and capture PDFs.
- The free plan includes 1,000 screenshots per month with no card. Paid plans start at $5 for 3,000 screenshots; every feature is available on every plan.
Sign up for 1,000 free screenshots a month, with no card.
Cost and performance notes
With Playwright, you manage the browser process and session in your own environment. Capture time and resource use depend on the page, browser, and whether you capture an element, viewport, or full page; no universal timing is implied here. Reuse a browser context when your workflow needs the same session for multiple pages, and close pages and browser resources when finished. For hosted capture, ScreenshotNeo’s free allowance is 1,000 per month; paid tiers are Starter $5 for 3,000, Growth $15 for 15,000, Pro $39 for 60,000, Scale $99 for 250,000, and Business $249 for 1,000,000. Yearly billing gives two months free. Only clean shots are billed, and the response identifies the page verdict and billing status.
FAQ
Does opening a new tab keep the user logged in?
It depends on the site and the session. The popup event only tells you a page opened; inspect that page for the signed-in state.
Can I capture a page opened by target="_blank"?
Yes. Wait for the popup on the source page, or listen for a new page on the browser context, then screenshot the resulting page object.
Should I use a viewport or full-page screenshot?
Use a viewport capture for what is currently visible, full-page for below-the-fold content, and a locator capture when only one region matters.
Can a URL screenshot API capture my private logged-in page?
Not from a URL alone when the site requires your private browser session. Use an authenticated browser workflow for that case; use a URL API for pages it can reach.


