Menu
Sign up

Hide cookie banners in screenshots: tested on 12 European sites

How to take website screenshots without cookie consent banners: Puppeteer code that clicks accept, and what our API removed on 12 European sites.

Published November 8, 2026 · 7 min read

A screenshot of a European website taken by a fresh browser shows the consent banner first: a dialog over half the page, a dimmed background and, often, scrolling switched off. For a thumbnail, a monitoring archive or a page in a report, that is the wrong picture. This page shows the two ways to get rid of it — accept or hide — with Puppeteer code, and what came out when we ran both on 12 real sites.

How we tested. On 2026-11-08 we captured the home pages of The Guardian, Le Monde, Der Spiegel, IKEA Germany, Booking.com, Cookiebot, Marca, Bild, Zalando, BBC, Wirtualna Polska and Onet at 1280×800, from a machine in Poland, so every site treated us as an EU visitor. Each site went through our API twice (banner option off and on) and once through the Puppeteer script below. Banners differ by country, by day and by A/B test; treat the counts as one snapshot, not a ranking of sites.

Accept or hide?

There are two ways to remove a banner from a capture:

  • Click "accept". The consent platform runs its own code: it stores the choice, removes the dialog and the dark overlay, and unlocks scrolling. The page then looks as it does for a visitor who has agreed — including the ads and trackers that consent switches on (after accepting on Marca, a game ad filled the top of the page).
  • Hide it with CSS. display: none on the banner's container. Nothing else changes, but an overlay or a overflow: hidden on <body> may stay behind, and a full-page capture may then stop at the first screen.

In practice you do both: click where you can, hide what is left. Clicking "reject" works too where a site offers it on the first layer, but many sites put it one screen deeper, and a "pay or accept" site (Le Monde, Spiegel, Bild, Marca and The Guardian all had one) offers no free reject at all.

Doing it yourself in Puppeteer

The script below tries the "accept all" buttons of the common consent platforms in every frame, falls back to matching button text, then injects CSS for whatever stays. It ran with Puppeteer 25 on 2026-11-08:

import puppeteer from 'puppeteer';

// "Accept all" buttons of common consent platforms.
const ACCEPT = [
  '#onetrust-accept-btn-handler',                           // OneTrust
  '#CybotCookiebotDialogBodyLevelButtonLevelOptinAllowAll', // Cookiebot
  '#CybotCookiebotDialogBodyButtonAccept',
  '#didomi-notice-agree-button',                            // Didomi
  '[data-testid="uc-accept-all-button"]',                   // Usercentrics
  '.qc-cmp2-summary-buttons button[mode="primary"]',        // Quantcast
  'button.sp_choice_type_11',                               // Sourcepoint (in an iframe)
];
// Text fallback for in-house banners.
const TEXT = /^(accept all( cookies)?|allow all|i agree|agree|alle akzeptieren|tout accepter|accepter et continuer|aceptar todo|acepto)/i;
// What to hide if clicking did not work.
const HIDE = '#onetrust-consent-sdk, #CybotCookiebotDialog, #didomi-host, #usercentrics-root, .qc-cmp2-container, [id^="sp_message_container"] { display: none !important; } html, body { overflow: auto !important; }';

async function acceptCookies(page) {
  for (const frame of page.frames()) {
    const clicked = await frame.evaluate((selectors, text) => {
      const visible = (el) => el && el.getBoundingClientRect().height > 0;
      for (const s of selectors) {
        const el = document.querySelector(s);
        if (visible(el)) { el.click(); return s; }
      }
      const button = [...document.querySelectorAll('button, a[role="button"]')]
        .find((b) => visible(b) && new RegExp(text, 'i').test(b.textContent.trim()));
      if (button) { button.click(); return button.textContent.trim(); }
      return null;
    }, ACCEPT, TEXT.source).catch(() => null);
    if (clicked) return clicked;
  }
  return null;
}

const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.setViewport({ width: 1280, height: 800 });
await page.goto('https://www.theguardian.com/europe', { waitUntil: 'load' });
await new Promise((r) => setTimeout(r, 2000));   // banners arrive late
await acceptCookies(page);
await new Promise((r) => setTimeout(r, 1000));   // let the dialog close
await page.addStyleTag({ content: HIDE });
await page.screenshot({ path: 'guardian.jpg', type: 'jpeg' });
await browser.close();

Three details matter. Frames: Sourcepoint (The Guardian, BBC, Bild, Spiegel) draws its dialog in a cross-origin iframe, so a selector in the main frame finds nothing — page.frames() reaches it. Timing: most banners appear after load, so a fixed wait or a waitForSelector with a short timeout is needed. Text: the button text is in the page's language.

What this script got on the same 11 sites that showed a banner:

