ScreenshotNeo

BlogHow-to

How to Bypass a Cookie Banner for Website Screenshots Without Accepting Tracking

Hide a cookie banner in a screenshot without clicking Accept. Use Playwright to apply a site-specific CSS rule, and learn what that does—and does not—change.

By the ScreenshotNeo team4 October 20268 min read

To remove a cookie banner from a website screenshot without accepting tracking, hide the verified banner element with a temporary CSS rule when capturing the screenshot. Do not click Accept or preload a consent cookie. This changes the screenshot’s appearance; it does not reject consent, prevent tracking requests, or prove that tracking did not happen.

The examples below use Playwright with JavaScript. They create a fresh, non-persistent browser context, load the page without changing consent state, and apply a narrow style only to the screenshot. Replace the example URL and selector with a page you are authorized to view and a selector you have verified on that page.

1. Use Playwright to hide the banner for one screenshot

Install Playwright and its Chromium browser if you have not already:

npm install playwright
npx playwright install chromium

Save this as screenshot.mjs. Set TARGET_URL to the page and BANNER_SELECTOR to the banner’s actual container selector. The placeholder deliberately will not match a real element until you replace it.

import { chromium } from 'playwright';

const targetUrl = process.env.TARGET_URL ?? 'https://example.com';
const bannerSelector = process.env.BANNER_SELECTOR ?? '.REPLACE_WITH_VERIFIED_BANNER_SELECTOR';

const browser = await chromium.launch({ headless: true });
try {
  // A fresh, non-persistent context avoids reusing this script's prior browser state.
  const context = await browser.newContext({ viewport: { width: 1440, height: 900 } });
  const page = await context.newPage();
  const response = await page.goto(targetUrl, {
    waitUntil: 'domcontentloaded',
    timeout: 30_000
  });

  if (!response || !response.ok()) {
    throw new Error(`Page load failed: ${response?.status() ?? 'no response'}`);
  }

  // Check that the selector matches a visible element before hiding it.
  const banner = page.locator(bannerSelector).first();
  if (await banner.count() === 0 || !(await banner.isVisible())) {
    throw new Error(`No visible banner found for selector: ${bannerSelector}`);
  }

  await page.screenshot({
    path: 'page.png',
    fullPage: true,
    style: `${bannerSelector} { display: none !important; }`
  });

  await context.close();
} finally {
  await browser.close();
}

Run it with values for the page and selector. Quote the selector so the shell passes it as one value:

TARGET_URL='https://example.com' BANNER_SELECTOR='#cookie-consent' node screenshot.mjs

Playwright’s screenshot style option applies CSS while the screenshot is taken. The rule is intended to affect the captured presentation, not to activate a consent control. The selector is site-specific: inspect the page’s DOM and confirm that the matched element is the banner, not a wrapper containing page content. See the Playwright screenshot API and browser context API.

Why use a fresh context?

A new non-persistent browser context starts without this script inheriting cookies or local storage from an earlier run. It does not guarantee that the website will make no tracking requests: the page’s own scripts can still run after navigation. Do not add an accept click, consent cookie, or saved consent state when the goal is only to clean up the image.

Finding the right selector

  1. Open the target page in browser developer tools and inspect the visible banner.
  2. Find the smallest stable element that contains the banner itself. Prefer a specific ID or class belonging to that banner.
  3. Check whether the banner is inside an iframe. A style on the top-level page does not select elements inside a separate frame; inspect and handle that frame explicitly or choose a capture method that supports the needed frame behavior.
  4. Run the script and inspect the output. Confirm that the banner disappeared and the page content around it remains.

There is no universal cookie-banner selector. Markup changes between sites and can change over time, so validate the selector for each target rather than assuming a selector copied from another page will work.

2. Choose the right method for the job

Method What it changes Use it when Limitation
Capture-time CSS The screenshot’s visual presentation You need a clean image without making a consent choice It does not reject consent or establish whether tracking occurred; the selector is site-specific.
Site’s Reject or Preferences control The site’s consent interaction or state You are testing the consent interface or need to exercise its controls This is a consent interaction, not screenshot-only cleanup. Verify what the site actually records.
Site’s Accept control The site’s consent interaction or state You are specifically testing acceptance behavior It conflicts with the goal of avoiding acceptance.

A hidden banner is not evidence that consent was rejected, that a preference was stored, or that the page stopped collecting data. If you need to verify or control network requests and browser storage, investigate those separately; a screenshot by itself cannot answer those questions.

3. Options and edge cases

Full-page or viewport screenshot

