ScreenshotNeo

BlogHow-to

How to Capture a Screenshot of an Authenticated Page with a Sticky Consent Bar

Use Playwright to restore a signed-in session, handle a sticky consent bar through its real controls, and capture the viewport, full page, or a specific element.

By the ScreenshotNeo team4 October 20268 min read

Use Playwright to load a saved authenticated browser state, open the page, interact with the consent bar’s real control, wait for the page to reach the state you need, and then capture a viewport, full page, or element screenshot. The correct consent button and selector depend on the site and your test scenario; do not assume every banner should be accepted. Protect the saved state and resulting screenshots because they may expose a signed-in account or private information.

This guide uses JavaScript with Playwright. The same workflow applies whether you are creating a one-off capture or adding screenshots to a repeatable test.

1. Save an authenticated browser state

Log in through the site’s normal flow once, verify that login succeeded, and save the browser context’s storage state. Playwright’s authentication guide describes reusing that state in later contexts. Keep the file in a git-ignored directory: it can contain cookies and headers that could be used to impersonate the account. Refresh it when the session expires. See the Playwright authentication guide.

Install Playwright Test and its browser binaries if your project does not already have them:

npm install --save-dev @playwright/test
npx playwright install chromium

Create scripts/save-auth-state.mjs. Replace the URL and selectors with stable, site-specific values. Use a dedicated test account where possible.

import { chromium } from '@playwright/test';

const browser = await chromium.launch({ headless: true });
const context = await browser.newContext();
const page = await context.newPage();

await page.goto('https://your-authorized-site.example/login', {
  waitUntil: 'domcontentloaded'
});

// Complete this step using the site's authorized login flow.
await page.getByLabel('Email').fill(process.env.TEST_EMAIL);
await page.getByLabel('Password').fill(process.env.TEST_PASSWORD);
await page.getByRole('button', { name: 'Sign in' }).click();

// Verify an authenticated state before saving credentials.
await page.getByRole('heading', { name: 'Account overview' }).waitFor();
await page.context().storageState({ path: 'playwright/.auth/user.json' });

await browser.close();

Add playwright/.auth/ to .gitignore. Do not commit the state file, print its contents in logs, or share it as an ordinary screenshot artifact. If the site uses a login flow that cannot be automated, obtain the state through an authorized setup process and protect it the same way.

Create scripts/capture-authenticated.mjs. The example chooses “Reject optional cookies” to make the intended preference clear; use the site’s actual control and the choice appropriate for your scenario. If the banner appears in a frame, locate the frame and use the same explicit-control approach there.

import { chromium } from '@playwright/test';

const browser = await chromium.launch({ headless: true });
const context = await browser.newContext({
  storageState: 'playwright/.auth/user.json'
});
const page = await context.newPage();

try {
  await page.goto('https://your-authorized-site.example/account', {
    waitUntil: 'domcontentloaded',
    timeout: 30_000
  });

  // Fail clearly if the saved session expired or login did not carry over.
  await page.getByRole('heading', { name: 'Account overview' }).waitFor({
    state: 'visible',
    timeout: 15_000
  });

  // This is an illustrative accessible name; use the real site control.
  const consentButton = page.getByRole('button', {
    name: 'Reject optional cookies'
  });

  // If consent is expected on this visit, wait for and use its real control.
  await consentButton.waitFor({ state: 'visible', timeout: 10_000 });
  await consentButton.click();
  await consentButton.waitFor({ state: 'detached', timeout: 10_000 });

  // Wait for the content that should appear in the screenshot.
  await page.getByRole('heading', { name: 'Recent activity' }).waitFor({
    state: 'visible'
  });

  await page.screenshot({
    path: 'account.png',
    fullPage: true,
    animations: 'disabled',
    caret: 'hide'
  });
} finally {
  await context.close();
  await browser.close();
}

Run it with credentials available in the environment when generating the state file, and with the saved state in place for capture:

TEST_EMAIL='your-test-user@example.com' TEST_PASSWORD='your-test-password' node scripts/save-auth-state.mjs
node scripts/capture-authenticated.mjs

The example waits for the button to become visible and then detached. Some sites hide a dismissed banner instead of removing it; in that case, wait for the relevant locator to become hidden, and verify the page is unobstructed. A consent bar may also appear only on the first visit, so make the script’s behavior match the state and consent setup used by your test.

3. Choose the screenshot region

Capture Playwright call Use it when Trade-off
Viewport page.screenshot({ path: 'view.png' }) The visible screen composition is the evidence you need. Content below the fold is omitted.
Full page page.screenshot({ path: 'full.png', fullPage: true }) You need the scrollable document in one image. The image may be much taller than the viewport; lazy-loaded content may need additional handling.
Element page.getByRole('region', { name: 'Recent activity' }).screenshot({ path: 'activity.png' }) Only one known component or region matters. Surrounding page context is omitted.

Playwright’s Page API documents page screenshot options, and its screenshot guide covers full-page and element captures. Use an accessible role and name or a stable site-specific locator for an element; the example region locator must match the target page.

