Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

If a Playwright click succeeds but a cookie banner remains open, first identify what kind of interface you are interacting with: an HTML banner, a JavaScript dialog, an iframe, or a component in an open Shadow DOM. Then scope a locator to the visible banner, click its actual consent button, and assert that the banner is hidden. A click completing is not proof that consent was saved.

Start by identifying the kind of cookie prompt

The right fix depends on where the prompt lives. An HTML banner is a DOM element; a browser alert is not. Consent UIs may also be rendered in a separate frame or inside a web component.

  • HTML banner: use Playwright locators such as getByRole() or getByText().
  • JavaScript alert, confirm, or prompt: handle the dialog event.
  • Iframe: enter the frame with frameLocator(), then locate the button.
  • Open Shadow DOM: normal Playwright locators can find elements in it.

These distinctions matter because a page-level button locator cannot find a control in a different browsing context, and a JavaScript dialog cannot be clicked as if it were an HTML button.

Use a scoped, user-facing locator

Prefer a locator based on the interface contract a user sees: a dialog role, an accessible button name, visible text, or a stable test ID. Playwright describes locators as central to auto-waiting and retryability and recommends user-facing attributes or explicit contracts. See the Playwright locator guide.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

For a typical TypeScript test, scope the consent button to the banner and verify the outcome:

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

test('accepts cookies', async ({ page }) => {
  await page.goto('https://example.com');

  const banner = page
    .getByRole('dialog')
    .filter({ hasText: /cookies|privacy|consent/i });
  const accept = banner.getByRole('button', {
    name: /accept all|allow all|agree/i,
  });

  await accept.waitFor({ state: 'visible' });
  await accept.click();
  await expect(banner).toBeHidden();
});

Replace the example URL and accessible names with the ones exposed by the site under test. If the site uses a different role or does not expose the prompt as a dialog, inspect its accessible tree and use the appropriate visible text or stable test ID instead. A hidden-state assertion checks whether the UI actually went away; when the site removes the element from the DOM, await expect(banner).toHaveCount(0) may be a more precise assertion.

Why scope the button to the banner?

A page can contain unrelated buttons named “Accept,” or separate desktop and mobile consent controls, with one hidden. A broad selector such as page.locator('button').first() may match the wrong control and silently couple the test to DOM order. Scoping to the visible dialog, checking the accessible name, and confirming the match count make the intended target clear.

For example, before clicking, you can make ambiguity explicit:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
await expect(accept).toHaveCount(1);
await accept.click();
await expect(banner).toBeHidden();

Playwright locators re-resolve the current DOM element when an action runs, which helps with re-rendering interfaces. The regular click() also checks whether the control is actionable. Avoid retaining a brittle element handle or immediately switching to a forced click; a re-render or blocked target is evidence to diagnose.

Wait for the control instead of sleeping

Consent banners often appear after the initial page render. Locator actions auto-wait for actionability, and assertions retry within their timeout. If the banner’s appearance itself is asynchronous, wait for a meaningful condition rather than using an arbitrary delay:

await banner.waitFor({ state: 'visible' });
await accept.click();
await expect(banner).toBeHidden();

A timeout should lead to inspection, not a longer sleep by default. Determine whether the banner appeared, whether the locator matched the right element, and whether a different browsing context owns it. Playwright’s actionability guide explains the checks performed for actions such as click, including visibility, stability, and whether the target can receive events.

Handle iframes and Shadow DOM correctly

Consent UI inside an iframe

If the consent manager is hosted in an iframe, use a frame locator with a stable selector from the actual page. For example:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
const consentFrame = page.frameLocator('iframe[title="consent"]');
const accept = consentFrame.getByRole('button', {
  name: /accept all|allow all|agree/i,
});

await accept.waitFor({ state: 'visible' });
await accept.click();

The title selector is only an example; consent providers and sites use different iframe attributes. Inspect the page and select the relevant frame. Playwright frame locators can search a specified frame, and are strict when a selector matches multiple frames; resolve ambiguity rather than picking an arbitrary one. See the frame locator documentation.

Consent UI in an open Shadow DOM

For an open Shadow DOM, normal Playwright locators pierce the shadow root, so the same role-, text-, or test-ID-based strategy generally applies. XPath does not pierce shadow roots, and closed-mode shadow roots are unsupported. Prefer selectors exposed by the component rather than reaching for brittle XPath. Details are in the Shadow DOM locator documentation.

Handle JavaScript dialogs with an event listener

A JavaScript alert, confirm, or prompt is a browser dialog rather than an HTML banner. Register a handler before the action that triggers it; otherwise the page can pause while waiting for the dialog to be accepted or dismissed.

page.on('dialog', async dialog => {
  if (/cookie|consent/i.test(dialog.message())) {
    await dialog.accept();
  } else {
    await dialog.dismiss();
  }
});

