Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

Use dom-to-image’s filter callback. The callback receives each descendant DOM node; return true to include it and false to omit it. Test node.classList for a class, compare node.id for an ID, or combine both tests. An excluded node takes its entire subtree out of the image.

How the dom-to-image filter works

dom-to-image does not document a selector-string option such as filter: '.ads'. Instead, pass a function in the rendering options object. The function is called with a DOM node and must return a Boolean:

  • true: include the node in the rendered output.
  • false: exclude the node and all of its children.

The callback is not called for the root node supplied to the capture method. That exception matters when you are trying to remove the root itself: choose a parent as the capture root, or place the unwanted element below a wrapper that can be filtered.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Exclude a class

This filter removes every element carrying no-capture, while allowing text and other non-element nodes through:

const root = document.getElementById('capture-root');

const filter = (node) =>
  node.nodeType !== 1 || !node.classList.contains('no-capture');

domtoimage.toPng(root, { filter })
  .then((dataUrl) => {
    const image = new Image();
    image.src = dataUrl;
    document.body.appendChild(image);
  })
  .catch((error) => console.error('Capture failed:', error));

nodeType === 1 identifies an Element. The guard prevents errors if the library passes a text, comment, or other node that does not have classList. Returning true for non-elements is normally the least surprising behavior because the class rule cannot apply to them.

Class matching details

  • classList.contains() tests one complete class token, so no-capture-extra does not accidentally match no-capture.
  • Class names are case-sensitive in HTML and CSS matching.
  • If a class is added or removed dynamically, run the capture after the DOM update has been applied.
  • The rule applies to every matching descendant, not just the first one.

Exclude an ID

IDs should be unique, but comparing the string directly also works if a page contains duplicates:

const root = document.getElementById('capture-root');

const filter = (node) =>
  node.nodeType !== 1 || node.id !== 'no-capture';

domtoimage.toPng(root, { filter })
  .then((dataUrl) => {
    const image = new Image();
    image.src = dataUrl;
    document.body.appendChild(image);
  })
  .catch((error) => console.error('Capture failed:', error));

An element with no ID has an empty id value and therefore passes this particular test. If your application assigns IDs at runtime, start the capture only after those assignments are complete.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Exclude by class, ID, or both

Either a class or a specific ID

Use a logical AND between the “not this class” and “not this ID” conditions. A node is included only when it satisfies both:

const filter = (node) => {
  if (node.nodeType !== 1) return true;

  const hasExcludedClass = node.classList.contains('exclude-from-capture');
  const hasExcludedId = node.id === 'exclude-from-capture';

  return !hasExcludedClass && !hasExcludedId;
};

domtoimage.toPng(document.getElementById('capture-root'), { filter })
  .then((dataUrl) => {
    const image = new Image();
    image.src = dataUrl;
    document.body.appendChild(image);
  })
  .catch((error) => console.error('Capture failed:', error));

Several classes or IDs

For a maintainable deny-list, use sets. This avoids a long chain of comparisons and makes the policy easy to change:

const excludedClasses = new Set(['ads', 'cookie-banner', 'chat-widget']);
const excludedIds = new Set(['debug-panel', 'print-controls']);

const filter = (node) => {
  if (node.nodeType !== 1) return true;

  const excludedByClass = [...node.classList]
    .some((name) => excludedClasses.has(name));
  const excludedById = excludedIds.has(node.id);

  return !excludedByClass && !excludedById;
};

const root = document.querySelector('#capture-root');
domtoimage.toPng(root, { filter })
  .then((dataUrl) => {
    const link = document.createElement('a');
    link.download = 'capture.png';
    link.href = dataUrl;
    link.click();
  });

Choose the correct capture root

Because the callback is not invoked for the root passed to toPng, toJpeg, toBlob, toPixelData, or toSvg, filtering the root itself has no effect. For example, this will still render #capture-root:

const root = document.getElementById('capture-root');
const filter = (node) => node.id !== 'capture-root';
domtoimage.toPng(root, { filter });

To omit that region, capture an ancestor and filter the descendant:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Rank #2
Sale
HTML and CSS: Design and Build Websites
  • HTML CSS Design and Build Web Sites
  • Comes with secure packaging
  • It can be a gift option
const page = document.getElementById('page');
const filter = (node) =>
  node.nodeType !== 1 || node.id !== 'capture-root';

domtoimage.toPng(page, { filter });

Remember that removing a node also removes its children. Conversely, filtering an ancestor cannot preserve a child inside it. Keep every ancestor needed to position the content you want to retain.

Use the filter with other output methods

The same options object is used with the library’s documented output methods. Replace only the method when you need another format:

const options = { filter };
const root = document.getElementById('capture-root');

