How to Compare Logged-In Page Screenshots Without Including the Cookie Banner
Compare authenticated pages without banner noise: dismiss consent in Playwright, mask changing regions, or use visual-testing ignore regions.
To compare screenshots of a logged-in page without the cookie banner, first establish the authenticated state consistently, then choose whether the test should dismiss consent or exclude the banner from visual comparison. In Playwright, the clearest approach for a predictable banner is to wait for its real control and activate it before the screenshot. If the banner should remain but its changing pixels should not affect the comparison, use a visual-testing tool’s ignored region. Playwright’s screenshot mask covers the banner with a colored block; it does not remove it.
Keep a separate check for the banner if its appearance or consent behavior is part of the requirement. Otherwise, a narrowly scoped dismissal or exclusion gives you a cleaner comparison of the post-login page.
1. Make the logged-in state repeatable
Visual comparisons are only useful when the page starts from comparable conditions. Use the same test account or fixture, establish authentication through the normal test setup, and keep the page data stable enough that unrelated changes do not dominate the screenshot. Playwright recommends putting common setup such as login in a setup hook and keeping browser and operating-system versions consistent for visual tests. See Playwright best practices and visual comparisons.
Do not hard-code a generic cookie selector and assume it applies to every site. Inspect the page and identify the actual banner and its accept, dismiss, or preferences control. Consent actions differ, and the app may persist consent between runs.
2. Dismiss a predictable banner in Playwright
When the test represents the post-consent experience, dismiss the banner through the same visible control a user would use. Playwright recommends waiting for a predictable overlay and dismissing it as part of the normal flow. This exercises the page’s real consent path and leaves no artificial colored mask in the screenshot.
import { test, expect } from '@playwright/test';
test('authenticated dashboard has the expected layout after consent', async ({ page }) => {
await page.goto('https://app.example.test/login');
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();
await page.getByRole('heading', { name: 'Dashboard' }).waitFor();
// Use the actual consent control exposed by this application.
const acceptCookies = page.getByRole('button', { name: 'Accept all cookies' });
await acceptCookies.waitFor({ state: 'visible' });
await acceptCookies.click();
await expect(acceptCookies).toBeHidden();
await expect(page).toHaveScreenshot('dashboard.png', {
fullPage: true,
animations: 'disabled',
});
});
Replace the example URL, labels, and button name with the application’s actual login and consent controls. If authentication is already handled in a Playwright fixture or setup project, use that shared setup instead of repeating login in each test. Keep credentials in environment variables or your test secret store, not in source control.
Wait for an app-specific ready signal before capture, such as a heading, loaded data indicator, or stable component. Avoid treating a fixed sleep as proof that login and page rendering have completed. Playwright screenshot assertions can be used for visual snapshots; see the Page API for screenshot options.
3. Choose dismissal, masking, or an ignored region
| Method | What the comparison sees | Use it when | Trade-off |
|---|---|---|---|
| Dismiss through the page | The post-consent page without the banner | The requirement concerns the logged-in experience after consent | Requires the correct control and known consent persistence behavior |
| Playwright screenshot mask | A colored rectangle over the banner’s bounding box | The content changes and a visible placeholder is acceptable | The banner area remains visibly covered in the artifact |
| Visual tool ignored region | The service excludes the selected region from comparison | The banner should remain but should not affect a wider page check | Configuration and region behavior depend on the service |
| Capture-time CSS | A temporarily styled page, depending on the CSS rule | The capture pipeline intentionally applies a tightly scoped style | Can change layout and is not a substitute for exercising consent |
Mask with Playwright
Playwright accepts locators in the screenshot mask option and paints their bounding boxes with the configured mask color (pink by default). This is useful for suppressing variable pixels, but the colored shape remains in the image. Use a locator for the banner rather than a broad page region.
import { test, expect } from '@playwright/test';
test('compare dashboard while masking a changing banner', async ({ page }) => {
// Authentication and navigation belong in your shared fixture/setup.
await page.goto('https://app.example.test/dashboard');
const banner = page.locator('[data-testid="consent-banner"]');
await banner.waitFor({ state: 'visible' });
await expect(page).toHaveScreenshot('dashboard-with-banner-masked.png', {
fullPage: true,
mask: [banner],
maskColor: '#777777',
animations: 'disabled',
});
});
The selector shown is illustrative; use a selector that belongs to your application. Masking is appropriate when the banner’s contents vary but a visible block is acceptable. If the goal is a clean image with no banner area, dismiss the banner instead.
Ignore a region in a visual-testing service
Applitools Eyes and Percy document ignored-region controls for visual checks. Percy documents selector, XPath, and custom-coordinate approaches, and also documents temporary snapshot CSS. Choose the feature supported by the visual-testing workflow already in use, then confirm how its selector or coordinates map to the actual page. See Applitools’ Playwright integration and the Percy Playwright client documentation.
Ignored regions are useful when the banner must remain rendered but should not participate in a broader comparison. Review the resulting checkpoint to ensure the ignored area is limited to the banner; a region that is too large could hide a real layout regression. This recommendation follows from the documented effect of excluding regions.
4. Capture only the scope you intend to test
Use a full-page screenshot when the whole page layout matters. For a component-level requirement, capture or compare the relevant component or region instead. A full-page checkpoint can detect shifts beyond the initial viewport, while a smaller checkpoint reduces unrelated variation and makes failures easier to inspect. Applitools documents full-page and element-region checks, and its visual options cover match behavior and vertical shifts: Visual AI options.
Do not exclude the banner from every test if the banner itself is under evaluation. Keep a separate test for its visibility, content, and consent behavior, and use the post-consent checkpoint for the application page.
5. Stabilize the capture and baseline
- Use the same browser and operating-system versions across baseline creation and comparison.
- Use a consistent account, data fixture, and consent state.
- Wait for a meaningful page-ready condition and the banner’s intended state.
- Disable or control animations when they create timing-dependent pixels.
- Use the same viewport, device scale, and page scope for baseline and subsequent captures.
- Review changed pixels in context before accepting a new baseline.
These controls reduce unrelated differences; they do not guarantee identical rendering if the application data or external content changes.
Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server from Yorker Media. Its API can capture a URL in one request, and its clean-shot flow accepts cookie/consent banners like a visitor and removes 60+ known consent platforms, newsletter popups, and chat widgets before capture. The individual cleanup steps can be turned off. For a logged-in page, send the required authentication context using supported headers or cookies; an ordinary public URL alone cannot access a private session. Read 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://app.example.test/dashboard \
-o dashboard.webp
For a protected page that uses a cookie, add the cookie parameter according to the API documentation and keep the credential private. If the page uses a different login mechanism, configure the supported headers or authorization context as appropriate.
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://app.example.test/dashboard"},
timeout=90,
)
open("dashboard.webp", "wb").write(r.content)
const q = new URLSearchParams({
access_key: 'YOUR_API_KEY',
url: 'https://app.example.test/dashboard',
});
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('dashboard.webp', new Uint8Array(await res.arrayBuffer()));
With ScreenshotNeo, cookie banners, popups, and chat widgets are removed before the shot; bot checks, blank pages, and failed loads are never billed; and an MCP server lets AI agents use take_screenshot, get_page_info, and capture_pdf. The free plan includes 1,000 screenshots per month with no card, and paid plans start at $5 for 3,000. Sign up free for 1,000 screenshots a month, no card required.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Login page appears in the screenshot | Authentication did not complete, or the session was not restored | Wait for an authenticated-page signal; verify the setup fixture, credentials, and session state before capturing. |
| Consent button times out | The banner is absent because consent persisted, appears later, or uses different text | Inspect the current page state and use the application’s real locator. Handle the already-consented case deliberately instead of assuming the banner is always present. |
| Banner returns on every run | Consent storage is cleared between contexts or the test clicks a non-persistent control | Decide whether each test should exercise fresh consent or restore a known post-consent state. Set up storage consistently. |
| Screenshot still contains a colored block | Playwright mask is covering the banner |
Dismiss the banner for a clean image, or configure an ignored region in the visual-testing service. |
| Screenshot comparison fails intermittently | Page data, rendering timing, browser/OS, animation, or viewport varies | Stabilize fixtures and environment, wait for an app-specific ready condition, control animation, and keep capture dimensions consistent. |
| A real layout change is hidden | The ignored or masked region is broader than the banner | Narrow the selector or coordinates and retain a separate checkpoint for the banner itself. |
| Element locator does not match | The selector is stale, duplicated, or not available in the current state | Inspect the rendered DOM and use a specific role, label, or application-owned test identifier. |
Performance, reliability, and cost
For browser-based regression suites, the main operational cost is running the login flow and rendering the page for each checkpoint. Shared setup or authenticated state can avoid repeating unnecessary login steps, while deterministic data and targeted checkpoints reduce noisy reruns. Keep a full-page capture where coverage requires it; use a component checkpoint when the requirement is local.
Dismissal is generally the most faithful choice when the expected state is post-consent, because the test follows the page’s normal interaction. Masking is simpler for dynamic pixels but leaves a visible placeholder. Ignored regions depend on the visual service’s behavior and configuration. Maintain a separate consent test so a visual exclusion cannot silently hide a regression in the banner.
ScreenshotNeo charges only for clean shots: bot checks/CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, and responses report the page verdict and billing status in X-Page-Verdict and X-Billed headers. Plans are Free at 1,000 shots/month, 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, and every feature is on every plan. See the documentation for request configuration and billing details.
FAQ
Does Playwright’s mask remove the cookie banner?
No. It covers the locator’s bounding box with a colored overlay in the screenshot. Dismiss the banner or use a visual tool’s ignored region if the image should not show a colored block.
Should I accept cookies automatically in every visual test?
Only when the checkpoint is meant to represent the post-consent experience. Test the banner separately when consent behavior or appearance is part of the requirement.
Can I compare a page that requires login with a screenshot API?
Yes, if the capture request supplies the authentication context the site requires, such as supported cookies or headers. Protect those credentials and follow the API’s documented options.
Will ignoring the banner hide layout shifts?
It can hide changes inside the excluded region, and an overly broad region may hide nearby defects. Keep the exclusion narrow and cover the banner in a separate test when needed.


