ScreenshotNeo

BlogHow-to

Set a Cookie Banner to Dismissed Before Taking Screenshots with Playwright in Python

Dismiss a site's consent banner before a Playwright screenshot using a verified locator, with patterns for conditional banners, frames, and troubleshooting.

By the ScreenshotNeo team4 October 20268 min read

To dismiss a cookie banner before a screenshot in Python Playwright, inspect the target page, locate the consent control the way a user would, click the intended choice, and capture only after it is gone. There is no universal cookie-banner selector: button names, markup, timing, and consent behavior vary by site. The examples below use “Accept all” as a placeholder; replace it with a control verified on your target page. If your automation must reject optional cookies or open settings, click that option instead.

Playwright locators are designed for auto-waiting and retrying. A role-and-name locator is a good default when the page exposes an accessible button. See the Playwright locator guide and screenshot guide.

Before writing a selector, visit the page and determine whether the banner is an HTML dialog or region, whether it is inside an iframe, and what action you intend to take. Prefer a visible, user-facing button name or a documented stable test identifier. Avoid guessing a generic CSS selector: it may match a hidden element or an unrelated button.

When multiple controls share similar names, scope the locator to the consent dialog or other distinctive container. Confirm that the locator identifies exactly one intended control. If the site’s consent choice must persist between pages or runs, verify that behavior for the target site and use an appropriate browser context strategy; persistence is site-specific.

2. Runnable Python example: click, then capture

Install Playwright and its Chromium browser if they are not already available in your environment:

python -m pip install playwright
python -m playwright install chromium

Save this as capture.py. Change the URL and button name to match the site. This synchronous example waits for the button through Playwright’s locator behavior, clicks it, and then takes a full-page screenshot.

from playwright.sync_api import sync_playwright

URL = "https://example.com"
CONSENT_BUTTON_NAME = "Accept all"  # Replace with the verified accessible name.

with sync_playwright() as p:
    browser = p.chromium.launch()
    page = browser.new_page()
    page.goto(URL, wait_until="domcontentloaded")

    # Use the choice that matches your intended consent state.
    page.get_by_role("button", name=CONSENT_BUTTON_NAME).click()

    page.screenshot(path="page.png", full_page=True)
    browser.close()

Run it with python capture.py. Use full_page=True to capture the scrollable page; omit it for a viewport-only image. If the site renders the banner after initial navigation, target its dialog or button and let the locator wait for it rather than immediately taking the screenshot.

3. Handle banners that may not appear

When consent UI is conditional, do not make a missing banner a fatal error. Use a bounded wait and check whether the intended button is visible before clicking. This avoids waiting for the full default timeout on every page without a banner.

from playwright.sync_api import sync_playwright, TimeoutError as PlaywrightTimeoutError

URL = "https://example.com"

with sync_playwright() as p:
    browser = p.chromium.launch()
    page = browser.new_page()
    page.goto(URL, wait_until="domcontentloaded")

    consent = page.get_by_role("button", name="Accept all")
    try:
        consent.wait_for(state="visible", timeout=2500)
    except PlaywrightTimeoutError:
        pass  # No visible matching control during this bounded wait.
    else:
        consent.click()

    page.screenshot(path="page.png", full_page=True)
    browser.close()

Use a short timeout only if a missing banner is an acceptable outcome. If the banner is required for the capture, keep a suitable wait and report a clear failure instead of silently capturing with the overlay present. A button may be visible before the page finishes changing after the click; if necessary, wait for the dialog to become hidden before capturing.

4. Scope the locator and cover other UI types

If the page exposes an accessible dialog, scope the button locator to it to avoid matching a similarly named control elsewhere:

dialog = page.get_by_role("dialog", name="Privacy preferences")
dialog.get_by_role("button", name="Reject optional cookies").click()
page.screenshot(path="page.png", full_page=True)

Replace the dialog name and button name with the actual accessible names. If the consent panel is a region rather than a dialog, inspect its accessible semantics and use the appropriate locator. A locator that matches more than one element is ambiguous; narrow its scope rather than clicking the first match arbitrarily.

For a banner inside an iframe, use a frame-scoped locator. The iframe selector below is a placeholder that must be replaced after inspecting the page:

frame = page.frame_locator("iframe[title='Consent']")
frame.get_by_role("button", name="Accept all").click()
page.screenshot(path="page.png", full_page=True)

Use a stable iframe attribute when available. If the frame is cross-origin, Playwright can still target its rendered controls through the frame locator; the page’s own JavaScript access rules are a separate concern.

JavaScript alert, confirm, or prompt

