ScreenshotNeo

BlogHow-to

How to Block Ads and Tracking Scripts in Screenshot API Captures

Block unwanted ad and analytics requests during screenshot capture without breaking the page. See a Playwright implementation, hosted API options, and troubleshooting tips.

By the ScreenshotNeo team4 October 20267 min read

To block ads and tracking scripts in a self-hosted screenshot, install Playwright request routing before navigating, then abort only requests that match known ad or analytics endpoints. Continue every other request. For a hosted screenshot API, enable its ad and tracker controls explicitly if it provides them. Avoid blocking every script or all network traffic: page behavior, content, and layout may depend on those requests.

This guide uses Playwright’s JavaScript API. It also covers cURL, Python, and Node.js calls to hosted screenshot APIs, along with service-worker limits, breakage risks, troubleshooting, and operational tradeoffs.

1. Block selected requests with Playwright

Register a route on the browser context before page.goto(). The handler can inspect the request URL and resource type, abort a match, and continue everything else. Context routing applies across pages in that context, including popups and opened links, subject to the service-worker caveat below. The following is a runnable example; its example domains are placeholders, not a maintained block list.

import { chromium } from 'playwright';

const targetUrl = process.argv[2] ?? 'https://example.com';
const browser = await chromium.launch({ headless: true });
const context = await browser.newContext();

// Replace these placeholders with endpoints you have identified for your target.
const blockedHosts = [
  /analytics-provider\.example/i,
  /ad-network\.example/i,
];

await context.route('**/*', async route => {
  const request = route.request();
  const url = request.url();
  const shouldBlock = blockedHosts.some(pattern => pattern.test(url));

  if (shouldBlock) {
    await route.abort();
  } else {
    await route.continue();
  }
});

const page = await context.newPage();
await page.goto(targetUrl, { waitUntil: 'networkidle', timeout: 60000 });
await page.screenshot({ path: 'capture.png', fullPage: true });
await browser.close();

Install Playwright with npm install playwright and install a browser with npx playwright install chromium. Save the code as an ES module, for example capture.mjs, then run node capture.mjs https://your-target.example. For an official reference, see the Playwright network guide and the BrowserContext API.

Choose matching rules carefully

Use a maintained ruleset or a measured set of unwanted endpoints for production. Match narrowly enough to preserve site functionality; a broad substring can match a first-party hostname or a useful resource by accident. You can also inspect request.resourceType() when the unwanted traffic is consistently associated with a type, but type alone is often too broad. Blocking script, xhr, or fetch can remove application features as well as analytics.

await context.route('**/*', async route => {
  const request = route.request();
  const url = request.url();
  const type = request.resourceType();

  const knownTracker = /analytics-provider\.example/i.test(url);
  const knownAdHost = /ad-network\.example/i.test(new URL(url).hostname);
  const block = knownTracker || knownAdHost;

  console.log(block ? 'BLOCK' : 'ALLOW', type, url);
  if (block) await route.abort();
  else await route.continue();
});

Logging matched requests during development makes it easier to see whether a rule is too broad. Do not treat the placeholder expressions as a real-world filter list.

Service workers and request coverage

BrowserContext routing does not intercept requests handled by service workers. Playwright recommends setting serviceWorkers: 'block' when interception must cover routed traffic. That setting can change site behavior, including offline or cached behavior, so decide per workload and compare the rendered result with the intended page.

const context = await browser.newContext({
  serviceWorkers: 'block',
});

Routing and page behavior can also vary with frames, requests started after initial load, and popups. Context-level routing is useful for pages in the same context, but verify coverage for the specific site and workflow. Playwright can also modify responses or fulfill requests; those approaches can provide deterministic data when aborting a request would break the page.

2. Use a hosted screenshot API’s controls

A hosted API can avoid maintaining a browser runtime, but its filtering controls and defaults differ by provider. Check the provider’s current API documentation, explicitly enable the controls, and inspect the returned image for missing functionality. For example, PageBolt documents separate blockAds and blockTrackers booleans, both defaulting to false, as well as request and resource controls. It also documents URL substring rules and resource-type blocking. These are vendor-documented options, not independent evidence of blocker completeness.

ScreenshotCenter documents hide_ads=true to reduce ad noise in visual regression and monitoring captures. Treat this as a documented feature, not a guarantee that every ad or tracker will be removed. The research sources do not establish current pricing or independent effectiveness comparisons for these providers.

When evaluating a hosted API, check these details:

  • Are ad and tracker controls separate, and are they off by default?
  • Can you block specific request URLs or hosts without blocking all scripts?
  • Do rules cover requests after initial page load and any relevant frames or popups?
  • What does the service do with service-worker traffic?
  • Can you see whether a capture loaded, failed, or was blocked, and how billing is determined?
  • Does the output retain the page content and layout your use case requires?

