ScreenshotNeo

BlogHow-to

Playwright Screenshot of an Indian Website Shows the Cookie Preference Center: Fix

Diagnose why a cookie preference center appears in a Playwright screenshot, interact with its real controls, verify the saved state, and capture the right view.

By the ScreenshotNeo team4 October 20269 min read

If a cookie preference center appears in your Playwright screenshot, first decide whether the test should show it or show the page after a choice. Inspect the rendered page, locate the center and its controls by accessible role and name, account for an iframe if present, then interact with the real control and assert the result before capturing. A screenshot shows pixels; it does not prove that a consent choice was saved.

The title does not identify a particular website, DOM, test, browser, or Playwright version, so there is no verified site-specific fix. Use this diagnostic workflow with the actual accessible names and behavior of the site under test.

1. Identify the intended screenshot state

Choose the state the test is meant to document:

  • Preference-center state: the center should be visible. Capture the page for overlay placement and surrounding context, and capture the center itself to inspect its content.
  • Post-choice state: a user choice should have been made. Activate the corresponding site control, verify the center’s resulting state, then capture the page.
  • Initial-load state: the center should appear on a fresh visit. Use a fresh browser context or clear the relevant site state so a previous test’s saved choice does not hide it.

Check the viewport size and whether the screenshot is viewport-only or full-page. A full-page capture includes the scrollable page; it does not change the site’s consent state. A locator screenshot isolates one element. Playwright documents these options in its screenshots guide.

2. Inspect and locate the real controls

Prefer user-facing locators based on the page’s accessible roles and names. Playwright recommends user-facing attributes and explicit contracts such as getByRole(). Do not assume a particular dialog name, button label, or control type: inspect the rendered accessibility structure and use what the site actually exposes.

import { test, expect } from '@playwright/test';

test('choose cookie preferences before capturing the page', async ({ page }) => {
  await page.goto('https://example.com');

  // Replace these names with the actual accessible name and role.
  const preferences = page.getByRole('dialog', {
    name: /cookie preferences/i,
  });
  await expect(preferences).toBeVisible();

  const saveButton = preferences.getByRole('button', {
    name: /save preferences/i,
  });
  await expect(saveButton).toBeVisible();
  await saveButton.click();

  await expect(preferences).toBeHidden();
  await page.screenshot({ path: 'after-preferences.png' });
});

This is a template, not a tested fix for the unidentified site. The center may use a different role or label, or saving may leave it open. If the intended outcome is simply dismissal, use the actual dismiss or accept control and assert the site’s expected result instead of assuming that “Save preferences” exists.

If the center is inside an iframe

Page-level locators do not search inside a frame automatically. Identify the frame from the rendered page, then scope locators through frameLocator() using the frame’s actual selector:

const frame = page.frameLocator('iframe[title="Privacy preferences"]');
const save = frame.getByRole('button', { name: /save preferences/i });
await expect(save).toBeVisible();
await save.click();

Replace the iframe selector with one that matches the site. If the frame has no useful title, inspect its attributes and use a stable selector available in that page. Avoid choosing a frame by position if multiple frames could make the test ambiguous.

For a native checkbox or switch

Use the actual exposed control and assert its state. Do not click a nearby label or a guessed element if the accessible control can be targeted:

const analytics = preferences.getByRole('checkbox', {
  name: /analytics cookies/i,
});
await analytics.check();
await expect(analytics).toBeChecked();

If the site exposes a switch instead, use its actual role and verify its checked state. Some preference centers disable necessary-cookie controls or enforce category dependencies; assert only choices the site permits.

3. Verify behavior separately from the screenshot

A clean screenshot only establishes what was rendered at capture time. It does not show that a preference was persisted or will be honored after navigation. Assert the site’s real UI contract after the action. Where persistence is part of the behavior being tested, reload or revisit the page and check the resulting preference-center state as well.

await saveButton.click();
await expect(preferences).toBeHidden();

// Include this only when persistence across reload is part of the test.
await page.reload();
await expect(preferences).toBeHidden();

await page.screenshot({ path: 'saved-preferences.png' });

The correct persistence assertion depends on the site. It may expose the saved state in its controls or show that the center stays dismissed; do not infer a particular cookie, local-storage key, or backend implementation from the screenshot. If testing storage directly is necessary, first establish the site’s documented storage contract.

4. Choose the capture and visual assertion

Use a page screenshot when the issue concerns overlay placement, viewport composition, or full-page context. Use a locator screenshot when you need to inspect the preference center by itself:

await page.screenshot({ path: 'page.png' });
await page.screenshot({ path: 'full-page.png', fullPage: true });
await preferences.screenshot({ path: 'preference-center.png' });

For a visual regression test, Playwright Test’s toHaveScreenshot() waits for two consecutive screenshots to stabilize before comparing against the expected image. Options such as animation handling, masks, clipping, and screenshot scale affect the comparison. Keep a separate semantic assertion for the center’s state so a matching baseline cannot conceal a behavioral regression.

