# content_blockers

> Which of eight off-screen bait elements with ad-like names a content blocker hid. No request is made and everything is removed. Not in either id.

Source: https://whiskerjs.com/signals/content-blockers/ (last updated 2026-10-26)

**content_blockers at a glance (from the library code, signalsVersion 9)**

| Field | Value |
| --- | --- |
| Component name | `content_blockers` |
| In the visitorId | no (reported, kept out of both ids) |
| structuredId group | none |
| Hashing | plain value; a digest only when longer than 128 characters or not printable ASCII |
| Excluded under | no browser class |
| Inner timeout | 1000 ms |
| Added in | [signalsVersion 3](https://whiskerjs.com/whats-new/) |

> **In plain words:**
>
> Ad blockers hide page elements whose names look like ads. WhiskerJS puts eight tiny, invisible test boxes with ad-like names on the page for a moment and checks which ones were hidden. That shows whether a blocker is active here, without loading anything. Users switch blockers on and off, so the result is reported but kept out of the identifiers.

## What it reads

Whether each bait element has an `offsetParent` after 50 ms. The baits are 1x1 `div` elements with these selectors: classes `ad-banner`, `adsbox`, `ad-slot`, `banner-ad`, `sponsored-ad`, `textAd`, and ids `ad-unit`, `ad_leaderboard`. They are reported by the keys `ad_banner`, `ad_box`, `ad_slot`, `banner_ad`, `sponsored`, `text_ad`, `ad_unit`, `ad_leaderboard`.

## How the technique works

1. It needs a `document.body`; otherwise `unavailable` / `no_document`.
2. An off-screen container (`position: absolute; left: -9999px`) gets the eight baits and is appended to the body.
3. After 50 ms (time for cosmetic filters to apply), a bait whose `offsetParent` is `null` counts as hidden.
4. If all eight look hidden and the container itself has no `offsetParent`, the page is not laid out (for example `display: none` on the body): `unavailable` / `no_layout`.
5. The value is the keys of the hidden baits, comma-separated, or `none`.
6. The container is removed in a `finally` block, so it leaves nothing behind.

## Why it helps

It tells your server whether cosmetic filtering is active on this page, and roughly which kind of filter list: different blockers and lists hide different subsets of the baits. It also helps explain other values, such as missing page elements.

## Stability

Low to medium: users enable and disable blockers per site, and filter lists update. Outside both ids for that reason.

## Browser support and what blocks it

Works in any browser with a laid-out page: [Chrome](https://whiskerjs.com/browsers/chrome-desktop/), [Firefox](https://whiskerjs.com/browsers/firefox/), [Safari](https://whiskerjs.com/browsers/safari-macos/), [iOS browsers](https://whiskerjs.com/browsers/safari-ios/), [Edge](https://whiskerjs.com/browsers/edge/). [Brave](https://whiskerjs.com/browsers/brave/) has a built-in blocker, so baits may be hidden there by default. Pages that are hidden or not laid out give `no_layout`. On slow or emulated setups the 50 ms wait plus layout can exceed the 1000 ms inner timeout.

## Privacy

It reveals whether an ad blocker hides these names on this page. No ad or filter list is loaded, nothing is requested, and the elements are removed before `collect()` resolves. Leave it out with `collect({ exclude: ['content_blockers'] })` if you do not need it; no id changes.

## How WhiskerJS handles noise and failures

| Status | ruleId | When |
| --- | --- | --- |
| `ok` |   | `none` or a list of hidden bait keys |
| `unavailable` | `no_document` | no `document.body` |
| `unavailable` | `no_layout` | the container itself is not laid out |
| `blocked` | `threw`, `security_error` | adding the elements throws |
| `excluded` | `caller_excluded` | you excluded it |
| `timed_out` | `timeout`, `aborted` | budget or abort |

## Example value

In the container test, headless Chromium and Firefox reported `none`; headless WebKit reported `timed_out` / `timeout` (the run was slow under emulation). With a common ad blocker you might see something like `ad_banner,ad_box,banner_ad`.

## Questions and answers

### Does WhiskerJS load ads or test URLs to detect blockers?

No. It only adds eight small elements with ad-like class names and ids to the page, waits 50 ms and checks which were hidden. No request is made, and the names are WhiskerJS's own, not copied from any filter list.

### What does none mean?

No bait was hidden: either no content blocker is active on this page, or the blocker does not hide these names. It is not proof that no blocker is installed.

### Why is it not in the visitorId?

Users turn blockers on and off per site and filter lists update often, so the value changes too easily.

## Related pages

- [canvas_readback](https://whiskerjs.com/signals/canvas-readback/): Another diagnostic about the browser setup.
- [Content blocker](https://whiskerjs.com/glossary/#content-blocker): What cosmetic filtering is.
- [Privacy](https://whiskerjs.com/docs/privacy/): The hidden elements and when they are removed.