For ScreenshotNeo’s controls and request options, see the ScreenshotNeo API documentation.

3. Compare the approaches

Approach Control Coverage consideration Operational work
Playwright request routing Custom URL and request-type rules; can continue, abort, modify, or fulfill requests Service-worker-handled requests are not intercepted by BrowserContext routing Maintain rules and validate page behavior
Hosted API flags Convenient provider-defined controls, sometimes with custom block parameters Coverage and defaults depend on the service; verify its documentation and captures Less browser setup; understand provider behavior and billing
Blanket resource blocking Simple but coarse Can block functionality, content, and layout resources along with unwanted traffic May be quick to configure, but can cause hard-to-diagnose broken pages

The tradeoff is control and maintenance. Self-hosted routing makes matching rules visible and adjustable. A managed option can reduce browser infrastructure work, but you rely on the provider’s documented controls and should validate representative pages.

4. Troubleshoot common capture problems

Symptom Likely cause What to do
Ads or analytics still appear The endpoint did not match, traffic came from another host, or the request was handled by a service worker Log requests, inspect their full URLs, update narrow rules, and decide whether blocking service workers is acceptable.
Page is blank or missing content A broad rule blocked an essential script, API request, or document resource Temporarily allow the blocked requests, inspect what the page needs, and narrow the rule to known ad or tracker endpoints.
Buttons or interactive layout fail A functional script or fetch request was blocked Avoid blocking all scripts, XHR, or fetch traffic. Restore the needed request and target only identified unwanted endpoints.
Hosted API does not block anything The control was omitted or defaults to off Check the current provider documentation and pass the explicit flag; PageBolt documents its ad and tracker booleans as false by default.
Capture stalls waiting for network idle Pages can keep network activity open, or the chosen wait condition is unsuitable Use a bounded timeout and a wait condition suited to the page, such as a known selector or a deliberate delay; do not assume every page reaches network idle.
Results differ between runs Third-party content, timing, consent state, or page data may vary Use stable target pages and wait conditions; where suitable, fulfill or modify responses with deterministic data, and record the capture configuration.

5. Reliability, performance, and cost

Filtering can reduce unnecessary third-party work, but this research provides no benchmark for the speed improvement or the amount of traffic removed. Measure your own representative pages if capture time matters. Routing adds a decision for each request, and complex matching policies require maintenance as endpoints change.

For reliability, install routes before navigation, keep an allow-by-default policy, use bounded navigation and capture timeouts, and inspect captures after changing rules. Treat a blocked request as a possible cause when a layout or feature disappears. If a service-worker block is enabled, account for its effect on the site’s normal behavior.

Costs depend on whether you operate the browser infrastructure or pay a hosted service. Self-hosting requires maintaining browser execution and filtering rules; hosted services reduce that setup but have provider-specific billing and failure behavior. Do not infer a provider’s pricing, performance, or filtering completeness from the presence of a flag.

6. Or skip the browser setup

ScreenshotNeo is a website screenshot API and MCP server from Yorker Media. It has ad and tracker blocking controls, and it also accepts parameters used by other screenshot APIs to make switching easier. Here is a one-request capture:

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

For request options, authentication, and other formats, see the ScreenshotNeo documentation. The same endpoint can be called from Python or Node.js:

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}`);
const bytes = new Uint8Array(await res.arrayBuffer());
await import('node:fs/promises').then(fs => fs.writeFile('shot.webp', bytes));
  • Cookie banners are accepted like a visitor, and 60+ known consent platforms, newsletter popups, and chat widgets are removed before capture; each step can be turned off.
  • Bot checks and CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing. Response headers say which page verdict applied and whether the request was billed.
  • 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 screenshots per month with no card. Paid plans start at $5 for 3,000 screenshots; every feature is on every plan.

Sign up for 1,000 free screenshots a month, with no card required.

7. Frequently asked questions

Does blocking a tracker remove data already loaded into the page?

Request blocking prevents matching requests from completing through the routed path. It does not necessarily remove content already present in the document or data delivered by another endpoint.

Should I block every third-party domain?

Usually not without checking dependencies. Third-party requests can supply fonts, media, embeds, or other behavior that the page needs. Start with identified ad and analytics endpoints.

Can I use the same block rules for every website?

Rules can be reused, but pages use different providers and dependencies. Review matches and capture output for the sites in your workload.

Does an ad-blocking flag prove that all tracking scripts are blocked?

No. A documented option tells you what the provider offers, not the independent coverage or effectiveness of its filtering. Verify the behavior that matters to your capture.