A browser JavaScript dialog is not an HTML cookie banner. Handle it through Playwright’s dialog event rather than looking for a button in the page. Check the official Playwright dialog guide for the current API and choose accept or dismiss according to the site behavior. Do not add a blanket dialog handler unless you know which dialogs the page can open: it could affect unrelated prompts.

5. Optional pattern: handle a recognizable dialog during navigation

Playwright’s v1.42 release notes document page.add_locator_handler() with a cookie-dialog heading and an “Accept all” button. It can be useful when a recognizable overlay may interrupt an action. This API is version-dependent; check your installed Playwright version and the current Python API before adopting it. For a single banner shown at a known point in the flow, an explicit locator click is usually easier to reason about.

# Illustrative pattern; verify availability in your installed Playwright version.
page.add_locator_handler(
    page.get_by_role("heading", name="We value your privacy"),
    lambda: page.get_by_role("button", name="Accept all").click(),
)

Take the screenshot after the consent action has completed. The screenshot API supports full-page and element captures, and can return bytes for in-memory processing. For example, to capture one element:

page.locator("main").screenshot(path="main.png")

Screenshot options such as disabling animations, masking selected elements, or applying a stylesheet can help control the image. They do not dismiss the consent interface or establish that a choice was recorded. Hiding a banner with injected CSS changes only its appearance; it is not equivalent to interacting with the site’s consent controls.

7. Troubleshooting

Symptom Likely cause Fix
Timeout waiting for the button The banner did not appear, appears later, or has a different accessible name. Inspect the rendered page and accessible name. If the banner is optional, use a bounded visibility check; if required, wait for the actual control and fail clearly.
Strict mode says the locator matched multiple elements More than one visible or hidden control has the same name. Scope the locator to the consent dialog or a distinctive container, then verify it identifies the intended control.
Click succeeds but the screenshot still has an overlay The click targeted the wrong control, the overlay has not closed, or another banner remains. Use the correct consent action, wait for the relevant dialog to become hidden, and inspect for additional overlays before capture.
Button locator finds nothing in the main page The banner may be inside an iframe or may not expose a button role/name. Inspect the frame tree and accessible markup. Use a frame locator for an iframe or a stable, site-specific locator when justified.
Screenshot is clipped The default capture covers the viewport only. Pass full_page=True for the whole scrollable page, or capture the desired element with its locator.
Consent disappears in one run but returns in another The target site may store consent in browser state, or may ask again under different conditions. Check the target site’s behavior and browser-context storage strategy. Do not assume consent persists across fresh contexts.
A prompt remains despite clicking the page It is a browser JavaScript dialog, not an HTML overlay. Use Playwright’s dialog event handling and select the intended accept or dismiss action.

8. Reliability, speed, and cost

Reliability depends mainly on using the correct consent choice and a locator that matches the target site’s rendered interface. Accessible role-and-name locators are readable and benefit from Playwright’s waiting behavior, but they cannot make a site-specific label universal. For a fleet of pages, keep selectors and expected consent outcomes configurable per site, and log whether a banner was found, which action was taken, and whether the overlay disappeared.

Keep navigation and visibility waits bounded so a missing banner does not stall a batch indefinitely. Full-page captures can require more rendering and produce larger files than viewport captures; capture only the needed area when that meets the goal. No general timing or success-rate guarantee applies across different websites.

Playwright itself is open source, but browser execution has infrastructure and maintenance costs when run at scale: browser installation, CPU and memory, concurrency limits, retries, and keeping browser and package versions aligned. The free-running example above makes no claim about the cost of your hosting environment.

9. Or skip the browser setup

ScreenshotNeo is a website screenshot API and MCP server from Yorker Media. One GET request returns an image or PDF, and its documentation covers the API 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}`);
  • Cookie banners, popups, and chat widgets are removed before the shot; each cleanup step can be turned off.
  • Bot checks, blank pages, timeouts, failed loads, and cache hits are never billed. Response headers identify the page verdict and billing status.
  • An MCP server lets AI agents use take_screenshot, get_page_info, and capture_pdf.
  • 1,000 screenshots a month are free with no card. Paid plans start at $5 for 3,000 screenshots; every feature is on every plan.

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

10. FAQ

Can I reuse one locator across every website?

No. Consent controls and accessible names vary. Reuse a helper only when each site supplies a verified locator or configuration.

Should I accept all cookies to remove the banner?

Choose the action that matches your intended consent state. “Accept all” is only an example, not a default recommendation.

Does hiding the banner with CSS count as dismissing it?

No. CSS can alter the screenshot’s appearance, but it does not interact with the consent UI or prove the site recorded a choice.

Can I capture only the page content beneath the banner?

Dismiss the banner first, then use a locator screenshot for the content element or take a full-page capture as needed.