ScreenshotNeo

BlogHow-to

Use Puppeteer to Hide a Website’s Cookie Banner in Screenshots

Hide a known cookie banner in a Puppeteer screenshot by waiting for its selector and injecting CSS. This changes the screenshot, not the site's consent state.

By the ScreenshotNeo team4 October 20266 min read

To hide a cookie banner in a Puppeteer screenshot, navigate to the page, wait for the banner’s actual selector, inject a CSS rule that hides it, then capture the page. The selector and when the banner appears vary by site, so inspect the rendered page and replace the example selector below. Hiding the banner changes its presentation in the captured page; it does not accept, reject, or record cookie consent.

Runnable Puppeteer example

This Node.js script launches headless Chrome, waits for a banner, hides it with CSS, and saves a full-page PNG. It assumes the target site has an element with the example selector #cookie-banner; inspect the site and substitute its real selector before running.

const puppeteer = require('puppeteer');

(async () => {
  const url = process.argv[2] || 'https://example.com';
  const selector = process.env.COOKIE_BANNER_SELECTOR || '#cookie-banner';
  const browser = await puppeteer.launch({ headless: true });

  try {
    const page = await browser.newPage();
    await page.setViewport({ width: 1440, height: 900 });
    await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 30000 });
    await page.waitForSelector(selector, { timeout: 10000 });
    await page.addStyleTag({
      content: `${selector} { display: none !important; }`
    });
    await page.screenshot({ path: 'page.png', fullPage: true });
  } finally {
    await browser.close();
  }
})().catch(error => {
  console.error(error);
  process.exitCode = 1;
});

Install Puppeteer with npm install puppeteer, save the script as capture.js, and run node capture.js https://example.com. To use a different selector without editing the script, set COOKIE_BANNER_SELECTOR in the environment. Puppeteer runs headless by default, and its Page API provides the navigation, style injection, evaluation, and screenshot methods used here. See the Puppeteer documentation.

Find a selector that matches the banner

  1. Open the page in a browser and inspect the visible banner in developer tools.
  2. Identify a stable ID, class, or other CSS selector for the banner container. Prefer a selector specific to the banner over a broad selector such as div.
  3. Check whether the banner is inside an iframe. A selector in the top-level page cannot target content inside a separate frame; you must inspect and handle the relevant frame separately.
  4. Confirm the selector matches the element in the rendered page. A banner may be inserted after initial navigation, which is why the example waits for the selector.

The selector is site-specific. Puppeteer does not automatically identify every cookie banner or supply a universal selector. If a site changes its markup, update the selector.

Choose CSS hiding or DOM removal

CSS injection is usually the clearest choice when the goal is only to change screenshot appearance. It leaves the selected node in the page DOM while hiding it visually. For a one-off capture, you can instead remove the identified node with evaluate():

await page.waitForSelector('#cookie-banner', { timeout: 10000 });
await page.evaluate(() => {
  document.querySelector('#cookie-banner')?.remove();
});
await page.screenshot({ path: 'page.png', fullPage: true });

Use the same inspected selector in both examples. CSS may be preferable when page scripts expect the element to remain present. Removal takes the selected node out of the page context. Neither approach submits a consent choice or updates the site’s consent record.

Timing and capture options

  • Navigation wait: waitUntil: 'domcontentloaded' waits for the document’s DOM to be parsed, but not necessarily for every image or script. Choose a stronger readiness condition when the page needs more time, and set a timeout appropriate to your workload.
  • Banner wait: waitForSelector() prevents injecting the rule before a late-rendered banner exists. Its timeout gives a clear failure when the expected element never appears. If the banner is optional, handle a timeout explicitly rather than assuming it was hidden.
  • Capture size: fullPage: true captures the full document; omit it for a viewport screenshot. Set the viewport before navigation when responsive layout affects the banner or page.
  • Output format: Puppeteer supports screenshot output options such as a file path and image type. Match the output type to the consuming system and use an appropriate file extension.

Troubleshooting

Symptom Likely cause Fix
waitForSelector times out The selector is wrong, the banner has not appeared, or it is inside an iframe. Inspect the rendered page, verify the selector in the correct frame, and check when the banner is inserted.
The banner remains visible The rule targets a child instead of the banner container, a later script recreates or restyles it, or the banner is in another frame. Target the stable outer container, inject after it appears, and inspect the frame and computed styles.
The screenshot has a blank or incomplete page The page was captured before its main content rendered, or navigation failed. Wait for a page-specific content selector or a suitable readiness condition before capturing; inspect navigation errors and the final URL.
The page layout has an empty gap The banner was hidden, but a separate wrapper or reserved space remains. Inspect the layout and hide the specific wrapper only if it is part of the banner presentation.
The banner reappears on another run It is injected asynchronously or the selector/style timing differs between runs. Wait for its selector and apply the rule immediately before capture. Keep the selector tied to the current site markup.

Performance, reliability, and cost

A Puppeteer capture requires launching or reusing a browser and loading the target page. For repeated captures, reusing a browser process can avoid repeated launch overhead, while keeping pages isolated and closing each page after use. Set navigation and selector timeouts, close the browser in a finally block, and record failures so one slow or changed page does not silently produce a misleading image. Page load duration and resource use depend on the target site; this guide makes no benchmark claim.

Browser automation has infrastructure costs: the runtime, memory, browser maintenance, and engineering time to handle site-specific selectors and failures. The page’s consent state remains untouched by visual hiding. Follow the site’s own interaction flow whenever the task requires an actual consent choice.

Or skip the browser setup

ScreenshotNeo is a website screenshot API and MCP server. Its screenshot capture removes cookie banners, newsletter popups, and chat widgets from more than 60 known consent platforms before the shot, and each step can be turned off. Bot checks, blank pages, failed loads, timeouts, and cache hits cost nothing; responses identify page verdict and billing status in headers.

One GET request returns an image or PDF. This cURL example saves a WebP screenshot of Stripe:

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

Python:

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)

Node.js:

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 require('node:fs/promises').writeFile('shot.webp', Buffer.from(await res.arrayBuffer()));

See the ScreenshotNeo API documentation for the request options. An MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. The Free plan includes 1,000 shots per month with no card; paid plans start at $5 for 3,000 shots.

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

FAQ

Does hiding the banner mean the visitor consented?

No. CSS hiding and DOM removal alter page rendering. They do not record acceptance, rejection, or another consent choice.

Will the same selector work on every website?

No. Banner markup and timing vary by site. Inspect each target and use a selector that matches its current rendered banner.

Can Puppeteer hide a banner inside an iframe?

Not with a selector evaluated against the top-level document. Identify the frame containing the banner and target the element in that frame.