await page.getByRole('button', { name: 'Continue' }).click();

Use a condition appropriate to the application and test. Do not accept every dialog indiscriminately if unrelated dialogs should fail the test. Playwright documents the dialog event and handling behavior.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Check whether the click saved consent

Some interfaces have separate actions for closing settings and committing consent. A button labelled “Close” may only collapse a panel, while “Save choices” stores the selection. Even a successful click can be followed by an asynchronous UI update or a second confirmation step. Assert both the visible result and, when the test requires persistence, the resulting consent state.

To make a consent decision repeatable across tests, capture browser storage after a real interaction and reuse it. Playwright’s storage-state mechanism preserves cookies and local storage for later contexts:

// After completing consent through the site's real UI:
await context.storageState({ path: 'playwright/.auth/consent.json' });

// In a later test, create a context with the saved state:
const contextWithConsent = await browser.newContext({
  storageState: 'playwright/.auth/consent.json',
});

The path is an example; keep generated state files out of public repositories if they contain sensitive session data. Playwright’s authentication guide describes capturing and reusing storage state. Browser cookies include fields such as name, value, domain, and path; domain scope matters, and a leading dot applies to subdomains. Use the site’s own consent flow to discover state rather than guessing cookie names or values. Clear the saved state when the purpose is to test a first visit.

Troubleshoot the common reasons the banner stays open

Symptom Likely cause What to check or change
Click times out before it runs The button is late, hidden, covered, or not uniquely identified. Wait for the banner or button to be visible; inspect the accessible name, match count, and overlay layers.
Click completes, but the banner remains The wrong control was clicked, the action only closed a settings panel, or consent needs another save step. Confirm the matched button and follow the site’s actual consent flow; assert the banner becomes hidden after the final action.
Locator finds no button The control is in another frame, uses different accessible text, or the banner has not rendered. Inspect the DOM and accessible tree; use the correct frame locator and site-specific role or text.
More than one button matches Desktop/mobile variants or duplicate controls exist. Scope to the visible dialog and assert one match; avoid relying on first() unless DOM order is an intentional contract.
Button is covered or does not receive the click An overlay intercepts pointer events or the target is not actionable. Use a trace or screenshot to identify the overlay and correct timing or targeting. Do not treat force-click as the default fix.
Test passes once, then fails after a page update A saved element handle went stale or the consent manager re-rendered. Use locators, which re-resolve the current element, and wait for the post-action state.
Banner returns on each test Each test starts with fresh storage or consent was not persisted. Inspect cookies and local storage after accepting; save and reuse storage state when appropriate, or intentionally clear it for first-visit tests.

Use Playwright’s trace, screenshots, and DOM inspection to determine which case applies. A forced click can help establish whether hit testing is the blocker, but it bypasses actionability checks and may conceal a real user-visible defect. Fix the underlying locator, frame, timing, or overlay whenever possible. The Trace Viewer guide explains how to inspect a recorded test.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Decide whether to click the banner or control the network

Interact with the real consent UI when the test is specifically about the consent experience: for example, whether the expected choice is offered, saved, and reflected in the page. If the test is about your application’s API response or page behavior, and the consent overlay belongs to an external service outside your control, a network-level test seam may be more reliable. Playwright’s best-practices guidance recommends using the Network API for linked content and other dependencies outside the application’s control, which can include cookie banners or overlay pages.

This is a test-ownership decision, not a reason to hide a defect in a consent flow your product owns. See Playwright’s testing best practices and its Network API guide.

Or skip the browser setup

If your goal is to capture a page rather than test how its consent UI behaves, ScreenshotNeo can return a screenshot or PDF with one GET request. Cookie banners, newsletter popups, and chat widgets are removed before the shot; each step can be disabled. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing status. Its MCP server lets AI agents use tools including take_screenshot, get_page_info, and capture_pdf.

Example cURL request (replace the target URL and API key):

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
curl -G "https://api.screenshotneo.com/v1/shot" 
  -d access_key=YOUR_API_KEY 
  --data-urlencode url=https://example.com 
  -o shot.webp

See the ScreenshotNeo API documentation for setup and options. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 shots. Sign up free for 1,000 screenshots a month with no card.

Keep the Playwright version and consent state explicit

Playwright locator behavior and API signatures are version-sensitive. Pin the Playwright version in the project and revisit the official API documentation when upgrading. Consent cookie names, domains, local-storage keys, and frame selectors are specific to the site and environment; discover them through the actual application rather than copying values from another site’s test.

Frequently Asked Questions

Should I use `force: true` to make Playwright close the banner?

Only as a diagnostic to determine whether hit testing is blocking the click. It bypasses actionability checks and can mask an overlay or targeting problem.

Why does the banner appear again after accepting it?

The test may be using fresh browser storage, or the site’s consent choice may not have persisted. Inspect the site’s cookies and local storage after the real consent flow.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.