await expect(page).toHaveScreenshot('page-after-preferences.png', {
  fullPage: true,
  animations: 'disabled',
});

Use a mask only when a genuinely dynamic region makes pixel comparison unreliable, and keep the preference controls under test outside that mask. See the official PageAssertions documentation for the visual assertion behavior and options.

5. Make the test repeatable

  1. Set a deliberate viewport and use the same browser project for the test and baseline.
  2. Navigate to a known starting state. Use an isolated browser context for a first-visit test, or establish the intended saved state through the UI for a returning-visitor test.
  3. Wait for the center to be visible before interacting. Use locator assertions instead of a fixed sleep when the expected element provides a clear condition.
  4. Perform the choice through the real control and assert the result.
  5. Capture the page or element that answers the test’s question. Use full-page capture only when the scrolled content is relevant.
  6. For visual comparisons, keep browser, viewport, fonts, and relevant page state consistent with the baseline.

A fixed delay can be useful when the site has a known delayed display, but it is less reliable than waiting for the center or a specific state. If a delay is required, keep it explicit and bounded rather than using a long sleep to mask a missing condition.

6. Common errors and fixes

Symptom Likely cause Fix
Locator matches nothing The assumed role or accessible name differs from the rendered control, or the center is in a frame. Inspect the accessibility structure, use the actual role and name, and scope through the matching frame locator when needed.
Strict-mode error says multiple elements matched The page has repeated buttons or preference controls with the same name. Scope the locator to the preference dialog or a specific category, then locate the control within that scope.
Click times out The target is hidden, covered, disabled, not yet rendered, or outside the selected frame. Assert visibility and enabled state, verify the frame, and check whether an overlay intercepts the action. Do not force the click until the intended interaction is understood.
Center reappears after reload The choice may not have been saved, the save action may require another step, or the test may use a fresh context. Assert the post-click UI, confirm the site’s persistence behavior, and reload in the same context when testing persistence.
Center is missing on a first-visit test A prior test reused a context with a saved choice, or the site shows the center only under particular conditions. Start with an isolated context and verify the site’s actual display conditions.
Screenshot is flaky Fonts, animations, delayed content, viewport, or dynamic regions differ between runs. Stabilize the test state, wait for a meaningful condition, set the viewport, and use documented screenshot options such as disabling animations or masking unrelated dynamic regions.
Full-page screenshot still shows the center Full-page capture changes the captured area, not the rendered state or consent behavior. Interact with the center and verify the intended state before capture, or capture the visible center intentionally.

7. India context and what a screenshot can establish

India-specific context should be dated and limited to the cited sample. The Advertising Standards Council of India’s January 2025 Navigating Cookies report describes a dipstick of 50 popular Indian websites based on a December 2024 ranking. It reports that only 3 of those 50 sites (6%) implemented consent banners and discusses gaps in opt-out and granular choices. This is a finding about that sample and observation period, not a current census of all Indian websites.

A screenshot can help document what a site displayed at a particular point in a test. It cannot, by itself, establish how preferences are stored, whether a site honors them elsewhere, or whether the site meets a legal obligation. The report is not a substitute for current primary legal sources; do not infer a site’s compliance from its screenshot alone.

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. Its consent cleanup accepts the banner as a visitor and removes 60+ known consent platforms, newsletter popups, and chat widgets before capture; each cleanup step can be turned off. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, and the response reports the page verdict and billing status in headers.

For a simple image capture, use the API call below. See the ScreenshotNeo API documentation for options such as full-page capture, element selection, viewport and device presets, wait conditions, and output format.

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

r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={"access_key": "YOUR_API_KEY", "url": "https://example.com"},
    timeout=90,
)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({
  access_key: 'YOUR_API_KEY',
  url: 'https://example.com',
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await import('node:fs/promises').then(({ writeFile }) =>
  writeFile('shot.webp', Buffer.from(await res.arrayBuffer()))
);

Cookie banners, popups, and chat widgets are removed before the shot. Bot checks, blank pages, and failed loads are never billed. An MCP server lets AI agents use screenshot tools. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. The product also offers bulk capture, async jobs, signed links, caching, and an OpenAPI spec.

Sign up for 1,000 free screenshots a month, with no card required.

FAQ

Should I accept cookies automatically in every test?

No. Make the choice match the test’s purpose. Test the center when its display or controls are under test; make a choice when the test needs to cover the post-choice experience.

Can I remove the center with CSS before taking the screenshot?

That can hide the visual symptom, but it does not exercise the site control or show that preferences were saved. Capture the center when documenting it, or interact through its real control when testing the resulting page.

Does a full-page screenshot dismiss an overlay?

No. It changes the captured page area. Dismissal or saving requires the site’s actual interaction and state transition.

Is the ASCI statistic a current rate for Indian websites?

No. It describes 50 popular sites in a dipstick based on a December 2024 ranking, as reported in January 2025.

What information would identify the exact fix?

The failing screenshot, relevant test code, rendered accessibility structure, whether the center is framed, and the browser and Playwright version. Those details determine the actual locator and expected state.