To block cookie banners in a screenshot, set block.cookie_banners: true; add block.ads, block.trackers and block.chat_widgets for a fully clean page. These four switches handle most sites. For the banners that survive, this guide gives a fallback in three steps (click, remove, block the script), a table of common consent managers, and a script that renders every URL with and without blocking so you can check the result yourself. It is part of the guides; the option reference is blocking.
Tested on October 15, 2026: the variant script, request bodies and SDK examples (Node.js 22.18.0, Python 3.14.8, Ruby 4.0.7, PHP 8.5, Go 1.27) against a local mock of the RenderScreenshot API. We have not yet published renders or success rates from a consent-heavy test set; the "Check it on your URLs" section shows how to produce them.
The minimal request
GET, with the two blocking switches that have query parameters:
curl "https://api.renderscreenshot.com/v1/screenshot?url=https%3A%2F%2Fexample.com&block_cookies=true&block_ads=true" \ -H "Authorization: Bearer $RS_API_KEY" --output clean.png
POST, with every switch:
curl -X POST https://api.renderscreenshot.com/v1/screenshot \ -H "Authorization: Bearer $RS_API_KEY" -H "Content-Type: application/json" \ -d '{ "url": "https://example.com", "block": { "cookie_banners": true, "ads": true, "trackers": true, "chat_widgets": true } }' --output clean.png
What each option does
| Option | Default | What it does | Side effects |
|---|---|---|---|
block.cookie_banners |
false |
Clicks the first accept button it recognizes and waits 300 ms; if it finds none, hides common banner elements | The page usually behaves as if consent was given |
block.ads |
false |
Blocks requests to known ad networks and hides common ad containers | Site-specific ad wrappers can keep their size |
block.trackers |
false |
Blocks analytics and tracking scripts | Most analytics tags do not fire during the capture |
block.chat_widgets |
false |
Blocks Intercom, Drift, Zendesk, Crisp and similar | None known |
block.requests |
none | Blocks URLs matching glob patterns (*, **, ?) |
Blocking a script the page needs can break rendering |
block.resources |
none | Blocks image, font, media, script or stylesheet |
script and stylesheet often break layout |
Combine cookie_banners with trackers. Because the banner is usually dismissed by accepting, the site may then load the analytics and marketing tags it was waiting to load. block.trackers stops most of them.
When a banner survives: a three-step fallback
Consent managers change their markup, and some sites build their own banner. Work through these steps in order and stop at the first that works.
1. Click the site's own accept button. This keeps the page in the state a real visitor sees.
{ "url": "https://example.com", "block": { "cookie_banners": true }, "page": { "click": "#onetrust-accept-btn-handler", "click_required": false } }
click_required: false (the default) means the capture still succeeds on pages where the button is absent. The renderer waits 300 ms after the click. If the banner fades out more slowly, add an inline script such as new Promise((r) => setTimeout(r, 600)): scripts run after the click and the renderer waits for the promise. wait.delay does not help here, because it runs before the click.
2. Remove the banner container. When clicking does nothing, or the site reloads after consent, remove the container and the dimmed backdrop:
{ "url": "https://example.com", "page": { "remove": ["#onetrust-consent-sdk", "#CybotCookiebotDialog", ".cookie-overlay"] } }
page.remove collapses the space; page.hide keeps it, which matters for banners that sit in the page flow rather than on top of it.
3. Block the consent manager's script. No script, no banner:
{ "url": "https://example.com", "block": { "requests": ["*cdn.cookielaw.org*", "*consent.cookiebot.com*"] } }
Use this last. Some sites hold back content until consent arrives, so with the script blocked you may get placeholders where videos, maps or even prices should be.
Common consent managers
These selectors and hosts are the ones in common use in October 2026. Vendors change markup, so confirm them in your browser's inspector before you rely on them.
| Consent manager | Container to remove | Accept button to click | Script host to block |
|---|---|---|---|
| OneTrust | #onetrust-consent-sdk |
#onetrust-accept-btn-handler |
cdn.cookielaw.org |
| Cookiebot | #CybotCookiebotDialog |
#CybotCookiebotDialogBodyLevelButtonLevelOptinAllowAll |
consent.cookiebot.com |
| Didomi | #didomi-host |
#didomi-notice-agree-button |
sdk.privacy-center.org |
| TrustArc | #truste-consent-track |
#truste-consent-button |
consent.trustarc.com |
| Usercentrics | #usercentrics-root (shadow DOM) |
inside the shadow root | app.usercentrics.eu |
Usercentrics renders its banner inside a shadow root, which page selectors cannot reach into. Remove the host element, #usercentrics-root, or block the script host.
Banners that appear late
The built-in clean-up runs once, after the page loads and after wait.delay, and before your page changes. A banner that a site shows two or three seconds after load is not there yet when the clean-up runs. Set wait.delay (up to 10,000 ms) so the banner exists by then.
Ads: collapse the empty slots
block.ads stops ad network requests and also hides common ad containers, such as AdSense ins.adsbygoogle elements and Google ad iframes. Sites often wrap those in their own containers with a reserved height, to avoid layout shift. The result is a blank rectangle. Remove the site's wrappers:
{ "url": "https://example.com/article", "block": { "ads": true }, "page": { "remove": ["ins.adsbygoogle", ".ad-slot", "[id^='div-gpt-ad']"] } }
Use the class or ID the site uses for its own ad wrappers; the three above are examples, not a complete list.
SDK examples
All four switches plus a URL pattern, in each official SDK. page.click and page.remove have no documented builder method; send them in the POST body.
Node.js
import { Client, TakeOptions } from 'renderscreenshot'; const client = new Client(process.env.RS_API_KEY); const image = await client.take( TakeOptions.url('https://example.com').blockAds().blockTrackers() .blockCookieBanners().blockChatWidgets().blockUrls(['*cdn.cookielaw.org*']) );
Python
image = client.take( TakeOptions.url('https://example.com').block_ads().block_trackers() .block_cookie_banners().block_chat_widgets().block_urls(['*cdn.cookielaw.org*']) )
Ruby
image = client.take( RenderScreenshot::TakeOptions.url('https://example.com').block_ads.block_trackers .block_cookie_banners.block_chat_widgets.block_urls(['*cdn.cookielaw.org*']) )
PHP
$image = $client->take( TakeOptions::url('https://example.com')->blockAds()->blockTrackers() ->blockCookieBanners()->blockChatWidgets()->blockUrls(['*cdn.cookielaw.org*']) );
Java
byte[] image = client.take( TakeOptions.url("https://example.com").blockAds().blockTrackers() .blockCookieBanners().blockChatWidgets().blockUrls(Arrays.asList("*cdn.cookielaw.org*")) );
Go
image, err := client.Take(ctx, rs.URL("https://example.com").BlockAds().BlockTrackers(). BlockCookieBanners().BlockChatWidgets().BlockURLs([]string{"*cdn.cookielaw.org*"}))
The Java example follows the Java SDK reference and was not run; the others ran against the mock API.
Check it on your URLs
Blocking is heuristic, so measure it on the pages you care about. This script renders each URL three ways (no blocking, banners only, everything) and saves the images next to each other. It costs 3 credits per URL.
// variants.mjs: render each URL with and without blocking, so you can compare the images side by side. // Node 22+. Usage: RS_API_KEY=rs_live_... node variants.mjs urls.txt (writes ./out/*.png) import { mkdir, readFile, writeFile } from 'node:fs/promises'; const API = process.env.RS_API_BASE ?? 'https://api.renderscreenshot.com'; const VARIANTS = { none: {}, banners: { block: { cookie_banners: true } }, clean: { block: { cookie_banners: true, ads: true, trackers: true, chat_widgets: true } }, }; await mkdir('out', { recursive: true }); const urls = (await readFile(process.argv[2] ?? 'urls.txt', 'utf8')).split('\n').filter(Boolean); for (const url of urls) { for (const [name, extra] of Object.entries(VARIANTS)) { const res = await fetch(`${API}/v1/screenshot`, { method: 'POST', headers: { Authorization: `Bearer ${process.env.RS_API_KEY}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ url, viewport: { width: 1280, height: 800 }, ...extra }), }); if (!res.ok) { console.error(`${url} [${name}]: ${res.status} ${await res.text()}`); continue; } const file = `out/${new URL(url).hostname}-${name}.png`; await writeFile(file, Buffer.from(await res.arrayBuffer())); console.log(`${file}`); } }
Open the out/ folder and look at each trio. Record, per URL: banner gone (yes or no), ad slots collapsed, chat bubble gone, and any content missing in the clean image that is present in none. Missing content almost always means a site that gates content on consent; for those, use the click step instead of blocking. Failed renders are printed with their typed error and cost no credits.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Banner still visible | Custom or new consent manager markup, or the banner appeared after the clean-up ran | Fallback step 1 or 2 with the live selector; wait.delay for late banners |
| Dark overlay remains after the banner is gone | Backdrop is a separate element | Add the backdrop selector to page.remove |
| Embedded videos or maps show placeholders | Consent script blocked; the site waits for consent | Click accept (step 1) instead of blocking the script |
| Blank rectangles where ads were | The site's own wrapper reserves the height | page.remove the wrapper |
| Chat bubble still in the corner | Widget not on the built-in list | block.requests with the widget's host, or page.hide its container |
| Page layout broken | block.resources includes script or stylesheet |
Block specific URLs with block.requests instead |
| Banner removed but the page looks unstyled or empty | Removed a wrapper that contains the page | Use a narrower selector; check it in the inspector |
| Click step fails the capture | click_required: true on a page without that button |
Leave click_required false for mixed URL lists |
Related parameters
- Blocking: every
block.*option and the glob syntax. - Page modifications:
click,hide,remove,scriptsandstyles. The customize the page guide shows how to combine them. - Wait options: give a banner's closing animation time with
wait.delay. - Try it on your own site with a free API key.