Playwright Screenshot: Fixing a Banner That Covers Content on an Indian Web Page
Diagnose why a banner covers page content in a Playwright screenshot, then choose a fix that matches your test: preserve, dismiss, or hide it.
If a banner covers content in a Playwright screenshot, Playwright is capturing the page as it is rendered at that moment. It does not automatically remove banners. First identify whether the banner is part of the layout, a fixed or sticky overlay, a consent prompt, or a component inserted after navigation; then choose whether your test should preserve, dismiss, or hide it.
The title mentions an Indian web page, but the same diagnosis applies regardless of the site’s country. Without the page URL or a reproducible example, the particular banner and its cause are unknown.
1. Decide what the screenshot should show
Before changing code, write down the expected state:
- Real visitor view: keep the banner visible and test whether it obscures the right content. This is the right choice when banner layout or consent behavior is under test.
- Underlying content: dismiss the banner through its actual UI when possible, or use a test-only style override if the purpose is to inspect content behind it. Make the override explicit so the test does not conceal a consent defect.
- Whole document: use a full-page screenshot only when you need the full scrollable document. It changes the capture extent; it does not dismiss an overlay.
A locator screenshot scrolls its target into view, but scrolling does not remove an element covering it. Playwright’s locator screenshot documentation says, “If the element is covered by other elements, it will not be actually visible on the screenshot.” See the official locator screenshot API.
2. Inspect the banner and target at capture time
Use the exact viewport, browser, route, and timing used by the failing capture. Inspect the banner selector and covered target for visibility, bounding boxes, computed positioning, and stacking order. Also check whether the banner appears after navigation, a delay, scrolling, or a consent-state change.
import { test, expect } from '@playwright/test';
test('inspect banner overlap', async ({ page }) => {
await page.setViewportSize({ width: 1365, height: 768 });
await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });
const banner = page.locator('[data-testid="site-banner"]');
const target = page.locator('main h1');
await expect(target).toBeVisible();
console.log('banner visible:', await banner.isVisible().catch(() => false));
console.log('banner box:', await banner.boundingBox());
console.log('target box:', await target.boundingBox());
const details = await page.evaluate(() => {
const banner = document.querySelector('[data-testid="site-banner"]');
const target = document.querySelector('main h1');
if (!banner || !target) return { found: false };
const style = getComputedStyle(banner);
return {
found: true,
position: style.position,
zIndex: style.zIndex,
bannerRect: banner.getBoundingClientRect().toJSON(),
targetRect: target.getBoundingClientRect().toJSON(),
bannerPointerEvents: style.pointerEvents,
};
});
console.log(details);
await page.screenshot({ path: 'page.png' });
});
Replace the example selectors and URL with the page under test. If the banner is inserted asynchronously, wait for the relevant state with a locator assertion rather than assuming that navigation completion means all application UI has settled. Playwright’s actionability guidance and locator assertions help make these waits state-based.
3. Choose a fix that matches the cause
Dismiss it through the real interface
If the test should show the page after a visitor closes the banner, click its real close or accept control and assert that the banner is gone before capturing. Prefer accessible roles and names when the UI exposes them.
await page.goto('https://example.com');
const banner = page.getByRole('dialog', { name: 'Cookie preferences' });
await expect(banner).toBeVisible();
await banner.getByRole('button', { name: 'Accept all' }).click();
await expect(banner).toBeHidden();
await page.screenshot({ path: 'after-consent.png' });
Use the actual accessible name and button text from the site. Consent choices may be persisted in cookies or local storage, so create a fresh browser context when testing the first-visit state and a separate context with the expected saved state when testing returning visitors.
Hide it with a test-only override
If the test is specifically about the underlying page and does not test the banner, a narrowly scoped CSS override is a practical isolation tool. Apply it only in the test context and assert that the intended target remains visible.
await page.goto('https://example.com');
await page.addStyleTag({
content: `
[data-testid="site-banner"],
.newsletter-modal,
.chat-widget { display: none !important; }
`,
});
await expect(page.locator('main h1')).toBeVisible();
await page.screenshot({ path: 'content-only.png' });
Do not use broad selectors such as header or [role="dialog"] unless you have confirmed they target only the unwanted component. A broad rule can hide navigation, an important alert, or the very consent UI the test is meant to cover.
Fix the site layout when the overlap is a product defect
If the banner is meant to push content down, it should participate in normal layout flow or the page should reserve the required space. If it is meant to overlay the page, verify that the covered state is intentional and usable. Inspect position: fixed or sticky, element dimensions, stacking contexts, z-index, and the viewport dimensions. A high z-index alone may not behave as expected when ancestors create separate stacking contexts.
For a sticky banner that appears only after scrolling, reproduce the same scroll position before taking the screenshot. For a banner that appears after a consent-state change, test that state explicitly rather than relying on a previous run’s browser storage.
4. Capture the intended area
A regular page screenshot captures the current viewport. A full-page screenshot captures the scrollable document as if it were displayed on one very tall screen. Neither mode changes the banner’s behavior. Choose based on the artifact you need, especially if fixed elements repeat or move during a full-page capture.
// Current viewport
await page.screenshot({ path: 'viewport.png' });
// Entire scrollable document
await page.screenshot({ path: 'full-page.png', fullPage: true });
// A particular element (scrolls it into view first)
await page.locator('main article').screenshot({ path: 'article.png' });
See Playwright’s documentation for page screenshots and locator screenshots for the capture options and behavior.
5. Make screenshots stable for visual comparisons
Wait for the page state you expect, not an arbitrary long sleep. For example, wait for the banner to become hidden after clicking its control, or for the target content to appear. If animation is causing the banner or page content to move between captures, disable animations for that capture:
await page.screenshot({
path: 'stable.png',
animations: 'disabled',
});
Playwright’s screenshot animation option affects CSS animations, transitions, and Web Animations. It can stabilize motion; it does not fix a persistent layout or stacking problem. For visual snapshot assertions, Playwright Test waits for two consecutive screenshots to match before comparing the result, which helps with rendering stability but cannot determine whether the design is correct. See the page screenshot options and visual comparisons guide.
Keep the browser engine, operating system, viewport, device scale factor, and fonts consistent when comparing snapshots. Rendering can differ across browsers and platforms. See Playwright’s snapshot guidance.
6. Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
The banner is visible even with fullPage: true. |
Full-page capture changes the page extent, not its state. | Dismiss it, use a test-only override, or preserve it according to the test’s purpose. |
| A locator screenshot still shows the target covered. | The locator is scrolled into view, but another element remains above it. | Inspect bounding boxes and computed styles; address the overlay or test the covered state. |
| The banner sometimes appears and sometimes does not. | It may depend on delayed insertion, persisted consent, scroll position, or other page state. | Use a fresh context for first-visit tests, set the intended storage state, reproduce the scroll, and wait for the expected locator state. |
| The override hides other content. | The selector is too broad or matches multiple components. | Inspect matches and target a stable, specific selector for the banner only. |
| The screenshot differs across machines. | Browser, platform, viewport, device scale, font, or rendering differences. | Pin the environment and dimensions used for comparison; inspect the rendered image before changing expected snapshots. |
| The page is still visually unstable with animations disabled. | The movement may come from delayed content or layout shifts rather than animation. | Wait for the relevant content and banner state, then inspect bounding boxes at capture time. |
7. Performance, reliability, and cost
For local Playwright work, the main reliability tradeoff is whether your test represents a real visitor state or isolates the page content. Keep banner behavior in dedicated tests if other screenshot tests hide it; that way an override does not silently remove coverage. Avoid fixed sleeps where a specific locator state can express the condition directly. Use a consistent browser and viewport for visual comparisons.
For large visual suites, screenshots and snapshot comparisons add rendering and storage work; capture only the page area needed by each assertion and use full-page mode when the entire document is actually part of the requirement. Playwright itself does not charge per screenshot; compute and CI costs depend on where the browser runs and how many captures your pipeline performs. No benchmark or price estimate is available from the cited documentation.
8. Or skip the browser setup
If you need a clean website image without maintaining a browser capture script, ScreenshotNeo is a screenshot API and MCP server for developers. One GET request returns an image or PDF. The API can accept consent banners as a visitor and remove more than 60 known consent platforms, newsletter popups, and chat widgets before capture; those cleanup steps can be turned off. Bot checks and CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and the response identifies the page verdict and billing status in headers. AI agents can use its MCP server tools to take screenshots, get page information, and capture PDFs.
For this API call, see the ScreenshotNeo API documentation. Replace YOUR_API_KEY with your key.
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}`);
The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. Sign up for free and get 1,000 screenshots a month with no card.
9. FAQ
Does Playwright automatically close cookie banners before screenshots?
No. Your script must interact with the page or apply a deliberate test-only override if that matches the test purpose.
Will full-page mode reveal content hidden by a banner?
No. It captures a taller page, but an overlay can still cover content.
Should I hide the banner in every visual test?
No. Preserve it when its appearance, layout, or consent behavior is part of what you are checking.
Is this behavior specific to Indian sites?
The available Playwright documentation establishes general screenshot behavior, not a country-specific difference. The site’s own markup and state determine the particular fix.


