Block Ads, Chat Widgets & Distractions
Every screenshot you take through an API gets a fresh browser session. No cache, no cookies, no logged-in state. That means every site treats it like a first-time visitor: a cookie consent banner appears, the chat widget pops up in the corner, and if the page runs ads, they load in iframes that shift the layout around. On a news site, ads can take up more screen space than the article itself. None of this is the content you came for.
ScreenshotRun has three boolean parameters that handle the most common distractions: block_cookies removes consent banners, block_ads strips ad containers, and block_chats hides chat widgets like Intercom, Drift, and Tawk.to. For anything these don't cover, hide_selectors lets you target specific elements by CSS selector. Between them, you can clean up virtually any page without writing CSS or JavaScript.
Cookie banners: on by default
The block_cookies parameter is the only one that's enabled by default. There's a reason for that: screenshots always look like a first visit, and on most sites that means a consent banner covering a chunk of the viewport. Without blocking, you'd need to deal with this on every single capture.
The renderer handles cookie banners in three steps. First, it hides the banner elements with CSS so they don't appear in the capture. Then it tries to click an "Accept" button to dismiss the dialog properly. The click logic is careful about this: it checks up to six levels of parent elements to make sure the button is actually part of a consent dialog and not some other UI element. It supports accept buttons in twelve languages, including German, French, Spanish, Japanese, and Korean. After clicking, it waits a few hundred milliseconds for animations to finish, then removes the banner from the DOM entirely.
curl "https://api.screenshotrun.com/v1/screenshots/capture" \
-H "Authorization: Bearer YOUR_API_KEY" \
-G \
--data-urlencode "url=https://example.com" \
--data-urlencode "block_cookies=true" \
--data-urlencode "format=png"
If you need to see the cookie banner (for compliance testing or consent flow audits), set block_cookies=false explicitly.
Blocking ads
Ads cause two problems in screenshots. The obvious one is visual clutter: banners, sticky footers, interstitials, and in-content ad blocks that break the reading flow. The less obvious problem is speed. Ad networks inject dozens of scripts that make hundreds of network requests. A news article that loads in 2 seconds for a regular user can take 6-8 seconds when the renderer has to wait for all those ad scripts to finish. Blocking ads makes captures both cleaner and faster.
curl "https://api.screenshotrun.com/v1/screenshots/capture" \
-H "Authorization: Bearer YOUR_API_KEY" \
-G \
--data-urlencode "url=https://news-site.com/article/123" \
--data-urlencode "block_ads=true" \
--data-urlencode "full_page=true" \
--data-urlencode "format=png"
The renderer targets Google Adsense (ins.adsbygoogle), Google Publisher Tags ([id^="div-gpt-ad"]), DoubleClick iframes, and generic ad containers with classes like ad-container, ad-wrapper, ad-slot. It also strips AMP ad elements. All matching elements get hidden with CSS first, then removed from the DOM.
One thing to know: block_ads targets common ad network selectors. If a site uses a custom ad system with non-standard class names, the built-in blocker won't catch it. That's where hide_selectors comes in.
Blocking chat widgets
Chat widgets are the floating bubble in the bottom-right corner of almost every SaaS site. They're fine for users, but in screenshots they sit on top of your content and there's no way to dismiss them without clicking. The block_chats parameter handles the major providers: Intercom, Crisp, Tawk.to, Drift, Zendesk, LiveChat, HubSpot, Tidio, Chatwoot, and HelpScout.
curl "https://api.screenshotrun.com/v1/screenshots/capture" \
-H "Authorization: Bearer YOUR_API_KEY" \
-G \
--data-urlencode "url=https://saas-company.com" \
--data-urlencode "block_chats=true" \
--data-urlencode "format=png"
Each widget has its own DOM structure, so the renderer maintains specific selectors for each: #intercom-container for Intercom, .crisp-client for Crisp, [class*="tawk-"] for Tawk.to, [id^="drift-"] for Drift, and so on. The selectors are updated as these services change their markup.
Maximum cleanup: all three together
For the cleanest possible capture, turn on all three parameters. This is what I'd use for thumbnails, client reports, archival captures, or any automated pipeline where visual noise triggers false positives in change detection.
curl "https://api.screenshotrun.com/v1/screenshots/capture" \
-H "Authorization: Bearer YOUR_API_KEY" \
-G \
--data-urlencode "url=https://example.com" \
--data-urlencode "block_cookies=true" \
--data-urlencode "block_ads=true" \
--data-urlencode "block_chats=true" \
--data-urlencode "full_page=true" \
--data-urlencode "format=webp"
Blocking all three also improves capture speed. Fewer scripts loading means faster network idle, which means the renderer starts capturing sooner. On ad-heavy sites I've seen this cut capture time by 2-3 seconds.
When built-in blocking isn't enough
The three boolean parameters cover the standard third-party services. But plenty of sites build their own distractions: custom exit-intent popups, newsletter signup modals, promotional bars, app-install banners. These don't use Intercom or Google Ads, so the built-in blockers won't find them.
That's what hide_selectors is for. Pass an array of up to 20 CSS selectors, and the renderer does three things: hides them with CSS (display:none !important), removes them from the DOM, and sets up a MutationObserver that watches for any matching elements that appear dynamically after page load. That last part matters for popups triggered by scroll position or time delays.
curl "https://api.screenshotrun.com/v1/screenshots/capture" \
-H "Authorization: Bearer YOUR_API_KEY" \
-G \
--data-urlencode "url=https://example.com" \
--data-urlencode "block_ads=true" \
--data-urlencode "block_chats=true" \
--data-urlencode 'hide_selectors=[".exit-popup", ".newsletter-modal", ".sticky-promo-bar"]' \
--data-urlencode "format=png"
The combination of built-in blocking plus custom selectors handles nearly everything. Built-in blockers get the common stuff automatically, and hide_selectors targets whatever is specific to that particular site.
How blocking fits into the rendering pipeline
Blocking runs early in the capture process, before your custom code. The order matters if you're combining blocking with CSS/JS injection or other interaction parameters:
- Page loads (waits for network idle)
- Ad blocking runs (hide + remove ad elements)
- Cookie blocking runs (hide + click accept + remove banners)
- Chat blocking runs (hide + remove widgets)
- Custom JavaScript runs (
jsparameter) - Custom CSS is injected (
cssparameter) - hide_selectors runs (CSS + DOM removal + MutationObserver)
click_selector/hover_selectorinteractiondelaywaits- Screenshot is captured
Built-in blocking runs before custom code intentionally. Your JavaScript doesn't need to work around cookie banners or chat widgets because they're already gone by the time your script executes.
Practical use cases
Website monitoring pipelines capture thousands of URLs on a schedule. Without blocking, rotating ads trigger change-detection alerts that aren't real changes. A banner ad swaps out, your diff lights up, and someone has to triage a false positive. With block_ads=true, the ad slots are removed entirely, so your diffs only show actual content changes.
Client reporting has a similar problem. Agencies taking screenshots of client websites for monthly reports don't want the client's chat widget or a cookie banner in the deck. Combine all three blocking parameters with full_page=true and you get a clean, presentation-ready capture every time.
Visual regression testing needs consistent baselines. If your baseline screenshot has an ad in one position and the comparison has a different ad (or no ad at all), the test fails even though the actual UI hasn't changed. Blocking ads removes that variable entirely.
The blocking parameters
| Parameter | Type | Default | Plan | Description |
|---|---|---|---|---|
block_cookies | boolean | true | All plans | Hide and dismiss cookie consent banners. Supports OneTrust, CookieBot, Osano, Didomi, Quantcast, and dozens more. Clicks accept buttons in 12 languages. |
block_ads | boolean | false | Starter+ | Remove ad containers from Google Adsense, Google Publisher Tags, DoubleClick, and generic ad wrappers. |
block_chats | boolean | false | Starter+ | Remove chat widgets from Intercom, Crisp, Tawk.to, Drift, Zendesk, LiveChat, HubSpot, Tidio, Chatwoot, HelpScout. |
hide_selectors | array | — | All plans | Up to 20 CSS selectors. Elements are hidden with CSS, removed from DOM, and watched via MutationObserver for 1 second to catch dynamically injected content. |
block_cookies is available on all plans, including Free. block_ads and block_chats are available from Starter ($9/mo) and up. hide_selectors is available on all plans. See the full blocking & filtering docs for parameter details and more examples.
Limitations
Built-in blocking targets known third-party services. A site with its own custom ad server or a homegrown chat widget won't be caught by block_ads or block_chats. Use hide_selectors for those, or CSS injection if you need more control than just hiding.
Cookie banner detection covers the major consent management platforms, but new ones appear regularly. If a banner slips through, hide_selectors with the banner's CSS selector is the immediate fix. We update the built-in selectors as new platforms gain market share, but there's always a gap between a new consent tool launching and us adding support for it.
Blocking works by removing elements after the page loads. The scripts behind those elements still run and make their network requests. If you need to prevent the network requests entirely (to speed up loading or avoid tracking), use the block_requests parameter with URL patterns, or block_resources to block entire resource types like scripts or stylesheets.
Clean screenshots without the noise. Block ads, chat widgets, and cookie banners with a single API call.
Get your free API keyFrequently asked questions
Cookie banners appear on nearly every screenshot because captures always look like a first visit. Ads and chat widgets aren't on every site, and sometimes you need to keep them visible. That's why ads and chats are opt-in.
Google Adsense, Google Publisher Tags, DoubleClick, and generic ad containers with classes like ad-container, ad-wrapper, and ad-slot. For custom ad systems with non-standard class names, use hide_selectors to target them by CSS selector.
Intercom, Crisp, Tawk.to, Drift, Zendesk, LiveChat, HubSpot, Tidio, Chatwoot, and HelpScout. The selectors are updated as these services change their markup.
Yes. Built-in blocking removes standard third-party elements automatically, while hide_selectors targets custom popups, modals, and promotional bars specific to a particular site. You can use up to 20 CSS selectors.
The opposite. Blocking ads speeds up captures because ad scripts generate hundreds of network requests. Without them, the page reaches network idle faster and the renderer starts capturing sooner.
Vitalii Holben