4. Make repeat captures more reliable

  • Wait for meaningful content. Prefer a visible heading, account-specific marker, or final URL over an arbitrary sleep. This distinguishes a loaded signed-in page from a login redirect or partially rendered screen.
  • Handle predictable overlays explicitly. If the bar is expected, select the intended real control, click it, and verify the overlay no longer blocks the target. Playwright recommends explicitly handling predictable overlays in the normal flow. See the Page API and Browserless’s cookie consent example.
  • Reduce incidental visual changes. Screenshot options such as disabling animations and hiding the caret can help with repeatability. For visual regression assertions, Playwright waits until two consecutive screenshots match before comparing with a baseline; see the PageAssertions API.
  • Keep the environment consistent. Choose a fixed viewport when the composition matters, and use the same browser, state, consent choice, and readiness condition across runs.

5. Troubleshoot common failures

Symptom Likely cause Fix
The page shows a login form. The saved state is missing, expired, or not loaded for this context. Regenerate the state after verifying successful login. Confirm the context uses the right path and that the expected signed-in marker appears before capture.
The consent button times out. The banner did not appear, its accessible name differs, or it is inside a frame. Inspect the page in the relevant state, identify the actual control, and update the locator. If the banner is optional in this scenario, branch on visibility rather than waiting unconditionally.
The bar remains over the content after clicking. The click did not select the intended control, the banner hides instead of detaching, or the page needs to finish updating. Verify the resulting consent state and wait for the banner to be hidden or for an unobstructed target. Avoid removing arbitrary DOM nodes, which can skip the site’s consent behavior.
The screenshot captures a loading or empty region. Navigation completion did not mean the application content was ready, or a client-side request failed. Wait for a stable page-specific element and investigate failed requests or redirects. Increase a targeted timeout only when the site’s expected response time warrants it.
Full-page capture misses images or sections. Content is lazy-loaded or rendered only after scrolling. Scroll through the page to trigger the content, wait for the relevant images or sections, then capture. Confirm the full-page option is enabled.
Repeated images differ. Animation, caret, dynamic timestamps, rotating content, or data changes affect the pixels. Disable animations and hide the caret where appropriate, wait for stable content, and mask or control genuinely dynamic regions in your visual test setup.
The saved state works locally but not in another environment. Session state can be scoped to domain, browser context, or environment, and may expire or depend on additional setup. Create and use state in the intended environment, verify the authenticated marker there, and refresh the state when necessary.

6. Security, performance, and cost considerations

Protect both the state and the image

Playwright warns that saved authentication state may include cookies and headers capable of impersonating an account. Store it outside version control with restricted access, rotate or refresh it when required, and avoid placing it in build logs or public artifacts. Screenshots of authenticated pages can reveal account or customer information; limit access and retention according to the account owner’s policy.

Keep capture time predictable

Reuse saved state instead of logging in for every capture, wait for the specific content required, and use viewport or element capture when a full document is unnecessary. Full-page images can be very tall, and waiting for broad network idleness can be unreliable on pages with long-lived requests. Use a targeted readiness condition where possible; add a timeout based on the page’s expected behavior rather than an arbitrary long delay.

Account for the work your own browser performs

A Playwright capture consumes the time and resources of the machine or CI runner launching the browser. For a small number of pages, a local or CI browser may be straightforward. For many URLs, consider queueing work and limiting concurrent browser contexts so that the capture host is not overwhelmed. The dossier provides no benchmark or universal cost figure: actual runtime and infrastructure cost depend on the page, browser, host, and capture options.

Or skip the browser setup

ScreenshotNeo is a website screenshot API and MCP server. One GET request captures a URL as PNG, JPEG, WebP, or PDF. For an authenticated page, supply the required authentication using supported request options such as cookies, custom headers, or Authorization; a request-based capture may not work for sites whose login depends on a browser-only flow.

For supported pages, ScreenshotNeo removes cookie and consent banners, newsletter popups, and chat widgets before capture. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed; the response identifies the page verdict and billing status in headers. Its MCP server provides take_screenshot, get_page_info, and capture_pdf tools for AI agents.

Example request (replace the target with a page you are authorized to capture):

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

More request options and examples are in the ScreenshotNeo API documentation. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 screenshots. Sign up for 1,000 free screenshots a month, with no card required.

FAQ

No. Choose the site’s actual control that matches the intended preference or test scenario. Acceptance is not a universal requirement.

Can I capture only the sticky bar?

Yes. Locate the bar with a stable locator and call its locator screenshot method. This is useful for inspecting the banner itself, while a page screenshot is better for showing its effect on content.

Will saved authentication state stay valid indefinitely?

No. Sessions may expire or be invalidated. Regenerate the state through an authorized login flow and verify the signed-in marker before capture.

Can a screenshot API use every authenticated session?

No. Authentication mechanisms and page behavior vary. A request-based capture needs credentials the service can use; browser-only login flows may require a browser automation workflow such as Playwright.