Set fullPage: true to capture the full document, as in the example, or set it to false to capture the current viewport. A long page may load images or other content as it scrolls, so inspect the final image for missing or shifted content.

Wait for the page and banner

The example waits for domcontentloaded to avoid waiting indefinitely for every network connection. If the banner appears later, wait for the verified selector before capturing:

await page.locator(bannerSelector).waitFor({ state: 'visible', timeout: 10_000 });

Use a bounded timeout. Some pages show no banner for a given region, session, or browser state; in that case, a wait for visibility will time out. Handle that as a page-specific condition rather than clicking a control to force a result.

Selectors and layout

  • Use a selector narrow enough to match only the banner. A broad rule such as div { display: none } can hide page content.
  • If the banner has several separate elements, target its outer container where possible. Hiding only a button or text node may leave a blank overlay.
  • If the selector matches multiple elements, inspect each match and refine it. The example hides every element matching the style rule, even though its preflight check looks at the first match.
  • A site may use a shadow root or an embedded frame. Ordinary page-level CSS may not reach into those structures; verify the result and use the browser automation APIs appropriate to the page structure.
  • The banner may cover content with a separate backdrop. If so, identify and target the backdrop only after confirming it belongs to the consent UI.

Screenshot CSS versus page initialization scripts

Use the screenshot style option for a capture-only visual adjustment. A page initialization script is a different mechanism that runs as the page loads and may alter the rendered page state more broadly. Neither a hidden banner nor a CSS change should be described as blocking tracking unless network and storage behavior has been separately inspected.

4. Troubleshooting

Symptom Likely cause Fix
The script reports that no visible banner matches. The placeholder or outdated selector does not match, the banner has not appeared yet, or the page does not show a banner in this context. Inspect the page, set the verified selector, and wait for visibility only if the banner is expected. Do not accept consent to make the selector match.
The banner still appears in the image. The selector is wrong, CSS does not reach an iframe or shadow root, or the banner is rendered outside the selected container. Inspect the actual DOM structure and identify the visible overlay and its container. Confirm the screenshot style is being passed to the screenshot call.
Part of the page disappears. The selector is too broad or matches a shared layout wrapper. Use a more specific selector and review the matched elements before capture.
The page is blank or incomplete. Navigation failed, the page needs more time, or it depends on client-side rendering. Check the navigation response and page errors. Wait for a relevant page element or a bounded delay, then capture again. Avoid an unbounded network-idle wait on pages with persistent requests.
The banner appears in some runs but not others. The site varies its UI by location, timing, browser state, or other conditions. Record the capture context, inspect the banner each time, and make the script handle the no-banner case explicitly.
Tracking still occurs. Hiding the banner changes presentation only; the website’s scripts can still run. Do not treat the screenshot method as tracking prevention. Separately inspect or control requests and storage if that is part of your task.

5. Performance, reliability, and cost

A local Playwright capture has no screenshot API charge, but you operate the browser: installation, browser updates, compute, concurrency, retries, and storage are your responsibility. Keep navigation and selector waits bounded so a slow page or a missing banner does not stall a batch indefinitely. Reuse a browser process for multiple captures when appropriate, while creating a fresh context per capture if you need isolated browser state.

For reliable output, validate the navigation response, check the selector, keep a fixed viewport when comparing images, and inspect representative screenshots after changing a selector. Page content can vary across runs, and hiding a banner does not make page rendering deterministic.

Or skip the browser setup

ScreenshotNeo is a website screenshot API and MCP server. Its capture flow accepts cookie and consent banners like a visitor and removes 60+ known consent platforms, newsletter popups, and chat widgets before the shot; each cleanup step can be turned off. That is a hosted cleanup option, while the Playwright technique above gives you direct control over a specific selector. Check the ScreenshotNeo documentation for API parameters and setup.

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}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await Bun.write('shot.webp', res);

Only clean shots are billed: bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, and response headers report the page verdict and billing status. The MCP server offers take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 screenshots. Sign up for 1,000 free screenshots a month, with no card required.

6. FAQ

Does hiding the banner mean I rejected cookies?

No. It only hides a visual element for the screenshot. Use the site’s actual consent controls if you need to exercise a choice.

Does this guarantee no tracking requests were sent?

No. The page may run scripts and send requests while it loads. A screenshot cannot establish whether tracking happened.

Can I use one selector for every website?

No universal selector is established here. Inspect and verify the banner selector on each target page.

Should I click Accept and then remove the banner?

No, not for this goal. Clicking Accept changes the consent interaction and contradicts the requirement to avoid accepting tracking.

Can I use this on pages I cannot access?

The method is for pages you are authorized to view. It does not bypass authentication or access controls.