const pngUrl = await domtoimage.toPng(root, options);
const jpegUrl = await domtoimage.toJpeg(root, options);
const blob = await domtoimage.toBlob(root, options);
const pixels = await domtoimage.toPixelData(root, options);
const svg = await domtoimage.toSvg(root, options);

These methods return promises, so handle success and failure with await/try…catch or .then()/.catch(). The README’s own filter example uses toSvg; the other methods are shown in separate examples but accept the rendering options pattern.

Common mistakes and fixes

Passing a selector string

Symptom: You write { filter: '.no-capture' }, but nothing is excluded or the library rejects the option.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Cause: The documented API expects a function, not a CSS selector string.

Fix: Test classList.contains() or id inside a callback as shown above.

Calling classList on every node

Symptom: An exception says classList is undefined.

Cause: The callback contract is node-based; not every DOM node is an element.

Fix: Guard with node.nodeType !== 1 before reading element properties.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The target is the root

Symptom: The element’s own ID or class is ignored.

Cause: The callback is not called for the capture root.

Fix: Capture an ancestor and filter the target as a descendant, or restructure the markup with a wrapper.

Children disappear unexpectedly

Symptom: Filtering a small-looking element removes more content than expected.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Cause: Excluding a node excludes its complete subtree.

Fix: Move the class or ID to the smallest wrapper that contains only the content you intend to omit.

Rank #4
Sale
Web Design with HTML, CSS, JavaScript and jQuery Set
  • Brand: Wiley
  • Set of 2 Volumes
  • A handy two-book set that uniquely combines related technologies Highly visual format and accessible language makes these books highly effective learning tools Perfect for beginning web designers and front-end developers

Changes are not visible

Symptom: A newly applied class or removed ID has no effect.

Cause: Capture started before the DOM mutation, framework render, or style update completed.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Fix: Trigger the capture after the update (for example, in the framework’s post-render hook or a queued task).

Options copied from another package

Symptom: An option found in an online example is ignored.

Cause: dom-to-image-more and other forks document additional controls such as filterStyles. Fork documentation is not evidence that the original dom-to-image package supports those options.

Fix: Check the README and installed version for the exact package you imported, and keep the callback limited to documented behavior.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Performance and reliability considerations

Keep the predicate inexpensive: class and ID checks are constant-time operations for each visited element, while scanning large arrays or querying the document repeatedly can add unnecessary work. Pre-build sets outside the callback, as in the multi-rule example. Avoid modifying the DOM from inside the predicate; filtering should describe what to include, not mutate the tree being traversed.

Use a stable capture root and wait until images, fonts, and application state are ready. If a capture fails, log the rejected promise so the underlying error is not hidden. Filtering cannot repair unrelated rendering problems such as inaccessible cross-origin resources, missing styles, or a root that is not present.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup

For server-side or automated screenshots, ScreenshotNeo accepts one request and returns a PNG, JPEG, WebP, or PDF. It is not a DOM filter, so use the browser callback when you must remove a particular class or ID from an already rendered page. Use ScreenshotNeo when you want a remote capture without maintaining browser automation: it accepts cookie and consent banners before capture, removes more than 60 known consent platforms plus newsletter popups and chat widgets, and lets each cleanup step be disabled.

Only clean shots are billed. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are reported in the response and cost nothing. Its MCP server exposes take_screenshot, get_page_info, and capture_pdf to Claude, Cursor, and other MCP clients.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

cURL

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,
)
r.raise_for_status()
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(`HTTP ${res.status}`);
const bytes = Buffer.from(await res.arrayBuffer());
await import('node:fs/promises').then(fs => fs.writeFile('shot.webp', bytes));

See the ScreenshotNeo documentation for parameters such as full-page capture, CSS selectors, custom JavaScript, waits, device presets, PDF settings, headers, cookies, geolocation, caching, signed links, asynchronous jobs, bulk capture, and usage reporting. The free plan includes 1,000 screenshots per month without a card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.

FAQ

Can I filter the root node directly?

No. The documented callback is not called for the node passed as the capture root. Capture an ancestor if the root itself must be omitted.

Does excluding a parent preserve its children?

No. Returning false excludes the node and its entire descendant subtree.

Is filterStyles available in dom-to-image?

Do not assume so. That option is documented by the dom-to-image-more fork; verify the package and version installed in your project.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Frequently Asked Questions

Can I filter the root node directly?

No. The callback is not called for the node passed as the capture root. Capture an ancestor if the root itself must be omitted.

Does excluding a parent preserve its children?

No. Returning false excludes the node and its entire descendant subtree.

Is filterStyles available in dom-to-image?

Do not assume so. That option is documented by the dom-to-image-more fork; verify the package and version installed in your project.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.