Result Sites
Banner gone The Guardian, Le Monde, IKEA, Cookiebot, Marca, Bild, Der Spiegel (7)
Dialog gone, a cookie bar left at the bottom BBC
Banner left: button text not in the list Wirtualna Polska ("Akceptuję i przechodzę do serwisu"), Onet ("Przejdź do serwisu")
No page: the site answered "Site can't be reached right now" to default headless Chrome Zalando

None of these is hard to fix one by one — add the Polish texts, the BBC bar's selector, a normal user agent. That is the real cost of doing it yourself: the list grows with every site you capture, and vendors change their markup. Two shortcuts exist. The EasyList Cookie List is a maintained filter list of banner elements, usable through an ad-blocking library. DuckDuckGo's autoconsent (MPL-2.0) is a library of per-platform rules that click through consent pop-ups, choosing opt-in or opt-out, and runs in a Chrome extension or a Playwright-driven headless browser; DuckDuckGo's own browser apps use it.

The same sites through our API

Our screenshot API does the same in one option. block_cookie_banners first clicks "accept" for the consent platforms it knows (OneTrust, Cookiebot, Didomi, Usercentrics, Quantcast, TrustArc, Sourcepoint) in every frame, then tries "accept" buttons by their text (English, German, French, Spanish, Italian, Polish, Dutch, Swedish, Portuguese, Czech and Hungarian) inside elements that call themselves cookie or consent banners, and hides what is left using the EasyList Cookie List, unlocking scrolling afterwards:

curl -X POST "https://shareglint.com/v1/screenshots?wait=true" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://www.theguardian.com/europe", "block_cookie_banners": true, "format": "jpeg"}'

What came out on the 12 sites:

Without the option With block_cookie_banners
Sites showing a cookie banner 11 of 12 (Booking.com showed none to us) 1 of 12 in the first run (Marca), 0 after the fix below
Median render time 5.0 s 9.4 s
Other pop-ups on the picture — Spiegel: a subscription offer; Booking.com: a sign-in box

Marca's banner is a "pay or accept" box whose button reads "Acepto y continúo gratis", which the text matching did not recognise in the first run. Clicking it ourselves fixed the capture: "click_selector": ["button[action-name=\"agreeAll\"]"]. We added the phrase to the text matching the same day, and a second capture of Marca with only block_cookie_banners came out clean. That is the general workaround for any banner the option misses: name its button in click_selector. The subscription offer and the sign-in box are not consent banners and are not touched by the option; hide them with hide_selectors once you know their selector (right-click → Inspect in Chrome shows it).

The extra four seconds are the price of waiting: the capture watches for consent-platform traffic and waits for late banners and for the page to settle after the click. Sites without any banner pay a little of it too (example.com: 1.8 s without the option, 6.0 s with).

Options that go with it

  • block_ads hides ads and blocks ad requests; on its own it also turns on block_cookie_banners. Useful together with "accept", which switches ads on.
  • block_trackers blocks analytics and tracking requests (EasyPrivacy).
  • hide_selectors takes a list of CSS selectors to hide; click_selector one selector or a list, clicked in order before the capture.
  • full_page with lazy_load for the whole page; after an "accept" the page scrolls again.

A viewport screenshot is 1 render of the quota, a full page 2, and the same URL with the same options within 24 hours is returned from cache for free. The option list is in the screenshot API docs; bulk screenshots shows how to run it over a list of URLs.

Limits, honestly

  • Banners change. A site that is clean today may ship a new dialog tomorrow; the filter lists catch up, but not the same day.
  • Country matters. We captured as a visitor from Poland. Outside the EU many of these sites show a smaller banner or none, so the same URL can give a different picture from another country.
  • Accepting is accepting. The capture session agrees to the site's cookies, so the picture shows the consented page. Nothing is stored between captures: each one connects to a fresh browser, so the banner is accepted again every time.
  • Pages behind a login are out of reach for the API; for those, run your own Puppeteer with the session cookies.

FAQ

How do I take a screenshot without the cookie banner?

Either accept the banner before the capture (click its "accept all" button, as a visitor would) or hide it with CSS. Clicking is cleaner: the platform removes its own overlay and unlocks scrolling. Hiding is the fallback for banners you cannot click. With our API, set "block_cookie_banners": true and both happen for you.

Why does my Puppeteer screenshot still show the cookie banner?

Usually one of three reasons: the banner loads a second or two after the load event, it sits in an iframe (Sourcepoint draws its dialog in one, so page.$ in the main frame finds nothing), or it is an in-house banner whose button text your script does not know. In our test, a short script missed both Polish news sites for the last reason.

Does hiding cookie banners also remove other pop-ups?

No. Subscription offers, sign-in prompts and newsletter boxes are not consent banners. In our test Der Spiegel showed a subscription offer and Booking.com a sign-in box after the cookie banner was gone. Hide those with their own selector (hide_selectors) or close them with click_selector.

Is it slower to remove cookie banners?

Yes, a little: the capture waits for banners that arrive late and for the page to settle after the click. On our 12 sites the median render time was 5.0 s without the option and 9.4 s with it.