Only this pageAll pages
Powered by GitBook
1 of 68

Developer Documentation

Loading...

Browser Ad-Filtering Solution

Loading...

Loading...

Loading...

Loading...

Loading...

Guides

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Advanced

Loading...

Loading...

Loading...

Loading...

Snippets

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Performance Snippets

Loading...

Loading...

Loading...

Loading...

Loading...

DATA AND PRIVACY

Loading...

Getting Started

Quickstart

Get up and running with the eyeo Browser Ad-Filtering Solution.

About the eyeo Browser Ad-Filtering Solution

eyeo's Browser Ad-Filtering Solution is a software development kit that you can use to integrate eyeo's ad-filtering technology into Chromium-based browsers.

By the end of this quickstart guide, you'll have cloned the Solution's project and built Chromium with ad blocking for Linux.

This guide assumes familiarity with both Git and the command line.

Install depot_tools

Follow these steps to set up depot_tools:

  1. Clone the repository:

git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
  1. Add depot_tools to your PATH:

export PATH="$PATH:/path/to/depot_tools"

When cloning depot_tools to your home directory do not use ~ on PATH, otherwise gclient runhooks will fail to run. Rather, you should use either $HOME or the absolute path:

export PATH="$PATH:${HOME}/depot_tools"

Warning: It is a good idea at this point to make sure that the gn command is pointing to depot_tools, as it is sometimes possible that a different instance of gn is present on the system:

whereis gn

The output of this command should only show:

gn: /path/to/depot_tools/gn

If there are any others listed in the output, delete them.

Get the eyeo Browser Ad-Filtering Solution code

Clone the eyeo Browser Ad-Filtering Solution repository using the following command:

mkdir chromium && cd chromium
git clone https://gitlab.com/eyeo/adblockplus/chromium-sdk src/

Expect the command to take 30 minutes on even a fast connection, and many hours on slower ones.

Update dependencies and build

  1. Create a .gclient configuration file relevant for your development platform:

Put one of these .gclient files into chromium/ (not chromium/src/):

solutions = [
  {
    "url": "https://chromium.googlesource.com/chromium/src.git",
    "managed": False,
    "name": "src",
    "deps_file": ".DEPS.git",
    "custom_deps": {},
  },
]
solutions = [
  {
    "url": "https://chromium.googlesource.com/chromium/src.git",
    "managed": False,
    "name": "src",
    "deps_file": ".DEPS.git",
    "custom_deps": {},
  },
]
target_os = ["android"]
solutions = [
  {
    "url": "https://chromium.googlesource.com/chromium/src.git",
    "managed": False,
    "name": "src",
    "deps_file": ".DEPS.git",
    "custom_deps": {},
  },
]
target_os = ["win"]
  1. Run gclient sync to update the third party dependencies of Chromium:

This steps downloads and sets up dependencies, in accordance with the .gclient file you created in the previous step.

gclient sync --force --reset --delete_unversioned_trees --no-history
  1. Set up the build:

Chromium uses Ninja as its main build tool along with a tool called GN to generate .ninja files. You can create any number of build directories with different configurations. To create a build directory, run:

cd src/
gn gen out/Default
  1. Build chromium with unit tests:

The following command builds chrome and unit tests:

autoninja -j X -C out/Default chrome components_unittests

where X should be an integer to represent how many jobs should be triggered on the build cluster, to ensure that your system is not overloaded with too many jobs running locally.

Depending on your hardware the build might take several hours to complete.

Run unit tests

You can run ad-filtering unit tests with the following command:

./out/Default/components_unittests --gtest_filter="*Adblock*"

Next up

In this quickstart guide, you cloned and built the eyeo Browser Ad-Filtering Solution and unit tests.

To test the ad-filtering capabilities of the browser see Testing

Check out the eyeo Browser Ad-Filtering Solution Features documentation to learn how the Solution handles common ad-filtering use cases.

Getting Started

On this site, you'll find documentation to help you integrate eyeo's ad-filtering solutions, as well as a comprehensive guide to using snippets.

About eyeo

eyeo Ad-Filtering Solutions offer customizable options to enhance your mobile and desktop products with minimal technical effort.

Ad-filtering solutions

Working with snippets

Maintained as a set of patches added to the , the Solution lets you incorporate eyeo's ad-filtering functionality and filter lists into your own browser.

For a more detailed build description and for building for other platforms follow Chromium's .

is dedicated to building technology that supports a fair and sustainable online value exchange between users, publishers and advertisers.

eyeo offers several ad-filtering solutions for your development projects across different platforms and browsers. Jump right in with the or the .

If you need help with another eyeo product or you're interested in becoming a tech partner, .

eyeo uses snippets to fight ad-filtering circumvention. eyeo's explains what snippets are, which snippets you can use, and examples for putting them into practice.

Chromium project
standard instructions
eyeo
Browser Ad-Filtering Solution
Web Extension Ad-Filtering Solution
reach out to the eyeo team
snippets documentation

Set up user counting

How to set-up eyeometry.

Obligatory arguments

You must provide special gn arguments before building your product in order to enable user counting.

  • eyeo_telemetry_client_id

  • eyeo_telemetry_activeping_auth_token

eyeo will provide the argument values upon contact.

To set the arguments, generate project build files like the following:

gn gen --args='eyeo_telemetry_client_id="mycompany" eyeo_telemetry_activeping_auth_token="peyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9" ...' ...

If you don't set these arguments, eyeo will not correctly attribute users to your product, although your application will still build and run.

Keep your auth token secure. Never embed it in open-source repositories or documents. If your auth token is revealed, reach out to eyeo as soon as possible to receive a new token.

User counting doesn't transfer any PII or other identifiable data to eyeo, nor does it allow tracking or profiling of users by eyeo.

Optional arguments

You may additionally provide values for application and application_version by setting the following gn arguments:

  • eyeo_application_name

  • eyeo_application_version

For example:

gn gen --args='eyeo_telemetry_client_id="mycompany" eyeo_telemetry_activeping_auth_token="peyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9" eyeo_application_name="My great browser" eyeo_application_version="111.24.0.1" ...' ...

No requests sent to data collection services contain any personally identifiable information. To learn about eyeometry, view .

In absence of these values, the eyeo Browser Ad-Filtering Solution will fall back to version_info::GetProductName() and version_info::GetVersionNumber() from

User Counting
version_info.h

Integrate the Solution

In this guide, you'll learn about the different ways you can integrate the eyeo Browser Ad-Filtering Solution into your own Chromium-based browser project.

Integration strategies

You can integrate eyeo's changes into your own Chromium project in three ways:

  • Strategy 1: Base your product on top of eyeo's changes

  • Strategy 2: Download modules and apply them to your source code

  • Strategy 3: Create a patch with changes and apply it to your source code

  • Strategy 4: Copy eyeo's functionality into your adapation

In the following sections, you'll learn the advantages of each strategy.

eyeo recommends Strategy 1.

Strategy 1: Base your product on top of eyeo's changes

If you use this strategy, you'll fork eyeo's Chromium form, then base your development on our release tag.

Benefits of Strategy 1:

  • It's the safest and most reliable way to integrate eyeo’s Browser Ad-Filtering Solution into your browser.

  • Full support from eyeo.

What you need to do

  • Use eyeo's tagged release commit as the parent of your changes. Begin with a git clone of our fork of Chromium and then add your changes. For more information, following the eyeo Browser Ad-Filtering Solution Quickstart guide, which is based on Strategy 1.

  • Make sure your users are properly informed about ad blocking and Acceptable Ads.

eyeo regularly informs you by email when a new version of the Solution is released. eyeo strives for beta releases for every Chromium version one week before the Chromium stable cut and official releases for odd Chromium releases within ten business days of the Chromium stable release.

Strategy 3: create a patch with changes and apply it to your source code

If you use this strategy, you'll check out eyeo's fork of Chromium, generate a patch file (as a diff between the pure Chromium release tag and the eyeo Browser Ad-Filtering Solution release tag) and apply it to your source code.

Benefits and tradeoffs of Strategy 3:

  • Access to all major Solution functionalities

  • Higher risk of conflicts between eyeo and partner changes and more complicated resolution

  • More complex integration strategy than Strategy 1

  • Some information may get lost, which reduces eyeo's ability to provide support.

What you need to do

Make sure that the base version of Chromium you use in your project matches the eyeo Browser Ad-Filtering Solution version you are integrating.

Generating the patch

The diff file is generated with access to eyeo's git Chromium fork repository as a branch diff:

$ git diff 113.0.5672.76 eyeo-release-113.0.5672.76-v1 > ../eyeo-release-113.0.5672.76-v1.diff

Applying the patch

Run the following command to apply the patch:

$ git apply ../eyeo-release-113.0.5672.76-v1.diff
Strategy 4: copy eyeo's functionality into your adaption

If you use this strategy, you'll copy eyeo's functionality into your project.

Benefits and tradeoffs of Strategy 4:

  • Access to all major Solution functionalities.

  • Higher risk of conflicts between eyeo and partner changes and more complicated resolution.

  • More complex integration strategy than Strategies 1 and 2.

  • Additional information gets lost, which reduces our ability to provide support.

Strategy 3, the least safe approach, limits eyeo's ability to debug or support any issues.

What you need to do

  • Track the changed files and apply the changes one-by-one.

  • Copy and integrate all tracked changes.

  • Make sure that your integration supports all the filter options, UI elements and user counting features as required by your contract with eyeo.

You'll also need to ensure that user counting and all required ad filtering and whitelisting features work.

About automation

If you decide to automate the steps to copy eyeo's functionality into your adaptation, remember to:

  • Write the script files that automate the steps.

  • Update the scripts when branch/tag naming agreements are changed or the release flow is changed.

As with any automated, consider whether the time saved will compensate for the efforts to write and test the automation scripts. eyeo can help you decide, so reach out to us with any questions.

eyeo's versioning scheme

For an example Chromium release tag of 113.0.5672.76, eyeo's release tag would be eyeo-release-113.0.5672.76-v1.diff. This tag would contain all Solution-related changes, based on top of the corresponding Chromium release.

Because eyeo hosts the Browser Ad-Filtering Solution in remote Git repositories, you can find the Solution release for each version:

$ git ls-remote --tags https://gitlab.com/eyeo/adblockplus/chromium-sdk
$ git tag | grep release-103
eyeo-release-113.0.5672.76-v1

Usually, one release tag is available for each major Chromium version. Patch releases may also be available if eyeo finds a critical bug in the release.

Strategy 2: Download modules and apply them to your source code

If you use this strategy, you'll download modules of your choice and apply them to your source code.

Benefits and tradeoffs of Strategy 2:

  • Access to all major Solution functionalities.

  • Apply relevant code only, no internal eyeo testing files (for example, CI pipelines and configs).

  • Possibility to apply only needed part of our implementation.

  • More complex integration strategy than Strategy 1.

What you need to do

Make sure that the base version of Chromium you use in your project matches the Browser Ad-Filtering Solution version you are integrating.

Download modules

The module files are stored in the eyeo Browser Ad-Filtering Solution repository inside src/eyeo-modules directory. Identified by a release tag with a -modules suffix:

$ git checkout eyeo-release-113.0.5672.76-v1-modules

Optionally, modules can be downloaded. It won’t require adding eyeo's Browser Ad-Filtering Solution repository as remote.

$ wget "https://gitlab.com/eyeo/adblockplus/chromium-sdk/-/archive/eyeo-release-113.0.5672.76-v1-modules/chromium-sdk-eyeo-release-113.0.5672.76-v1-modules.zip?path=eyeo_modules" -O chromium-sdk-eyeo-release-113.0.5672.76-v1-modules.zip

Applying the module

Choose the modules that are relevant to your needs. Be aware that certain modules require the presence of other modules to be successfully applied.

base.patch:

  • This module provides the core Eyeo ad-filtering engine with all the latest features.

  • Note that it does not include a User Interface, and settings management needs to be implemented separately.

  • It must be applied as the first module.

chrome_integration.patch:

  • This module contains the necessary code for integrating our ad-filtering engine with the Chromium browser.

This module depends on base.patch

webview_integration.patch:

  • This module contains the necessary code for integrating our ad-filtering engine with Chromium WebView component.

This module depends on base.patch

android_api.patch:

  • This module provides the Android Java API for interacting with our ad-filtering engine.

This module can be applied either on chrome_integration.patch or webview_integration.patch

android_settings.patch:

  • This module introduces a simple Android Settings UI, presented as a Chromium settings page.

  • It supports multi-language translations for strings.

This module depends on android_api.patch applied on chrome_integration.patch

extension_api.patch:

  • This module introduces an API for managing Eyeo ad-filtering settings via extensions.

  • Note that it does not include an extension.

This module depends on chrome_integration.patch

content_shell.patch:

  • This module introduces an integration for the content layer.

  • This is just support for specific build target, no other module depends on it.

This module depends on base.patch

eyeo Browser Ad-Filtering Solution modules are designed to be applied with git am command:

$ git am eyeo_modules/base.patch

Configure Solution settings

Customization options for the Browser Ad-Filtering Solution.

Available APIs

You can control the ad-filtering behavior via any of these entry points:

  • The C++ class FilteringConfiguration,

  • The Java class org.chromium.components.adblock.FilteringConfiguration

  • The Browser Extension API defined and documented in chrome/common/extensions/api/eyeo_filtering_private.idl

API requirements

  • Android OS

  • Instance of a BrowserContextHandle required

  • Desktop OS (Windows, Linux, MacOS)

  • The SHA1 hash of your extension ID must be added to the allowlist in chrome/common/extensions/api/_permission_features.json

  • Works on any platform

  • Instance of a BrowserContext required

  • API changes more frequently than the Java and JavaScript APIs

Capabilities

Toggle ad filtering

To toggle ad filtering call setEnabled with the appropriate bool value:

To query if ad filtering is enabled call isEnabled.

The following example disables ad filtering:

import org.chromium.components.adblock.FilteringConfiguration;

// Creates "adblock" configuration if does not exist yet, returns a valid handle.
FilteringConfiguration adblockConfiguration = FilteringConfiguration.createConfiguration("adblock", browserContextHandle);

adblockConfiguration.isEnabled();  // true
adblockConfiguration.setEnabled(false);
adblockConfiguration.isEnabled();  // false
chrome.eyeoFilteringPrivate.isEnabled("adblock");  // true
chrome.eyeoFilteringPrivate.setEnabled("adblock", false);
chrome.eyeoFilteringPrivate.isEnabled("adblock");  // false
#include "components/adblock/content/browser/factories/subscription_service_factory.h"
#include "components/adblock/core/subscription/subscription_config.h"
#include "components/adblock/core/subscription/subscription_service.h"
#include "components/adblock/core/configuration/filtering_configuration.h"

  auto* subscription_service =
      adblock::SubscriptionServiceFactory::GetForBrowserContext(context);
  auto configuration = subscription_service->GetFilteringConfiguration("adblock");
  configuration->isEnabled(); // true
  configuration->SetEnabled(false);
  configuration->isEnabled(); // false

Toggle Acceptable Ads

You can toggle Acceptable Ads by adding or removing a filter list with the Acceptable Ads URL. The following example:

  1. checks whether Acceptable Ads are enabled

  2. disables them

  3. verifies that Acceptable Ads are disabled

import org.chromium.components.adblock.FilteringConfiguration;

// Creates "adblock" configuration if does not exist yet, returns a valid handle.
FilteringConfiguration adblockConfiguration = FilteringConfiguration.createConfiguration("adblock", browserContextHandle);

adblockConfiguration.getFilterLists().contains(FilteringConfiguration.getAcceptableAdsUrl());  // true
adblockConfiguration.removeFilterList(FilteringConfiguration.getAcceptableAdsUrl());
adblockConfiguration.getFilterLists().contains(FilteringConfiguration.getAcceptableAdsUrl());  // false
let aa_url;
chrome.eyeoFilteringPrivate.getAcceptableAdsUrl()
    .then(url => aa_url = url)
    .then(() => chrome.eyeoFilteringPrivate.getFilterLists("adblock"))
    .then(list => list.includes(aa_url))  // true
    .then(() => chrome.eyeoFilteringPrivate.removeFilterList("adblock", aa_url))
    .then(() => chrome.eyeoFilteringPrivate.getFilterLists("adblock"))
    .then(list => list.includes(aa_url)); // false
#include "components/adblock/content/browser/factories/subscription_service_factory.h"
#include "components/adblock/core/subscription/subscription_config.h"
#include "components/adblock/core/subscription/subscription_service.h"
#include "components/adblock/core/configuration/filtering_configuration.h"

  auto* subscription_service =
      adblock::SubscriptionServiceFactory::GetForBrowserContext(context);
  auto configuration = subscription_service->GetFilteringConfiguration("adblock");
  configuration->IsFilterListPresent(AcceptableAdsUrl()); // true
  configuration->RemoveFilterList(AcceptableAdsUrl());
  configuration->IsFilterListPresent(AcceptableAdsUrl()); // false

Add/Remove filter lists

Filter lists are uniquely identified by URLs from which they're downloaded.

Use addFilterList to add and removeFilterList to remove a filter list.

To get the list of installed subscriptions use getFilterLists.

The following code snippet installs http://example.com/example_list.txt:

import org.chromium.components.adblock.FilteringConfiguration;

// Creates "adblock" configuration if does not exist yet, returns a valid handle.
FilteringConfiguration adblockConfiguration = FilteringConfiguration.createConfiguration("adblock", browserContextHandle);
URL exampleFilterList = new URL("http://example.com/example_list.txt");

adblockConfiguration.addFilterList(exampleFilterList);
adblockConfiguration.getFilterLists();  // ["http://example.com/example_list.txt", ...]
var exampleFilterList = new URL("http://example.com/example_list.txt");
chrome.eyeoFilteringPrivate.addFilterList("adblock", exampleFilterList.href);
chrome.eyeoFilteringPrivate.getFilterLists("adblock");  // ["http://example.com/example_list.txt", ...]
#include "components/adblock/content/browser/factories/subscription_service_factory.h"
#include "components/adblock/core/subscription/subscription_config.h"
#include "components/adblock/core/subscription/subscription_service.h"
#include "components/adblock/core/configuration/filtering_configuration.h"

const GURL example_filter_list("http://example.com/example_list.txt");
auto* subscription_service =
    adblock::SubscriptionServiceFactory::GetForBrowserContext(context);
auto configuration = subscription_service->GetFilteringConfiguration("adblock");
configuration->AddFilterList(example_filter_list);
configuration->GetFilterLists(); // ["http://example.com/example_list.txt", ...]

Enable/Disable ad filtering on a specific domain

Use addAllowedDomain to stop filtering ads on a specific domain, and removeAllowedDomain to resume.

getAllowedDomains returns a list of allowed domains.

import org.chromium.components.adblock.FilteringConfiguration;

// Creates "adblock" configuration if does not exist yet, returns a valid handle.
FilteringConfiguration adblockConfiguration = FilteringConfiguration.createConfiguration("adblock", browserContextHandle);

adblockConfiguration.addAllowedDomain("example.com");
adblockConfiguration.getAllowedDomains();  // ["example.com"]
adblockConfiguration.removeAllowedDomain("example.com");
adblockConfiguration.getAllowedDomains();  // []
chrome.eyeoFilteringPrivate.addAllowedDomain("adblock", "example.com");
chrome.eyeoFilteringPrivate.getAllowedDomains("adblock");  // ["example.com"]
chrome.eyeoFilteringPrivate.removeAllowedDomain("adblock", "example.com");
chrome.eyeoFilteringPrivate.getAllowedDomains("adblock");  // []
#include "components/adblock/content/browser/factories/subscription_service_factory.h"
#include "components/adblock/core/subscription/subscription_config.h"
#include "components/adblock/core/subscription/subscription_service.h"
#include "components/adblock/core/configuration/filtering_configuration.h"

const GURL example_filter_list("http://example.com/example_list.txt");
auto* subscription_service =
    adblock::SubscriptionServiceFactory::GetForBrowserContext(context);
auto configuration = subscription_service->GetFilteringConfiguration("adblock");
configuration->AddAllowedDomain("example.com");
configuration->GetAllowedDomains(); // ["example.com"]
configuration->RemoveAllowedDomain("example.com");
configuration->GetAllowedDomains(); // []

Note: Pass a domain ('example.com') as an argument, not a URL ('http://www.example.com/page.html').

Add/Remove custom filters

Use addCustomFilter to add and removeCustomFilter to remove a single filter.

To get the list of custom filters added use getCustomFilters.

The following code snippet installs a new filter:

import org.chromium.components.adblock.FilteringConfiguration;

// Creates "adblock" configuration if does not exist yet, returns a valid handle.
FilteringConfiguration adblockConfiguration = FilteringConfiguration.createConfiguration("adblock", browserContextHandle);

adblockConfiguration.addCustomFilter("example_domain##.example_selector");
adblockConfiguration.getCustomFilters();  // ["example_domain##.example_selector"]
adblockConfiguration.removeCustomFilter("example_domain##.example_selector");
adblockConfiguration.getCustomFilters();  // []
chrome.eyeoFilteringPrivate.addCustomFilter("adblock", "example_domain##.example_selector");
chrome.eyeoFilteringPrivate.getCustomFilters("adblock");  // ["example_domain##.example_selector"]
chrome.eyeoFilteringPrivate.removeCustomFilter("adblock", "example_domain##.example_selector");
chrome.eyeoFilteringPrivate.getCustomFilters("adblock");  // []
#include "components/adblock/content/browser/factories/subscription_service_factory.h"
#include "components/adblock/core/subscription/subscription_config.h"
#include "components/adblock/core/subscription/subscription_service.h"
#include "components/adblock/core/configuration/filtering_configuration.h"

const GURL example_filter_list("http://example.com/example_list.txt");
auto* subscription_service =
    adblock::SubscriptionServiceFactory::GetForBrowserContext(context);
auto configuration = subscription_service->GetFilteringConfiguration("adblock");
configuration->AddCustomFilter("example_domain##.example_selector");
configuration->GetCustomFilters(); // ["example_domain##.example_selector"]
configuration->RemoveCustomFilter("example_domain##.example_selector");
configuration->GetCustomFilters(); // []

Subscribe for resource blocked or allowed events

There is an option to receive events when some resource is blocked or allowed. Typically, this is needed to implement a counter in the UI. Please do not subscribe if you are not going to consume these notifications, as it has a small performance penalty.

import org.chromium.components.adblock.ResourceClassificationNotifier;

ResourceClassificationNotifier.getInstance().addOnAdBlockedObserver(new ResourceClassificationNotifier.ResourceFilteringObserver{
    @Override
    public void onRequestAllowed(ResourceFilteringCounters.ResourceInfo info) {
        // ...
    }
    @Override
    public void onRequestBlocked(ResourceFilteringCounters.ResourceInfo info) {
        // ...
    }
    @Override
    public void onPageAllowed(ResourceFilteringCounters.ResourceInfo info) {
        // ...
    }
    @Override
    public void onPopupAllowed(ResourceFilteringCounters.ResourceInfo info) {
        // ...
    }
    @Override
    public void onPopupBlocked(ResourceFilteringCounters.ResourceInfo info) {
        // ...
    }
});
chrome.eyeoFilteringPrivate.onRequestAllowed.addListener(function(info) {
    // ...
});
chrome.eyeoFilteringPrivate.onRequestBlocked.addListener(function(info) {
    // ...
});
#include "components/adblock/content/browser/factories/resource_classification_runner_factory.h"
#include "components/adblock/content/browser/resource_classification_runner.h"

class MyObserver : public adblock::ResourceClassificationRunner::Observer {
 public:
  void OnRequestMatched(const GURL& url,
                        adblock::FilterMatchResult match_result,
                        const std::vector<GURL>& parent_frame_urls,
                        adblock::ContentType content_type,
                        content::RenderFrameHost* render_frame_host,
                        const GURL& subscription,
                        const std::string& configuration_name) override {
    // ...
  }
  void OnPageAllowed(const GURL& url,
                     content::RenderFrameHost* render_frame_host,
                     const GURL& subscription,
                     const std::string& configuration_name) override {
    // ...
  }
  void OnPopupMatched(const GURL& url,
                      adblock::FilterMatchResult match_result,
                      const GURL& opener_url,
                      content::RenderFrameHost* render_frame_host,
                      const GURL& subscription,
                      const std::string& configuration_name) override {
    // ...
  }
};

MyObserver observer;

adblock::ResourceClassificationRunnerFactory::GetForBrowserContext(context)
    ->AddObserver(&observer);

User counting

How eyeo protects privacy while counting users.

To improve eyeo's understanding of cross-platform usage and versioning, the eyeo Browser Ad-Filtering Solution collects some user data.

Because one of eyeo's driving principles is to respect user privacy, no requests sent to data collection services contain any personally identifiable information (PII).

This page contains information on how and why eyeo implements user counting in its ad-filtering solutions.

Why eyeo count users

  • Understanding user distribution across Chromium and Solution versions helps eyeo decide which versions to maintain and which to deprecate.

  • Understanding user distribution across operating systems and platforms helps eyeo prioritize quality assurance and automation efforts on the most popular platforms and OS versions.

  • Understanding how users perceive Acceptable Ads, which eyeo determines from user opt-out rate. eyeo wants to ensure that ads that users see don't negatively impact user experience.

  • Establishing the basis of payouts to partners who monetize their Acceptable Ads users.

How user counting works

A ping request is sent automatically by the Solution to eyeo's dedicated service at least twice per day, if the browser is in use (including in the background) and ad-filtering is enabled. These contain no personally identifiable information.

Ping request payload

To track active clients while maintaining user privacy, the server combines the values of ping timestamps with a randomly-generated tag. Dates are truncated to further protect privacy.

The following table outlines the parameters sent with the ping:

Parameter
Type
Description

nonce

string

Number only used once, one of the algorithms that might be used to generate nonce is UUID4. This helps to anonymously distinguish between several ping requests with the same values for the rest of the parameters.

addon_name

string

Identifier of the Solution. Example: eyeo-chromium-sdk

addon_version

string

Version of the Solution, corresponding to addon_name. Example: 2.0.0

application

string

Name of the application. Used for attributing users to a specific product. Example: My great browser

application_version

string

Current version of the application. Often follows the underlying Chromium version. Example: 86.0.4240.183

first_ping

string

Timestamp of the first ping sent by the client and acknowledged by the server (as measured by the server), extracted from the first 2xx response body. Example: 2022-02-28T19:50:00Z

last_ping

string

Timestamp of the last ping sent by the client and acknowledged by the server (as measured by the server), extracted from 2xx response body. Example: 2022-02-28T19:50:00Z

last_ping_tag

string

Number generated by the client using UUID4 when it receives a response with a last_ping. Empty in the first message. If a ping is retried, the same last_ping_tag number should be used; this helps to anonymously distinguish between several ping requests with the same value of last_ping.

previous_last_ping

string

Timestamp of the previous to last ping sent by the client and acknowledged by the server (as measured by the server), copied from the last request. Example: 2022-02-28T19:50:00Z

aa_active

bool

Whether the client opted into Acceptable Ads.

platform

string

Client operating system. Example: Android

platform_version

string

Respective version corresponding to the OS. Example: 10

Update the Solution

Find out what's changed between eyeo Browser Ad-Filtering Solution releases.

Update the Solution

Overview

Module interdiffs are supported from version 115 of the eyeo Browser Ad-Filtering Solution.

Usage

./tools/adblock/generate_interdiffs.sh <eyeo-release-tag> <eyeo-release-tag> <options>

You can get the necessary tags for the revision ranges from release announcements.

Options

The script accepts several options to customize the generation of interdiffs:

--full-sdk: Generates a single diff file that includes changes for the entire eyeo Browser Ad-blocking Solution, including testing and CI (Continuous Integration) files.

--all-modules: Generates individual diff files for each module within the Solution, including base, chrome, webview, android-api, android-settings, and extension-api.

--base: Generates a diff file for changes in the base module.

--chrome: Generates a diff file for changes in the Chrome Integration module.

--webview: Generates a diff file for changes in the Android Webview Integration module.

--android-api: Generates a diff file for changes in the Android API module.

--android-settings: Generates a diff file for changes in the Android UI module.

--extension-api: Generates a diff file for changes in the Extension API module.

Example Usage

Generate an interdiff between two eyeo Browser Ad-Filtering Solution releases with the base, chrome, and android-api modules:

./tools/adblock/generate_interdiffs.sh eyeo-release-111.0.5563.58-6.0-v1 eyeo-release-113.0.5672.76-v1 --base --chrome --android-api

Generate an interdiff for the entire eyeo Browser Ad-Filtering Solution between two specific releases:

./tools/adblock/generate_interdiffs.sh eyeo-release-111.0.5563.58-6.0-v1 eyeo-release-113.0.5672.76-v1 --full-sdk

Understand the snippets library

What are snippets?

Snippets are pieces of JavaScript code, injected by the Ad-Filtering Solution, that execute within the context of a website and combat advanced ads that circumvent ordinary blocking.

How snippets work

A snippet is typically a JavaScript function. It may optionally take arguments.

Snippets are stored in a snippet library and selected for execution based on the content of a filter list. The filter list also specifies any arguments passed to snippets on a given website.

Multiple snippets with various arguments may be executed on a single website. For more on snippet functionality, view the Snippets Overview.

Requirements for using snippets

In order to execute snippets on websites, the following are required:

  • the snippet library of a sufficiently recent version must be built into the browser

Verify the Anti-CV filter subscription

The Anti-CV filter list is subscribed by default.

If it isn't in your configuration, you can subscribe to it the same way as you subscribe to any other filter list, through FilteringConfiguration or any of the platform-specific APIs.

Keeping the snippets library up to date

The snippet library may sometimes be updated separately from the remainder of the Solution by changing the tagged version.

Some changes to the snippets library may require alignment of the Solution. Consult the following compatibility matrix to see if a Solution version is compatible with a snippet library version:

Snippet library version
Required Solution version

0.5.1

105+

0.8.1

117+

1.2.0

123+

Update the snippets library

  1. Run gclient sync to pull the new version of the library to your local repository.

  2. Rebuild the browser (ninja -C out/...)

Remember to consult the compatibility matrix to avoid mismatches between the snippets library content and the Solution's expectations.

eyeo count users who have both ad-filtering and enabled, as well as those who only have ad-filtering enabled. eyeo does this for the following reasons:

You can use eyeo's to generate interdiffs between different releases of the eyeo Browser Ad-Filtering Solution. These interdiffs show the changes made between two specific releases, and the resulting diff files are saved in the eyeo_modules/interdiffs/ directory, which will be created if it doesn't exist. The script leverages git diff functionality to generate the interdiffs.

the must be subscribed

The version of the snippets library built into the Browser Ad-Filtering Solution is defined in the .

Set the new desired version in the .

Acceptable Ads scheme
interdiffs script
Anti-CV filter list
DEPS file
DEPS file

Services and classes

This page lists the services and classes important to the eyeo Browser Ad-Filtering Solution, as well as the role each plays in the Solution's implementation.

Services

The Solution consists of the following main KeyedService services:

  • SubscriptionService; maintains a state of available subscriptions and synchronizes it with persistent storage.

  • ResourceClassificationRunner; decides whether to block or allow network requests.

  • ElementHider; applies element hiding scripts and stylesheets on web pages.

  • AdblockTelemetryService; reports anonymous usage statistics to eyeo.

Important Chromium classes

The following Chromium classes play an important role in the Solution's implementation:

  • WebContentsObserver; receives page load events and injects element hiding; extended by AdblockWebContentsObserver.

  • ChromeContentBrowserClient ; extended by AdblockChromeContentBrowserClient in order to set up an internal proxy for inspecting network requests.

Mapping to Chromium processes and threads

  • Classification of network requests

  • Preparing element hiding selectors

  • Conversion/serialization of filter lists

  • Loading installed filter lists from disk

Testing

Integration testing for the Browser Ad-Filtering Solution.

Controlling ad filtering

Smoke testing

You may use these scenarios for quickly checking if ad-filtering works in your browser.

Scenario 1: Verify ads are blocked when ad filtering is ON and Acceptable Ads are OFF.

Given I have ad filtering enabled and AA disabled on eyeo Browser Ad-Filtering Solution .
When I open "https://www.ask.com"
And search for "laptops"
Then I verify that ads are not displayed

Scenario 2: Verify ads are blocked when ad filtering is ON and Acceptable Ads are ON.

Given I have ad filtering enabled and AA disabled on eyeo Browser Ad-Filtering Solution
When I open "https://www.ask.com"
And search for "laptops"
Then I verify that ads are displayed.

Scenario 3: Verify ads are displayed when ad filtering is OFF.

Given I have ad filtering disabled on eyeo Browser Ad-Filtering Solution
When I open "https://www.ask.com"
And search for "laptops"
Then I verify that ads are displayed.

Scenario 4: Verify allowlisting feature is working properly.

Given I have ad filtering enabled
When I add www.wikihow.com to allowlisted domains and
And open a subpage on www.wikihow.com
Then I verify that ads are displayed

Testing on ABP testpages

ABP testpages are designed to test the ad-filtering code against various types of html elements in a controlled environment.

You need to enable More Blocking Options in order to run these tests.

Scenario 1 : Testing ABP testpages using custom filter lists

  1. On the More blocking options screen, select the option of Custom Filter lists.

  2. Enter the URL https://abptestpages.org/en/abp-testcase-subscription.txt in the text field and tap on the + icon.

  3. Verify that you see green boxes, according to the descriptions of the test cases

Scenario 2 : Testing ABP testpages using custom filters

Alternatively, you can try adding custom filters rather than a custom filter list. This takes more effort but avoids unexpected interplay between filters defined for different test cases.

  1. Copy the filter mentioned on the testpage corresponding to the scenario under test.

  2. On the More blocking options screen, select the option of Custom Filters.

  3. Paste the filter to the custom filter field and refresh the page under test.

  4. Verify the test state matches the test case description, typically by showing a green box.

Filter lists

The eyeo Browser Ad-Filtering Solution needs filter lists in order to filter ads. Filter lists define which web resources should be blocked or hidden.

Default filter lists

On first run, the browser will attempt to download and install the following default filter lists:

It will take a couple of seconds to download and install these lists. The user is free to browse the web while this is happening, and the Solution falls back to built-in, preloaded variants of the default lists to provide some level of ad-filtering.

Downloading a filter list

The Solution downloads filter lists when:

  • The browser starts for the first time and the default lists are installed

  • The user selects a new list in the Language Filters menu

  • The user adds a new custom filter list in the More Blocking Options menu

  • A filter list expires and needs to be updated

Every filter list download is a GET request to the URL of the filter list with a set of extra GET parameters.

GET parameters

The Solution reports some information to eyeo via GET parameters added to the URL of each filter list.

This information is designed to preserve the user's anonymity and is used to:

  • Count how many active users your browser attributes to the Acceptable Ads program

  • Collect insights about what platforms eyeo should focus development efforts on

Parameter
Value

addonName

eyeo-chromium-sdk

addonVersion

1.0

application

The name of for your product.

applicationVersion

Follows Chromium's versioning by default, but can be overridden to reflect your product's version.

platform

Windows, MacOSX, Linux or Android, depending on the operating system.

platformVersion

1.0

lastVersion

Version of the filter list that is being updated, for example 202111101251. Version is normally parsed from the filter list's "! Version: 202111101251" header comment. 0 if it's a new download or when a filter list doesn't declare a version.

disabled

true when Acceptable Ads is disabled in settings, false if it's enabled.

downloadCount

Total number of successful update downloads of the subscription. For anonymity reasons, clamped between 0 and 4+.

An example:

https://easylist-downloads.adblockplus.org/exceptionrules.txt?addonName=eyeo-chromium-sdk&addonVersion=1.0&application=Chromium&applicationVersion=110.0.5476.3&platform=Linux&platformVersion=1.0&lastVersion=202301021041&disabled=false&downloadCount=3

Periodic pings of Acceptable Ads filter list

To not lose track of users that have disabled Acceptable Ads, the SDK performs periodic pings .

A ping is a HEAD-type filter list download request, very similar to ordinary filter list download requests. Because it's a HEAD (and not GET) request, the server will not respond with filter list content and the browser will not download Acceptable Ads. However the server will be made aware of the user's existence.

Pings are sent every 24 hours while Acceptable Ads is disabled. They are visible as HEAD requests to:

https://easylist-downloads.adblockplus.org/exceptionrules.txt?addonName=eyeo-chromium-sdk&...&disabled=true

Periodic updates

The browser updates the filter lists according to their expiry times - typically every 24 hours. In order to check if filter lists are updated upon expiration, do the following:

  1. Let all the default filter lists download successfully.

  2. On Android, force stop the application

  3. Navigate to phone settings to advance the time by 25 hours.

  4. Launch the application.

  5. Filter lists download requests should be sent to the server with an increased downloadCount in request parameter.

  6. If you have enabled VLOGs, you should see relevant logs in the system console, for example:

... [eyeo] Running update check
... [eyeo] Updating expired subscription https://easylist-downloads.adblockplus.org/abp-filters-anti-cv.txt
... [eyeo] Downloading https://easylist-downloads.adblockplus.org/abp-filters-anti-cv.txt?addonName=eyeo-chromium-sdk&...&downloadCount=4+
... [eyeo] Finished downloading https://easylist-downloads.adblockplus.org/abp-filters-anti-cv.txt, starting conversion
... [eyeo] Finished converting https://easylist-downloads.adblockplus.org/abp-filters-anti-cv.txt successfully
... [eyeo] Updated subscription https://easylist-downloads.adblockplus.org/abp-filters-anti-cv.txt, current version 202301121221

Verifying Eyeometery

To learn about Eyeometry refer to: user counting

  1. The browser sends an Eyeometry ping every 12 hours. You should see it in browser logs if you have enabled VLOGs

... [eyeo] Telemetry request for https://eyeo-chromium.telemetry.eyeo.com/topic/eyeochromium_activeping/version/1 is due
... [eyeo] Telemetry request for https://eyeo-chromium.telemetry.eyeo.com/topic/eyeochromium_activeping/version/1 starting now
... [eyeo] Sending request to: https://eyeo-chromium.telemetry.eyeo.com/topic/eyeochromium_activeping/version/1
... [eyeo] Telemetry ping succeeded
  1. If you see this line in the logs, your product wasn't built with a valid client id

[eyeo] Using default Telemetry server since a Telemetry client ID was not provided. Users will not be counted correctly by eyeo. Please set an ID via "eyeo_telemetry_client_id" gn argument.`
  1. If you see this line in the logs, your product wasn't built with a valid auth token

[eyeo] No Telemetry authentication token defined. Users will not be counted correctly by eyeo. Please set a token via "eyeo_telemetry_activeping_auth_token" gn argument.

Logging

eyeo Chromium SDK uses the following levels of logging:

  1. LOG(INFO/WARNING/ERROR) - these logs appear in all builds. These are emitted relatively rarely, to avoid clutter.

  2. DLOG(INFO/WARNING/ERROR) - these logs appear in debug build only

  3. VLOG(1/2/3/...) - these logs appear in all builds if vmodule flag is set

  4. DVLOG(1/2/3/...) - same as VLOG but only in debug builds

The browser writes these logs to the system console, also known as standard output. Do not confuse this with the Developer Tools console within the Inspector window.

Steps to enable VLOG/DVLOG

  1. Ensure Enable command line on non-rooted devices in chrome://flags is enabled

  2. Run the following command:

adb shell 'echo _ --enable-logging=stderr --vmodule="*subscription*=1,*activeping*=1,*adblock*=1,*converter*=1,*filtering_configuration*=1" > /data/local/tmp/chrome-command-line'

Note: the flag persists until it is cleared

  1. Launch the app now, manually, by tapping the icon on phone

  2. Run adb logcat to view logs

Note: To check the currently set command line flags, run the command:

adb shell 'cat /data/local/tmp/chrome-command-line'

To clear the currently set flags:

adb shell 'rm /data/local/tmp/chrome-command-line'

Run the browser executable with following arguments: --enable-logging=stderr --vmodule="*subscription*=1,*activeping*=1,*adblock*=1,*converter*=1,*filtering_configuration*=1

FilteringConfiguration; allows the

SitekeyStorage; extracts, validates, and stores from response headers.

RenderFrameHost; allows finding the and executes element hiding CSS and JavaScript.

The Solution's logic executes primarily in the . The only exception is code under third_party/blink/renderer/core/exported/web_document.cc that injects element hiding stylesheets into the website - this runs in a Renderer process.

In the Browser process, code that might take a long time to execute runs asynchronously in the . Examples of such code:

You may use the to control ad filtering settings.

Navigate to .

Navigate to and click on the page you wish to test. For example: https://abptestpages.org/en/filters/blocking

,

(assuming Acceptable Ads is enabled by default),

The Solution attempts to select a language-specific variant of Easylist, for example if the device's language is Spanish. Not all languages have such variants.

See also

control of resource filtering settings
SiteKeys
frame hierarchy
Browser process
ThreadPool
example UI
Blocking - ABP Test Pages
ABP Test Pages
Easylist
Acceptable Ads
Anti-Circumvention
Easylist+spanish
Chromium's instructions on logging

Behavioral Snippets

Sitekey

A sitekey is a special identifier that a server may attach to a resource. Sitekeys enable additional filters that determine whether to block or allow the resource.

Sitekeys are typically used to allowlist resources coming from a particular server that may serve many different domains.

How sitekeys work

The network responses headers for both sites will contain x-adblock-key. The sitekey is encoded within that header.

How sitekeys get computed on the server side

The sitekey server gets the following information:

  • The path with query of the URL requested by the client, for example, /page.html?param-value

  • The host that the client contacted, for example, catstoys.com

These three strings are connected into a single line of text, separated by null (\0) symbols, as in the following example:

/page.html?param-value\0catstoys.com\0Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36

This becomes the input to the encryption algorithm. This input is different for every URL that the browser requests.

The sitekey server holds a secret private key that is only generated once and never changes. Using this private key, the sitekey server encrypts the input text and generates a unique signature, or a hash. The hash would look something like this:

nLH8Vbc1rzmy0Q+Xg+bvm43IEO42h8rq5D9C0WCn/Y3ykgAoV4npzm7eMlqBSwZBLA/0DuuVsfTJT9MOVaurcA==

The sitekey server then returns the following:

  • The signature, that is, is the encrypted output. This signature changes for every request.

  • A sitekey, which is the public key to the server's internal, secret private key. The public key never changes.

The sitekey and signature are glued together with the underscore (_) as the separator, as in sitekey_signature. In the example scenario, the string would look like this:

MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANnylWw2vLY4hUn9w06zQKbhKBfvjFUCsdFlb6TdQhxb9RXWXuI4t31c+o8fYOv/s8q1LGPga3DE1L/tHU4LENMCAwEAAQ_nLH8Vbc1rzmy0Q+Xg+bvm43IEO42h8rq5D9C0WCn/Y3ykgAoV4npzm7eMlqBSwZBLA/0DuuVsfTJT9MOVaurcA=

The sitekey server then sends this string back to the browser in the x-adblock-keyheader.

The following diagram illustrates the process in its entirety:

Sitekey on the browser side

When the browser receives an HTTP response whose header contains x-adblock-key, it splits the string back into a separate sitekey and signature.

Because the browser knows the signature's three parameters (host, URL, UserAgent) and it has the public key, it can verify that the sender has the private key that corresponds to the sitekey that the browser received. In other words, the browser now knows that the server is a legitimate provider of the MFwwDQYJKoZIhvcNAQ... sitekey. This is because the server successfully encrypted inputs given by the browser in a way that's verifiable with that sitekey.

Applicable sitekey filter
@@$document,sitekey=MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANnylWw2vLY4hUn9w06zQKbhKBfvjFUCsdFlb6TdQhxb9RXWXuI4t31c+o8fYOv/s8q1LGPga3DE1L/tHU4LENMCAwEAAQ

The following diagram illustrates the browser-side sitekey process:

Other resources

ADRs

Learn about the thinking behind the eyeo Browser Ad-Filtering Solution.

This page contains the eyeo Browser Ad-Filtering Solution architectural decision records (ADRs), which summarize the most important software design choices made during the development of the Solution.

These decisions address functional and non-functional requirements that eyeo finds architecturally significant.

Implementing ad-filtering from scratch

Patching these limitations requires significant tradeoffs, some of which include the following:

  • More conflicts to solve after Chromium updates

  • Less flexibility to introduce new features and optimizations

  • Irreconcilably different objectives between eyeo and Chrome's authors

For these reasons, the eyeo team chose not to build on top of the subresource filter, opting for an implementation with ad-filtering capabilities built from scratch.

Using full or minified filter lists

In previous implementations of our ad-filtering core, eyeo used minified filter lists to reduce memory consumption for mobile users. More recent implementations achieved this reduction by adopting FlatButters as a filter list file format and by moving from V8 to a native implementation.

Storing filter lists in FlatBuffer format

Filter lists aren't consumed in plain text format right after download. Instead, they are converted from plain text into the FlatBuffers format, which offers the following advantages:

  • Reduced memory consumption, down to approximately 15 MB

  • Reduced startup time, from seconds down to milliseconds

  • No negative impact on page load time, except for sites with long URLs

  • Facilities for multi-threading and synchronous popup blocking

  • No required deserialization, because FlatBuffers is already in a binary format

  • FlatBuffers can be memory-mapped and accessed as memory directly from disk.

  • Accessing data in a flatbuffer is as fast as dereferencing pointers to memory.

A FlatBuffers file contains only one filter list, for the following reasons:

  • Filter lists updated at different times can be downloaded independently.

  • Less time consumed in conversion than if all selected filter lists are combined in one file

  • For long-term distribution of FlatBuffers files, having to provide a file containing all selected filter lists would cause excessive combinations.

Moving user counting to a dedicated service

Coupling the user counting service with filter lists downloads gives eyeo insight into Solution usage across Chromium, OS, and platform versions.

As a dedicated service, it also allows eyeo to monitor Acceptable Ads opt-out rate, while enabling partners to serve and monetize filter lists from their own servers.

Snippets Overview

An introduction to snippets.

On this page, you’ll learn what snippets are, why they’re useful, and ways you can include them in your development workflow.

Snippet basics

A snippet is a small piece of code intended to solve one problem:

eyeo uses snippets to fight ad-filtering circumvention. The following is the first snippet ever written for Adblock Plus:

This snippet prints its arguments to the developer tools console for the tab on which it’s executed.

The eyeo snippets library contains dozens of snippets to hide elements, find text, or block malicious code. Each snippet is exposed to the SDK that integrates thew snippets library. As a result, you can use filters to execute snippets for a given page.

Snippet filter structure

A snippet filter contains several parts:

  • a domain

  • the snippet marker

  • a function name

  • parameters

Consider the following example, which prints Hello, world! to the console:

In this snippet, example.com is the domain, #$# is the snippet market, and log is the function. The snippet takes two parameters, Hello and , world, both separated by white space.

How snippets work

The way a snippet works depends on if the snippet is injected or isolated.

Injected and isolated snippets

  • Injected JavaScript snippets are inserted into a page and interrupt, modify, terminate, or otherwise change the behavior of other JavaScript functions

  • An isolated snippet, on the other hand, has access to, reads, and manipulates the DOM.

Injected snippets are executed as inline scripts, whereas isolated snippets are executed as content scripts. For example, an injected snippet could interrupt the loading of JSON data that contains information about what ads should be shown.

Understanding the difference between injected and isolated scripts especially matters if you work in an isolated environment. For example, in browser extensions, all DOM-related operations can run more securely in a sandboxed extension context where they cannot be accessed by the page itself.

The following table compares injected and isolated snippets:

Types of snippets

In addition to classifying snippets by their functionality, you can also categorize snippets into the following types:

  • Behavioral Snippets, which change a page’s normal execution behavior

  • Conditional Hiding Snippets, which are responsible for hiding page content based on conditions like matching text, style, image hash

  • Debugging Snippets, which you can use in debugging tasks

  • Performance snippets, which reduce the performance overhead caused by other snippets

Working with snippets

When you use a snippet, you can efficiently interfere with ad display code and locate elements you want to hide in ways CSS or advanced selectors don't allow.

Snippets help you solve problems by working directly with the JavaScript environment, giving you a better ad-filtering solution and your users a better experience.

Invoking snippets

Invoking a snippet requires two steps:

  1. Write a snippet filter.

You can test the snippet filter on Adblock Plus or Adblock by adding the filter to the My filter list field on the extension's settings page.

Combining snippets on a single website

Like Unix commands, multiple snippets may be combined in a filter to achieve a certain outcome.

The following filter, for example, blocks any inline script containing the string tracker while enabling all style sheets in the document:

The small and targeted approach

Snippets need to be as efficient and fast as possible. When you add a snippet to a website, in particular, you only want to inject what's strictly necessary to suppress ads.

Injected scripts race against others already embedded in a site. As a result, you should aim for an unchanged user experience in terms of performance. Choosing a small, targeted snippets lets you maximize performance.

Where you can use snippets

eyeo supports snippets on the following platforms:

  • Web Extensions on Manifest V2 (WebRequest and Background Pages)

  • Web Extensions on Manifest V3 (Declarative NetRequest and Service Workers)

  • Chromium based browsers (on Desktop and Android)

  • Apple WebKit (on iOS, but potentially also on Mac OS)

FAQs

Are snippets designed for specific websites?

No. Snippets are generalized and reusable.

Do snippets work with Manifest V3?

Yes.

Can snippets take any type of arguments?

Are snippets injected into frames?

They should be, especially if you're using an eyeo SDK.

Whether or not a snippet is injected into a web document has nothing to do with whether the document is loaded into the top-level frame or lower-level frames. Injection depends only on the domain of the document.

Do snippets share any data?

Snippets run through the extension and share the same environment as each page that uses snippets. They share nothing, though, with other snippets injected in the browser.

Injected snippets share the same private scope. As a result, it's possible to declare and reuse variables and helpers that each snippet can access, whether in the browser or extension.

Where can I find the eyeo snippets library?

Other resources

Suppose a user visits two sites: and . A single sitekey server handles both sites.

The client's , like Mozilla/5.0 (X11; Linux x86_64), Chrome/92.0.4515.107 Safari/537.36, and so on.

The recipient of a public key cannot perform the encryption; that requires the private key. However, the recipient may verify whether an encryption was made using the private key paired with the public key. This is the basis of .

As a result, in the example, filter list allowing can now be applied on :

The filter used in the example on this page allows all resources to load and disables element hiding on any page with the specified sitekey. For more on filter language, see .

Chromium contains some ad-filtering functionality in the form of the . The Chromium subresource filter, however, doesn't support CSS element-hiding, JavaScript element hiding emulation, or snippets.

Chromium authors control subresource filter development. As a result, they may have different (ad-related) business objectives that could take subresource filtering in a direction that doesn't fit with .

eyeo now uses full filter lists, which allow for more filter rules. This improves user experience and blocks a greater number of intrusive ads. More Acceptable Ads are also allowed, which increases for publishers who adhere to the .

For more information, view the .

Behavior
Injected
Isolated

Refer to , , and for a comprehensive snippets list.

Deploy the filter to the .

Not all snippets are supported on all platforms. Refer to for a comprehensive table of supported snippets.

From an interface perspective, any argument to a snippet always is picked as a .

A snippet may interpret a string in any way, though. For example, some snippets interpret arguments surrounded by forward slashes (/) as .

One exception to this is frames, which have a unique origin by design.

eyeo release the eyeo snippets library as a public named @eyeo/snippets. You can reach the homepage from the .

https://catstoys.com
https://dogstoys.com
user agent
public-key cryptography
https://catstoys.com
How to write filters
function greetings() {
print("Hello there!");
}
function log(...args)
{
  console.log(...args);
}
example.com#$#log Hello ', world' 

Execution

Inline

Content Script (include links)

DOM interaction

Can modify the DOM but have no access to it

Have access to their own copy of DOM APIs

example.com#$#abort-on-property-read Object.prototype.loadImage; hide-if-contains-visible-text 'Sponsored'; prevent-listener beforeunload ();
Behavioral Snippets
Conditional Hiding Snippets
Performance Snippets
subresource filter
eyeo's vision
Acceptable Ads standard
user counting documentation
ABP anti-circumvention filter list
Snippets Support by Platform
string
regular expressions
data URI
npm module
eyeo GitLab snippets repository
Snippet Filters Tutorial

Create a filter list

Creating a filter list

Anatomy of a filter list

A filter list is a text file that contains, in this order:

  • A collection of optional special comments, one per line

  • A collection of filters or normal comments, one per line

The header line

The header line must be the first line of the file.

It should say [Adblock Plus]. It might also contain a version number, for example [Adblock Plus 2.0], but the version is ignored by the eyeo Browser Ad-Filtering Solution.

Special comments

Special comments are a single block of consecutive comments that start from an exclamation mark (!) and follow a key:value semantic.

The Browser Ad-Filtering Solution interprets the following special comments:

Key
Value
Meaning
Example

Redirect

URL

Instead of parsing this filter list, download a filter list from the provided URL. Useful when the list location has changed and an http redirect cannot be implemented.

! Redirect: https://new-location.com/list.txt

Title

String

Human-readable title of the filter list. Returned by:

  • C++: Subscription::GetTitle()

  • Java: Subscription::title()

  • JavaScript: Subscription.title

! Title: My filters

Version

String

An arbitrary string that describes the current version of the list. Returned by:

  • C++: Subscription::GetCurrentVersion()

  • Java: Subscription::version()

  • JavaScript: Subscription.current_version

! Version: 202305310750 ! Version: 5.0.4

Expires

Number, optionally followed by text

How frequently should the Solution download updates. In number of days, unless followed by a text starting from h, then in number of hours. Following text is ignored.

! Expires: 1 days (update frequency) ! Expires: 1 hours ! Expires: 7 (weekly)

There are other special comments that may be interpreted by other eyeo Ad-Filtering Solution, for example:

  • Homepage

  • License

  • Checksum

Parsing of the special comments block stops after encountering a line that isn't a ! key : value. All further comments are treated as not special and ignored.

Filters and normal comments

This is probably the most important block of a filter list - the actual filters.

Comment lines start from an exclamation mark (!) and are skipped during parsing.

The filters are parsed until the end of file.

Examples

[Adblock Plus]
! Version: 202306020710
! Title: My list
! Expires: 2 days

! Allow loading all resources on mysite.net
@@||mysite.net^$document,domain=mysite.net

! Unhide banner element on example.com
example.com#@#.banner

For a big working example, consider https://easylist-downloads.adblockplus.org/easylist.txt

For a more minimal example, compare the filter list used for test pages: https://abptestpages.org/en/abp-testcase-subscription.txt

Hosting

For safety, the Browser Ad-Filtering Solution will only download filter lists from HTTPS servers, HTTP is not allowed.

An exception is localhost - the Solution will download a filter list from http://localhost/any/path.txt to facilitate local development and testing.

Updating

The eyeo Browser Ad-Filtering Solution will periodically download filter list updates. It will respect the interval specified in ! Expires or revert to the default period of 5 days.

The update check interval is clamped between 1 hour and 14 days.

If a new version of the filter list fails to download or parse correctly, the SDK will retain the old version and retry the update in an hour.

Limitations

An [Adblock Plus] header line, to identify itself as following the

You can write one filter rule per line, as described in .

and header filters will be ignored. They are only allowed on .

You can still add snippet and header filters as individual custom filters, as explained .

Adblock Plus syntax
Adblock Plus syntax
Snippet filters
ABP Filters
Modules dependency diagram

Frame hierarchy

Frame hierarchy is a term coined by eyeo. It represents a list of URLs where each element is embedded by the next one.

As an example, consider:

  • A website's main page is https://example.com

  • This website embeds an <iframe> with src = https://iframe.com/content.html

  • This iframe contains an ad - an image with src = https://ads.com/ad.png

In this example, the image https://ads.com/ad.png has a frame hierarchy of:

  • https://iframe.com/content.html

  • https://example.com

By convention, the first element on the frame hierarchy is the immediate parent frame of the resource.

Purpose

The Browser Ad-Filtering Solution uses the frame hierarchy to establish whether allowing filters exist for parents of a resource.

Consider a blocking filter: ||ads.com/ad.png

This filter matches the URL of the ad image. When a website loads, a resource classifier will mark the image as an ad and stop the request from leaving the browser.

Now consider an allowing filter: @@||example.com^$document

This filter allows everything on the example.com domain, it overrides any blocking filters.

If both filters are present, the resource classifier should allow the ad from this particular frame hierarchy to load. But the same ad loaded from a different frame hierarchy might still be blocked.

The resource classifier searches not only for blocking and allowing filters that match https://ads.com/ad.png, but also for $document-type allowing filters that match https://iframe.com/content.html and https://example.com.

This is critical for correctly implementing the Acceptable Ads allowlists.

Implementation

The frame hierarchy can be assembled by recursively following content::RenderFrameHost::GetParent() results.

Features

All about the eyeo Browser Ad-Filtering Solution.

Integrating the eyeo Browser Ad-Filtering Solution provides a browsing experience that benefits users. On this page, you'll learn about the solution's main features and services.

About the eyeo Browser Ad-Filtering Solution

Advertisements frustrate users, as they take up valuable screen space and can slow page load time. By integrating a proven, widely used ad-filtering solution directly into the browser, your users will no longer need to install and configure ad-filtering extensions manually.

With the eyeo Browser Ad-Filtering Solution, ad filtering is automatically enabled, giving users an immediate improvement in browsing speed and aesthetics.

The eyeo Browser Ad-Filtering Solution enables partners with Chromium-based browsers to introduce ad filtering and related features to their browsers across multiple platforms. As a result, Chromium-enforced limitations on desktop extensions (like Manifest V3) no longer apply.

Features

The feature-rich solution works alongside other services offered to all partners. In this section, you'll learn about the benefits and capabilities of integrating an ad-filtering solution into a browser.

Basic ad filtering

Ad filtering is the core feature of the solution, which uses two approaches to remove ads:

  • Network blocking, which blocks ads from being requested and downloaded. This approach saves data and helps web pages loader faster.

  • Element hiding, which hides ads. Element hiding also hides white spaces left from hidden ads, improving the user experience even after removing ads.

Partners can access an API to introduce an on/off switch for ad filtering features in the UI.

Anti-circumvention and snippets

An advanced feature of the solution, anti-circumvention, depends on JavaScript snippets that execute within the context of a website to stop publishers from circumventing ad blockers.

Snippets are built into the browser as a library, rather then being downloaded from the Internet, to avoid running untrusted code. Partners can update the snippets library on their own as part of their release pipeline. Snippets are enabled by default but can be disabled if needed.

For more on snippets, view Snippets Overview.

Acceptable Ads

Keep the following in mind when configuring Acceptable Ads for your project:

  • This feature is powered by exception rules, a proprietary eyeo filter list. eyeo recommends all partners enable this filter list by default.

  • Inform users about Acceptable Ads during onboarding so that they can opt out if they wish.

  • Make sure that Acceptable Ads has a dedicated on/off switch in the browser settings.

To turn this feature off, you'll need to disable (that is, unsubscribe from) the exception rules filter list through the Subscription API.

Filter lists

Filter lists power ad filtering. The Browser Ad-filtering Solution downloads the following filter lists by default:

  • Language-specific versions of EasyList:

    • During the first run a list is automatically selected and downloaded based on the user's device language.

    • Later "temporary" lists are downloaded based on geolocation and will be deleted if the geolocation has changed and the list remains unrecommended for a period of 14 days.

  • A proprietary list to enable Acceptable Ads.

  • Anti-circumvention list to stop publishers from circumventing ad blockers.

Adding and removing filter lists

Using the Subscription API, browser partners can add and remove custom filter lists during browser runtime. You can also expose this option to your end users.

Automatic filter list updates

The Browser Ad-Filtering Solution updates all installed filter lists automatically, according to their expiration time.

Reporting ad filtering statistics

With this feature enabled, you can count how many ad requests were blocked or allowed. The Browser Ad-Filtering Solution sends a notification for each blocked request, which the browser can then count and display to users in their UI.

Depending on your project, you can also use a global counter to engage users who reach a specific milestone of blocked ads.

Privacy-preserving user counting

User counting helps browser partners and eyeo count the following:

  • How many users are using the eyeo Browser Ad-Filtering Solution

  • How many users support content creators via the Acceptable Ads program

eyeo counts users in a way that preserves privacy. The Solution sends regular, anonymous ping requests to eyeo servers. These requests let eyeo apply formulas and identify unique, active users without knowing any personal information about the user.

Adding and removing domains to and from allowlists

Browser partners can add or remove domains to and from a local allowlist during runtime.

With this feature, your end users can disable ad filtering for specific websites. This lets users support certain websites, or turn ad filtering off for websites with ad blocker walls or websites that break when ads are blocked.

By providing this feature to users, you give them the option to keep ad filtering enabled for all other websites, resulting in a low opt-out rate for ad filtering.

You can also let some users manage their local allowlist. Adding and removing domains to the local allowlist is done through the custom allowlist API.

Adding and removing custom filters to and from local block lists

eyeo recommends to reserve this capability for power users or developers.

Multi-platform support

Partners only need to integrate the ad-filtering solution into their Chromium codebase once. The Solution supports the following platforms:

  • Windows

  • MacOS

  • Linux

  • Android

In addition to platform dimension, the following targets are supported:

  • Chromium app

  • WebView (Android system component to display HTML)

  • Monochrome (combined app and WebView)

  • Content Shell (minimal browser code base, can be used for Smart TV platforms)

Example UI

Next up

Now that you're familiar with the features of the eyeo Browser Ad-Filtering Solution, jump right in and follow the Quickstart guide to begin building.

See:

gives users the option to support content creators and contribute to a fair online ecosystem. Users who enable Acceptable Ads see non-intrusive advertising that respects the online user experience. In so doing, they help reward content creators for their free content.

, the standard for filtering ad content online, is the default filter list enabled in the ad filtering solution.

For more information, view .

Browser partners can add an expiration value to their filter lists by in the filter list content.

For more information, view .

For more information, view .

Partners or users can add and remove individual filters that follow the .

can help you implement a user interface to control ad filtering.

FrameHierarchyBuilder
Acceptable Ads
EasyList
setting special headers
user counting
Adblock Plus syntax
Examples
adding and removing filter lists
receiving notifications about blocked or allowed network requests

abort-on-property-read

The abort-on-property-read snippet patches a property on the window object that aborts execution when the property is read. No error gets printed to the console.

You can use this snippet to abort the execution of inline scripts.

Only use this snippet for read properties. Place it just inside the script you want to abort, otherwise, an error will be thrown.

Parameters

Name
Description
Mandatory

property

The name of the property or path to the property. If the property is a direct child of window, this parameter will be the property name. If you want to access a sub property, though, this parameter becomes a chain of properties separated by dots.

Yes

setConfigurable

Value of the configurable attribute of the descriptor of property. If this parameter is not used it defaults to true. Setting it to false will prevent the property set and get being overwritten or otherwise changed by anybody. If this snippet doesn't work as expected when passing only the property, it could mean that the website is circumventing and setting this parameter to false can come in handy.

No

Filter examples

The following table lists examples that use the abort-on-property-read snippet:

Filter
Result

abort-on-property-read atob

The code that reads/calls the atob global function throws an exception.

abort-on-property-read adHandler.cmd.push

The code that reads/calls the push function throws an exception. This function is a property of cmd, which is a property of the adHandler global object.

abort-on-property-read Object.prototype.adfoxCode

The code that reads/calls the adfoxCode property throws an exception.

This example shows that you can attach the filter to prototype properties as well.

Debugging

The following table contains error messages you'll find useful during debugging:

Message
When the error occurs
Definition

no property to abort on read

At the beginning of snippet execution

No property parameter was passed to the snippet.

<property> access aborted

Each time the property is read, right before throwing the error

The error is about to be thrown.

aborting on <property> access

Right before attaching to the property

This log is printed just before the snippet takes over the property getter OR setter.

Tradeoffs

Keep the following tradeoffs in mind when you use the abort-on-property-readsnippet:

  • The snippet is executed after all a page's inline scripts. As a result, you should only attach properties read inside of a callback, which can be executed after the script.

  • You can only attach this snippet to global properties, or properties of the window object.

abort-on-iframe-property-read

The abort-on-iframe-property-read snippet patches a list of properties on the iframe's window object that aborts execution when the property is read.

You can use this snippet to prevent CV providers from using iframe native functions.

Parameters

Name
Description
Mandatory

properties

The list with the targeted properties to abort.

Yes

Filter examples

The following table lists examples that use the abort-on-iframe-property-read snippet:

Filter
Result

abort-on-iframe-property-read atob

The code that reads/calls the atob function inside an iframe throws an exception.

abort-on-iframe-property-read atob btoa

The code that reads/calls the atob or btoa function inside an iframe throws an exception.

abort-on-iframe-property-read adHandler.cmd.push

The code that reads/calls the push function throws an exception. This function is a property of cmd, which is a property of the adHandler global object.

abort-on-iframe-property-read Element.prototype.attachShadow

The code that reads/calls the attachShadow property throws an exception. This example shows that you can attach the filter to prototype iframe properties as well.

Debugging

The following table contains messages you'll find useful during debugging:

Message
When the error occurs
Definition

no property to abort on read

At the beginning of snippet execution

No property parameter was passed to the snippet.

<property> access aborted

Each time the property is set, right before throwing the error

The error is about to be thrown.

aborting on <property> access

Right before attaching to the property

This log is printed just before the snippet takes over the property getter OR setter.

abort-on-property-write

The abort-on-property-write snippet patches a property on the window object that aborts execution when the property is written or set. No error gets printed to the console.

You can use this snippet to abort the execution of inline scripts.

Only use this snippet for written properties. Place it just inside the script you want to abort, otherwise, an error will be thrown.

Parameters

Name
Description
Mandatory

property

The name of the property or path to the property. If the property is a direct child of window, this parameter will be the property name. If you want to access a sub property, though, this parameter becomes a chain of properties separated by dots.

yes

setConfigurable

Value of the configurable attribute of the descriptor of property. If this parameter is not used it defaults to true. Setting it to false will prevent the property set and get being overwritten or otherwise changed by anybody. If this snippet doesn't work as expected when passing only the property, it could mean that the website is circumventing and setting this parameter to false can come in handy.

No

Filter examples

The following table lists examples that use the abort-on-property-write snippet:

Filter
Result

abort-on-property-write hasAdvert

The code that sets the hasAdvert global property throws an exception.

abort-on-property-write adHandler.cmd.push

The code that sets the push function throws an exception. This function is a property of cmd, which is a property of the adHandler global object.

abort-on-property-write Object.prototype.AdblockCookieMatchingType

The code that sets the AdblockCookieMatchingType property throws an exception.

This example shows that you can attach the filter to prototype properties as well.

Debugging

The following table contains messages you'll find useful during debugging:

Message
When the error occurs
Definition

no property to abort on write

At the beginning of snippet execution

No property parameter was passed to the snippet.

setting <property> aborted

Each time the property is set, right before throwing the error

The error is about to be thrown.

aborting when setting <property>

Right before attaching to the property

This log is printed just before the snippet takes over the property getter OR setter.

Tradeoffs

Keep the following tradeoffs in mind when you use the abort-on-property-writefilter:

  • The snippet is executed after all of a page's inline scripts. As a result, you should only attach properties read inside of a callback, which can be executed after the script.

  • You can only attach this snippet to global properties, or properties of the window object.

  • You should only attach to properties set just inside the script you want to abort. Otherwise, an error will be thrown.

abort-on-iframe-property-write

The abort-on-iframe-property-write snippet patches a list of properties on the iframe's window object that aborts execution when the property is written.

You can use this snippet to prevent CV providers from overwriting properties inside an iframe.

Parameters

Name
Description
Mandatory

properties

The list with the targeted properties to abort.

Yes

Filter examples

The following table lists examples that use the abort-on-iframe-property-write snippet:

Filter
Result

abort-on-iframe-property-write atob

The code that sets the atob function inside an iframe throws an exception.

abort-on-iframe-property-write atob btoa

The code that sets the atob or btoa function inside an iframe throws an exception.

abort-on-iframe-property-write adHandler.cmd.push

The code that sets the push function throws an exception. This function is a property of cmd, which is a property of the adHandler global object.

abort-on-iframe-property-write Object.prototype.adfoxCode

The code that sets the adfoxCode property throws an exception. This example shows that you can attach the filter to prototype iframe properties as well.

Debugging

The following table contains messages you'll find useful during debugging:

Message
When the error occurs
Definition

no property to abort on write

At the beginning of snippet execution

No property parameter was passed to the snippet.

setting <property> aborted

Each time the property is set, right before throwing the error

The error is about to be thrown.

aborting when setting <property>

Right before attaching to the property

This log is printed just before the snippet takes over the property getter OR setter.

here

Run separate instances of the filtering engine

Using multiple filtering configurations.

The filtering engine is flexible

It could, for example:

  • block intrusive trackers,

  • block age-sensitive material,

  • filter geo-limited content,

  • remove arbitrary unwanted content from the user's browsing experience

This section describes how to introduce new aspects of content filtering independently of ad-filtering.

Filtering configuration

A filtering configuration is a named, independent set of filtering options that are applied to network requests and website content.

Each filtering configuration has the following parameters:

Parameter
Description

Name

Unique name of this configuration

Enabled

Whether this entire configuration is currently enabled and active

Filter lists

List of currently selected filter lists, typically identified by URLs

Allowed domains

List of domains exempt from filtering

Custom filters

List of individual filters installed in addition to those from filter lists

The default, ad-filtering configuration

Multiple filtering configurations

Filtering configurations are independent, meaning each can be enabled, disabled or reconfigured separately from the others. Each maintains its own list of installed filter lists, custom filters and allowed domains.

Interactions between filtering configurations

What happens when one filtering configuration classifies a resource as blocked while another classifies it as allowed?

The blocking decision always wins.

This is a design decision. An example to rationalize it:

  • Perhaps filtering configuration adblock is an ad-filtering configuration and has a blanket rule to block every URL with an ad substring.

  • However, the user has allowlisted example.com by adding it to adblock's allowed domains, therefore filtering configuration adblock classifies https://example.com/ad.png as an allowed resource.

  • Filtering configuration sfw is an age-restricting configuration and it has a blocking filter for https://example.com/ad.png - not because it's an ad, but because it contains inappropriate content.

  • The blocking decision from filtering configuration sfw "wins", the inappropriate ad is blocked.

Creating a filtering configuration

Each filtering configuration must be installed on each browser start.

The configuration's settings are persistent and will be loaded upon installation.

import org.chromium.components.adblock.FilteringConfiguration;

// Creates "adblock" configuration if does not exist yet, returns a valid handle.
FilteringConfiguration myConfiguration = FilteringConfiguration.createConfiguration("my_configuration", browserContextHandle);
// No-op if configuration already exists.
chrome.eyeoFilteringPrivate.createConfiguration("my_configuration")
#include "chrome/browser/adblock/subscription_service_factory.h"
#include "components/adblock/core/configuration/persistent_filtering_configuration.h"
#include "components/adblock/core/subscription/subscription_service.h"

auto my_configuration =
    std::make_unique<PersistentFilteringConfiguration>(profile()->GetPrefs(),
                                                       "my_configuration");
SubscriptionServiceFactory::GetForBrowserContext(profile())
    ->InstallFilteringConfiguration(std::move(configuration));

Getting installed filtering configurations

List<FilteringConfiguration> configs = FilteringConfiguration.getConfigurations();
// Without promises:
chrome.eyeoFilteringPrivate.getConfigurations(function(configs) {
  // configs = ['adblock', 'my_configuration']
  // 'adblock' installed by default.
  // 'my_configuration' installed by previous example.
});

// With promises:
await chrome.eyeoFilteringPrivate.getConfigurations().then(
    configs => {
        // configs = ['adblock', 'my_configuration']
    });
#include "chrome/browser/adblock/subscription_service_factory.h"
#include "components/adblock/core/configuration/filtering_configuration.h"
#include "components/adblock/core/subscription/subscription_service.h"

SubscriptionService* subscription_service =
    SubscriptionServiceFactory::GetForBrowserContext(profile());
const std::vector<FilteringConfiguration*> configurations =
    subscription_service->GetInstalledFilteringConfigurations();

// "adblock" installed by default.
// "my_configuration" installed by previous example.
configurations[0]->GetName();  // "adblock"
configurations[1]->GetName();  // "my_configuration"

Removing a filtering configuration

You can remove filtering configuration if it is not needed. This means all associated preferences data will be removed.

FilteringConfiguration.removeConfiguration("my_configuration");

If you have FilteringConfirutation object for removed configuration, it becomes invalid. Any method called on a removed configuration will throw an IllegalStateException.

chrome.eyeoFilteringPrivate.removeConfiguration("my_configuration")
#include "chrome/browser/adblock/subscription_service_factory.h"
#include "components/adblock/core/subscription/subscription_service.h"

SubscriptionServiceFactory::GetForBrowserContext(profile())
    ->UninstallFilteringConfiguration("my_configuration");

Enabling and disabling a configuration

By default, each configuration starts as enabled. If you disable it, the state persists and the configuration starts as disabled next time the browser runs.

The following example disables my_configuraion:

import org.chromium.components.adblock.FilteringConfiguration;

// myConfiguration created by previous example.

myConfiguration.isEnabled();  // true
myConfiguration.setEnabled(false);
myConfiguration.isEnabled();  // false
// "my_configuration" created by previous example.

// Without promises:
chrome.eyeoFilteringPrivate.isEnabled('my_configuration', function(enabled) {
  // enabled == true
});
// With promises:
chrome.eyeoFilteringPrivate.setEnabled('my_configuration', false)
    .then(
        () => {chrome.eyeoFilteringPrivate.isEnabled('my_configuration')
                   .then(
                       enabled => {
                           // enabled == false;
                       })});
#include "components/adblock/core/configuration/filtering_configuration.h"

FilteringConfiguration* my_configuration =
    ...;                        // Created or retrieved by previous examples.
my_configuration->IsEnabled();  // true
my_configuration->SetEnabled(false);
my_configuration->IsEnabled();  // false

Add/Remove filter lists

Observe filter list installation progress

When you add a filter list to a configuration, the configuration is updated instantly but the download and installation may take several seconds. If you want to be notified when an installation completes, you can register an observer.

import org.chromium.components.adblock.FilteringConfiguration;

public class MySubscriptionUpdateObserver
        implements FilteringConfiguration.SubscriptionUpdateObserver {
    @Override
    public void onSubscriptionDownloaded(final URL url) {
        // url == "http://filters.com/list.txt"
    }
}

MySubscriptionUpdateObserver observer = new MySubscriptionUpdateObserver();

// myConfiguration created by previous example.
myConfiguration.addSubscriptionUpdateObserver(observer);

URL filterList = new URL("http://filters.com/list.txt");
myConfiguration.addFilterList(filterList);

// Wait until download completes
// observer.onSubscriptionDownloaded("http://filters.com/list.txt") is called
// "my_configuration" created by previous example.
const filterList = 'http://filters.com/list.txt';

chrome.eyeoFilteringPrivate.onSubscriptionUpdated.addListener(function(url) {
  // url == 'http://filters.com/list.txt'
});

await chrome.eyeoFilteringPrivate.subscribeToFilterList(
    'my_configuration', filterList);

// Wait until download completes
// the listener is called
#include "components/adblock/core/configuration/filtering_configuration.h"
#include "components/adblock/core/subscription/subscription_service.h"

class Observer : public SubscriptionService::SubscriptionObserver {
 public:
  void OnSubscriptionInstalled(const GURL& subscription_url) override {
    // subscription_url == "http://filters.com/list.txt"
  }
};

FilteringConfiguration* my_configuration =
    ...;  // Created or retrieved by previous examples.

Observer observer;
SubscriptionServiceFactory::GetForBrowserContext(profile())->AddObserver(
    &observer);

const GURL filter_list("http://filters.com/list.txt");
my_configuration->AddFilterList(filter_list);

// Wait until download completes
// Observer::OnSubscriptionInstalled is called

The Solution will also trigger this notification every time it successfully installs an update to the filter list, for example as a result of a scheduled, periodic update check.

Exempt a domain from filtering

To effectively disable all content filtering on a specific domain, add an allowed domain.

Remember, this allows all content on the domain, not from the domain. Adding trusted.org will let ads appear while the user is browsing https://www.trusted.org. But when the user is browsing https://example.com which attempts to load https://www.trusted.org/ads.js, the filtering still applies and the script might be blocked.

import org.chromium.components.adblock.FilteringConfiguration;

String allowedDomain = "trusted.org";

// myConfiguration created by previous example.
myConfiguration.addAllowedDomain(allowedDomain);

List<String> allowedDomains = myConfiguration.getAllowedDomains();
// allowedDomains = ["trusted.org"]

// The Solution will not filter any content on trusted.org.
// "my_configuration" created by previous example.
const allowed_domain = 'trusted.org';

chrome.eyeoFilteringPrivate.addAllowedDomain(
    'my_configuration', allowed_domain);
chrome.eyeoFilteringPrivate.getAllowedDomains(
    'my_configuration', function(domains) {
      // domains == ['trusted.org']
    });

// The Solution will not filter any content on trusted.org.
#include "components/adblock/core/configuration/filtering_configuration.h"

FilteringConfiguration* my_configuration =
    ...;  // Created or retrieved by previous examples.

const std::string allowed_domain = "trusted.org";
my_configuration->AddAllowedDomain(allowed_domain);

std::vector<std::string> allowed_domains =
    my_configuration->GetAllowedDomains();
// allowed_domains = ["trusted.org"]

// The Solution will not filter any content on trusted.org.

Add/Remove custom filters

Subscribe to configuration change events

If you'd like to be notified when some piece of code changes a filtering configuration, you may register an observer:

import org.chromium.components.adblock.FilteringConfiguration;

public class MyConfigurationChangeObserver
        implements FilteringConfiguration.ConfigurationChangeObserver {
    @Override
    public void onEnabledStateChanged() {
        // runs when someone calls setEnabled() to set a new state
    }
    @Override
    public void onFilterListsChanged() {
        // runs when someone adds or removes filter lists
    }
    @Override
    public void onAllowedDomainsChanged() {
        // runs when someone adds or removes allowed domains
    }
    @Override
    public void onCustomFiltersChanged() {
        // runs when someone adds or removes custom filters
    }
}

MyConfigurationChangeObserver observer = new MyConfigurationChangeObserver();

// myConfiguration created by previous example.
myConfiguration.addObserver(observer);

URL filterList = new URL("http://filters.com/list.txt");
myConfiguration.addFilterList(filterList);

// observer.onFilterListsChanged() is called
// "my_configuration" created by previous example.
chrome.eyeoFilteringPrivate.onEnabledStateChanged.addListener(
    'my_configuration', function() {
      // runs when someone calls setEnabled() to set a new state
    });

chrome.eyeoFilteringPrivate.onFilterListsChanged.addListener(
    'my_configuration', function() {
      // runs when someone adds or removes filter lists
    });

chrome.eyeoFilteringPrivate.onAllowedDomainsChanged.addListener(
    'my_configuration', function() {
      // runs when someone adds or removes allowed domains
    });

chrome.eyeoFilteringPrivate.onCustomFiltersChanged.addListener(
    'my_configuration', function() {
      // runs when someone adds or removes custom filters
    });


const filterList = 'http://filters.com/list.txt';
await chrome.eyeoFilteringPrivate.subscribeToFilterList(
    'my_configuration', filterList);

// the second listener is called
#include "components/adblock/core/configuration/filtering_configuration.h"

class Observer : public FilteringConfiguration::Observer {
 public:
  void OnEnabledStateChanged(FilteringConfiguration* config) override {
    // runs when someone calls SetEnabled() to set a new state
  }
  void OnFilterListsChanged(FilteringConfiguration* config) override {
    // runs when someone adds or removes filter lists
  }
  void OnAllowedDomainsChanged(FilteringConfiguration* config) override {
    // runs when someone adds or removes allowed domains
  }
  void OnCustomFiltersChanged(FilteringConfiguration* config) override {
    // runs when someone adds or removes custom filters
  }
};

FilteringConfiguration* my_configuration =
    ...;  // Created or retrieved by previous examples.

Observer observer;
my_configuration->AddObserver(&observer);

const GURL filter_list("http://filters.com/list.txt");
my_configuration->AddFilterList(filter_list);

// Observer::OnFilterListsChanged is called

Observe resource classification

If you wish to be notified when network resources are blocked or allowed, register as an observer.

import org.chromium.components.adblock.ResourceClassificationNotifier;

public class MyClassificationObserver implements ResourceClassificationNotifier.AdBlockedObserver {
    @Override
    public void onAdAllowed(AdblockCounters.ResourceInfo info) {
        // Runs when a resource is specifically allowed by an
        // allowing filter from a filtering configuration
        // and isn't blocked by other filtering configurations.
    }
    @Override
    public void onAdBlocked(AdblockCounters.ResourceInfo info) {
        // Runs when a resource is blocked by a blocking filter
        // from at least one enabled filtering configuration.
    }
    @Override
    public void onPageAllowed(AdblockCounters.ResourceInfo info) {
        // Runs when every enabled filtering configuration exempts
        // this domain from filtering via allowed domains.
    }
    @Override
    public void onPopupAllowed(AdblockCounters.ResourceInfo info) {
        // Runs when a popup window is specifically allowed by an
        // allowing filter from a filtering configuration
        // and isn't blocked by other filtering configurations.
    }
    @Override
    public void onPopupBlocked(AdblockCounters.ResourceInfo info) {
        // Runs when a popup window is blocked by a blocking filter
        // from at least one enabled filtering configuration.
    }
}

MyClassificationObserver observer = new MyClassificationObserver();

ResourceClassificationNotifier.getInstance().addOnAdBlockedObserver(observer);
chrome.eyeoFilteringPrivate.onRequestAllowed.addListener(function(info) {
  // Runs when a resource is specifically allowed by an
  // allowing filter from a filtering configuration
  // and isn't blocked by other filtering configurations.
});
chrome.eyeoFilteringPrivate.onRequestBlocked.addListener(function(info) {
  // Runs when a resource is blocked by a blocking filter
  // from at least one enabled filtering configuration.
});
chrome.eyeoFilteringPrivate.onPageAllowed.addListener(function(info) {
  // Runs when every enabled filtering configuration exempts
  // this domain from filtering via allowed domains.
});
chrome.eyeoFilteringPrivate.onPopupAllowed.addListener(function(info) {
  // Runs when a popup window is specifically allowed by an
  // allowing filter from a filtering configuration
  // and isn't blocked by other filtering configurations.
});
chrome.eyeoFilteringPrivate.onPopupBlocked.addListener(function(info) {
  // Runs when a popup window is blocked by a blocking filter
  // from at least one enabled filtering configuration.
});

#include "chrome/browser/adblock/resource_classification_runner_factory.h"
#include "components/adblock/content/browser/resource_classification_runner.h"

class MyClassificationObserver : public ResourceClassificationRunner::Observer {
 public:
  void void OnAdMatched(const GURL& url,
                        FilterMatchResult match_result,
                        const std::vector<GURL>& parent_frame_urls,
                        ContentType content_type,
                        content::RenderFrameHost* render_frame_host,
                        const GURL& subscription) override {
    if (match_result == FilterMatchResult::kAllowRule) {
      // Runs when a resource is specifically allowed by an
      // allowing filter from a filtering configuration
      // and isn't blocked by other filtering configurations.
    }
    if (match_result == FilterMatchResult::kBlockRule) {
      // Runs when a resource is blocked by a blocking filter
      // from at least one enabled filtering configuration.
    }
  }
  void void OnPageAllowed(const GURL& url,
                          content::RenderFrameHost* render_frame_host,
                          const GURL& subscription) override {
    // Runs when every enabled filtering configuration exempts
    // this domain from filtering via allowed domains.
  }
  void void OnPopupMatched(const GURL& url,
                           FilterMatchResult match_result,
                           const GURL& opener_url,
                           content::RenderFrameHost* render_frame_host,
                           const GURL& subscription) override {
    if (match_result == FilterMatchResult::kAllowRule) {
      // Runs when a popup window is specifically allowed by an
      // allowing filter from a filtering configuration
      // and isn't blocked by other filtering configurations.
    }
    if (match_result == FilterMatchResult::kBlockRule) {
      // Runs when a popup window is blocked by a blocking filter
      // from at least one enabled filtering configuration.
    }
  }
};

MyClassificationObserver observer;
ResourceClassificationRunnerFactory::GetForBrowserContext(profile())
    ->AddObserver(&observer);

abort-current-inline-script

This snippet aborts the execution of an inline script when a property is either read or written.

Parameters

Filter examples

The following table lists examples that use the abort-current-inline-script filter:

Tradeoffs

Keep the following tradeoffs in mind when you use the abort-current-inline-scriptfilter:

  • The snippet is executed after all of a page's inline scripts. As a result, you should only attach properties read inside of a callback, which can be executed after the script.

  • You can only attach this snippet to global properties, or properties of the window object.

blob-override

The blob-override snippet overrides specific parts of the Blob injected in web-pages. We override the blob constructor in a way we can intercept calls and change the blob content.

Parameters

Filter examples

Debugging

The following table contains messages you'll find useful during debugging:

json-override

The json-override snippet wraps JSON.parse to override values from the same list as override-property-read.

Parameters

Possible override values

Filter examples

The following table lists examples that use the json-override snippet:

Debugging

The following table contains messages you'll find useful during debugging:

cookie-remover

The cookie-remover removes certain cookies. You can parse document.cookie to set the expiration dates in the past for cookies that match targeted patterns.

Parameters

Filter examples

The following table lists examples that use the abort-on-iframe-property-write snippet:

Debugging

The following table contains messages you'll find useful during debugging:

In the , you've learned how to configure ad-filtering. But the underlying filtering engine is more capable.

As long as you can express the filtering demands via , you can probably use the Browser Ad-Filtering Solution to implement the behavior.

These settings are stored persistently in .

These parameters are very similar to the ones you encountered in the . In fact, the ad-filtering settings are implemented as a filtering configuration - with the name adblock. It is created by default in the Solution.

Filtering configurations allow dynamic management of filter lists identified by their URLs. To see implementation details for managing filter lists, refer to the .

If you need to allow all content from a domain, see .

Custom filters allow fine-tuning of filtering behavior by adding individual filters. For details on adding or removing custom filters, refer to the .

You don't observe a single filtering configuration because all installed filtering configurations take part in classification - see .

Name
Description
Mandatory
Filter
Result
Name
Description
Mandatory
Default value
Filter
Result
Message
When the message occurs
Definition
Name
Description
Mandatory
Value
Definition
Filter
Result
Message
When the message occurs
Definition
Name
Description
Mandatory
Filter
Result
Message
When the message occurs
Definition
previous section
the filtering language
Preferences
previous section
Configure SDK Settings guide
Configure SDK Settings guide
Add/Remove custom filters
Interactions between filtering configurations

api

The API function or property name to anchor on. It can also be the path to that property.

If the property is a direct child of window, this parameter will be the property name. If you want to access a sub property, though, this parameter becomes a chain of properties separated by dots.

Yes

search

If specified, only scripts containing the given string are prevented from executing.

If the string begins and ends with a slash (/), the text in between is treated as a regular expression.

No

abort-current-inline-script setDefaultTheme

The code that calls/writes the setDefaultTheme global function throws an exception.

abort-current-inline-script document.head.appendChild

The code that calls/writes the appendChild function throws an exception. This function is a property of head, which is a property of the document global object. Be cautious when using this approach; it blocks any code that appends an element to head.

abort-current-inline-script Object.prototype.networkListener

The code that reads/writes the networkListener property throws an exception.

This example shows that you can attach the filter to prototype properties.

abort-current-inline-script btoa BOOTLOADER_LOADED

The code that calls/writes the btoa global function throws an exception. This filter would only work inside inline scripts whose text content contains the BOOTLOADER_LOADED string.

abort-current-inline-script document.createElement /ru-n4p|ua-n4p|загрузка.../

The code that calls/writes the createElement function of document throws an exception. This filter would only work inside inline scripts whose text content matches the /ru-n4p|ua-n4p|загрузка.../{regex}.

search

The string or regex pattern to match in the blob content.

Yes

n.a.

replacement

The string to replace the matched pattern with.

No

''

needle

An optional string or regex to check in the * blob parts before applying the replacement.

No

''

blob-override '/config = \\{[^}]*\\}/' 'config = {}' '/Sponsored/'

Will override the config content matched via regex pattern with an empty object only if the blob contains also the string Sponsored.

info - Wrapped Blob constructor in context

After we have wrapped the window.Blob API.

From this moment on the blob prototype is intercepted by us.

success - Replaced: search → replacement FILTER: blob-override params

After we have matched and replaced the blob content.

The filter successfully hit.

rawOverridePaths

A list of space-separated properties to remove. It also accepts property chains - e.g. foo.bar.tar. Can include placeholders {} and [] to iterate over nested objects and arrays respectively.

Yes

value

The value to override the property with.

Yes

rawNeedlePaths

A list of space-separated properties. All must be present for pruning to occur. Also accepts property chains.

No

filter

A string to look for in the raw string, before it's passed to JSON.parse. If no match is found, no further search is done on the resulting object.

If the string begins and ends with a slash (/), the text in between is treated as a regular expression.

No

undefined

false

true

null

" "

An empty string

decimal integer

noopFunc

A function with an empty body

trueFunc

A function that returns true

emptyArray

An array with no elements

emptyObj

An object with no properties

json-override ghl_label ''

Replaces the ghl_label property value (if found) with an empty string from every object parsed with JSON.parse.

json-override 'children text' ''

Replaces all children and text property values (if found) with an empty string from every object parsed with JSON.parse.

json-override ghl_label '' text

Replaces any ghl_label property value (if found) with an empty string from every object that has a text property and is parsed with JSON.parse.

json-override 'children text' '' 'styles tag'

Replaces all children and text property values (if found) from every object that has both the styles and tag properties and is parsed with JSON.parse.

json-override ghl_label.children '' '' 'test'

Replaces the children sub-property value of a ghl_label property (if found) with an empty string only if the raw string contains test from every object that is parsed with JSON.parse.

json-override data.nested.[].ad ''

Replaces all the ad values listed inside an array with an empty string. before {"data":{ "nested":[ {"ad":"replace me"}, {"ad":"replace me"}, {"ad":"replace me"}, {"not-ad":"don't replace me"}], "hello-world":"don't replace me"} } after {"data":{ "nested":[ {"ad":""}, {"ad":""}, {"ad":""}, {"not-ad":"don't replace me"}], "hello-world":"don't replace me"} }

json-override data.nested.{}.ad ''

Replaces ad values from item1, item2, etc. with an empty string. {} is a placeholder for any "parent" property of ad. before {data: { "nested": { "item1": { "ad": "replace me" }, "item2": { "ad": "replace me" }, "item3": { "ad": "replace me" }, "item4": { "not-ad": "don't replace me" }, "hello-world":"don't replace me"} } after {data: { "nested": { "item1": { "ad": "" }, "item2": { "ad": "" }, "item3": { "ad": "" }, "item4": { "not-ad": "don't replace me" }, "hello-world":"don't replace me"} }

Wrapped JSON.parse

After JSON.parse has been wrapped

The snippet was injected and the API was wrapped.

Iterating over array at [] or Iterating over object at {}

The snippet is parsing the placeholder.

The path leading up to the placeholder is accurate. If a success log does not follow this, it indicates that the filter needs further refinement beyond the placeholder.

Found <<rawOverridePath>> replaced it with <<value>> FILTER: json-override '<<param>>'

After a property was overridden.

A property was found and overridden. If rawOverridePaths has multiple paths, we will see a message for each found path. The filter that successfully overrode the property (the parameters will be individually wrapped in single quotes).

cookie

A pattern that matches the name of the cookie(s) you want to remove. If the string starts and ends with a slash (/), the text in between is treated as a regular expression.

Yes

autoRemoveCookie

Default value: false. When set to true, this parameter enables the snippet to continuously monitor the targeted cookie, checking for its presence every 1000 ms. If the cookie is found, it will be repeatedly removed. To use only in case the website sets back the cookie after removal.

No

cookie-remover adb

Removes any cookie that matches adb.

cookie-remover adb true

Removes every second any cookie that matches adb.

DEBUG cookie-remover Parsing cookies for matches

Before parsing begins

The first message displayed, indicating that parsing is about to begin

DEBUG cookie-remover Set expiration date on cookieName

Each time a match is found

This message contains the name of the cookie you just removed.

array-override

The array-override overrides functions under Array.prototype to change their behaviour according to the given parameters. .

Parameters

Name
Description
Mandatory
Default value

method

The Array function to override. Possible values to override the property with: push, includes.

Yes

n.a.

needle

The string or regex used to determine which function calls to trap. If the needle matches the parameter to the function call, the snippet will work, else the function will behave as normal. If the string begins and ends with a slash ( / ), the text in between is treated as a regular expression.

Yes

n.a.

returnValue

Optional parameter that is only relevant for includes. This parameter determines what to return when the parameter matches the needle. Accepts: true or false. Default is false.

No

false

Filter examples

Filter
Result

array-override push test

Will ignore array.push(“test“) while allowing other values to be added to the array. Example: const arr = []; arr.push(“1“); arr.push(“2“); arr.push(“test“) arr will only have the values “1” and “2” inside of it.

array-override push /first.*second/

Will ignore the call if the parameter to array.push starts with “first“ and ends with “second“ while allowing other values to be added to the array. Example: const arr = []; arr.push(“1“); arr.push(“2“); arr.push(“first-123-second“) arr will only have the values “1” and “2” inside of it.

array-override includes test true

array.includes(“test“) will always return true regardless of whether it’s in the array or not.

array-override includes /first.*second/ false

array.includes(“first-123-second“) will always return false regardless of whether it’s in the array or not.

Debugging

The following table contains messages you'll find useful during debugging:

Message
When the error occurs
Definition

Wrapped Array.prototype.push

After we have wrapped the Array.prototype.push API.

From this moment on push calls are intercepted by us.

Wrapped Array.prototype.includes

After we have wrapped the Array.prototype.includes API.

From this moment on includes calls are intercepted by us.

Array.push is ignored for needle: <> FILTER: array-override <>

Needle matches a call to Array.push.

The call to Array.push was ignored.

Array.includes returned <> for <> FILTER: array-override <>

Needle matches a call to Array.includes.

Array.includes returned the value given with returnValue instead of the correct value.

event-override

The event-override snippet proxies events and event handlers to defuse events or change their attributes. It works with the principle of proxying addEventHandler function and the original Event class with a CustomEvent class that we control. This way we can defuse/change any arbitrary event or create new ones.

Parameters

Name
Description
Mandatory
Default value

eventType

The type of the event to target. Examples: click, mouseover, someCustomEvent

Yes

n.a.

mode

The mode of the operation. Accepts: “trusted“, “disable“. trusted mode makes the event property isTrusted true. disable mode: Disables the matching event.

Yes

n.a.

needle

Needle to look for in the event listener function.

No

''

Filter examples

Filter
Result

event-override click disable

Will disable all event listeners for the click event.

event-override someCustomEvent disable

Will disable all event listeners for the onAbnormalityDetected event.

event-override click trusted serveAd

Will make the isTrusted attribute true for the click events that have the string “serveAd“ in their event listener function.

replace-fetch-response

The replace-fetch-response snippet replaces the response of a fetch request if the response text matches a given regular expression pattern.

Parameters

Filter examples

Debugging

The following table contains messages you'll find useful during debugging:

override-property-read

The override-property-read snippet overrides a property's value on the window object with a set of available properties.

You can use the override-property-read snippet to change the value of global properties.

Parameters

Possible override values

Possible values to override the property with:

Filter examples

The following table lists examples that use the override-property-read snippet:

Debugging

The following table contains messages you'll find useful during debugging:

freeze-element

The freeze-element freezes a DOM element, thereby preventing new nodes from being adding inside the element.

Parameters

Filter examples

The following table lists examples that use the abort-on-property-write snippet:

Debugging

During debugging, you'll see messages in your browser's Developer Console of the browser for every attempt to add a child node inside the frozen element.

As a result, the elements will be added to the frozen parent node, but they won't be visible as the CSS property display: none is added.

For all the DOM mutation properties apart from textContent, innerText and nodeValue, the structure of the message is the following (each line in the table is a line printed to the console):

For textContent, innerText and nodeValue, the structure of the message is the following (each line in the table is a line printed to the console):

Considerations

Keep the following in mind when you use the freeze-elementsnippet:

  • Logging is more reliable than highlighting. Sometimes, some elements don't show as highlighted even if their style has the correct rules.

  • Sometimes, when you hover on addedNode in the console, the added node is not highlighted on the page as it should be. That is because for some DOM mutation properties, like innerHTML, outerHTML or insertAdjacentHTML, the element loses its reference when it gets added.

  • When you see all the elements of a parent node highlighted/logged, that doesn't necessarily mean nothing was there to begin with. That's because of how innerHTML and outerHTML work: changing these properties of an element results in overriding the content. When you see all the children highlighted, then, it could be because innerHTML or outerHTML was used.

Name
Description
Mandatory
Default value
Filter
Result
Message
When the message occurs
Definition
Name
Description
Mandatory
Value
Definition
Filter
Result
Message
When the message occurs
Definition
Name
Description
Example
Mandatory
Filter
Result
Message
Structure
Explanation
Examples
Message
Structure
Explanation
Examples

search

String or regex pattern that will be run against the stringified fetch response. Everything that matches the regex will be replaced with the replacement value.

Yes

n.a.

replacement

Everything that matches the regex will be replaced with the replacement value. By default this will be an empty string, so everything that matches the regex will be removed from the fetch response.

No

empty string

needle

The replacement will only happen if the needle text is present in the response. By default this is an empty string. If the string begins and ends with a slash ( / ), the text in between is treated as a regular expression.

No

empty string

replace-xhr-response '/ads:\\[(.*?)\\]/'

Will remove anything that looks like ads:[any-string] from every fetch response body.

replace-fetch-response 'serve-ads:true' 'serve-ads:false'

Will replace the string serve-ads:true to serve-ads:false in the response body.

replace-fetch-response 'serve-ads:true' 'serve-ads:false' example.com

Will replace the string serve-ads:true to serve-ads:false in the response body only if the response contains "http://example.com"

Network API proxied

After we have wrapped the fetch API.

From this moment on fetch calls are intercepted by us.

Needle found in fetch response [original fetch response body]

A matching needle has been found in the response.

Needle found, we will look for the search parameter next.

Needle not found in fetch response [original fetch response body]

Needle not found in the response.

We will not modify this response.

Search * replaced with replacement in fetch response FILTER: replace-fetch-response param [replaced fetch response body]

The search parameter has been found and the response has been replaced with the replacement string.

This is a group of logs containing the filter that successfully replaced the fetch response (the parameters will be individually wrapped in single quotes) and the replaced response.

property

The name of the property or the path to that property. If the property is a direct child of window, this parameter will be just the property name. But, if you want to access a sub property, this parameter will be a chain of properties separated by dots.

Yes

value

The value to override the property with.

Yes

setConfigurable

Value of the configurable attribute of the [descriptor](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty#description) of property. If this parameter is not used it defaults to true. Setting it to false will prevent the property set and get being overwritten or otherwise changed by anybody (including us). If this snippet doesn't work as expected when passing only the property and the value, it could mean that the website is circumventing and setting this parameter to false can come in handy.

No

undefined

false

true

null

noopFunc

function with an empty body

trueFunc

function that returns true

falseFunc

function returning false

" "

empty string

positive decimal integer

override-property-read adConfig undefined

adConfig has the value of undefined.

override-property-read adConfig undefined false

adConfig has the value of undefined and it is no longer configurable.

override-property-read shouldShowAds falseFunc

shouldShowAds has the value of a function that returns false when called.

override-property-read config.adCount 0

config.adCount has the value of 0.

<<property>> override done

Each time the property is read

The property is accessed.

Overrding <<property>> FILTER: override-property-read <<param>>

Right before attaching to the property

This log is printed just before the snippet takes over the property getter, along with the filter that successfully overrode the property (the parameters will be individually wrapped in single quotes).

property

The CSS selector for the parent element that you want to freeze.

'.left-content .container'

Yes

options

A single parameter for snippet options. A string containing all the options you want to pass, each of them separated by a plus character (+), and empty single quotes if none ('').

Available options:

  • subtree (if you want to freeze all the element's children as well)

  • abort (throws an error every time a child element gets added)

'' or subtree or abort or subtree+abort etc.

No

exceptions

An array of regular expressions/selectors used to specify the nodes you don't want to prevent being added.

Each array item can be:

  • A selector (targeting element nodes)

  • Regex (targeting text nodes, identified by slash)

.article #banner .navigation /.*/

No

freeze-element ol#b_results

Any addition of an immediate child to the ol#b_results element will be blocked.

freeze-element ol#b_results subtree

Any addition of a node to the entire subtree of ol#b_results element will be blocked.

freeze-element ol#b_results '' .organic-result

Any addition of an immediate child to the ol#b_results element will be blocked, except for the elements with the organic-result class.

freeze-element ol#b_results '' .organic-result /hello/

Any addition of an immediate child to the ol#b_results element will be blocked, except for the elements with the organic-result class and the text nodes that match the /hello/ regex.

freeze-element ol#b_results '' .organic-result /.*/

Any addition of an immediate child to the ol#b_results element will be blocked, except for the elements with the organic-result class and any Text node.

freeze-element ol#b_results '' .organic-result #header

Any addition of an immediate child to the ol#b_results element will be blocked, except for the elements with the organic-result class or the id of header.

freeze-element ol#b_results subtree .organic-result #header

Any addition of a node to the entire subtree of ol#b_results element will be blocked, except for the elements with the organic-result class or the id of header.

freeze-element ol#b_results abort

Any addition of an immediate child to the ol#b_results element will throw an error.

freeze-element ol#b_results abort+subtree

Any addition of a node to the entire subtree of ol#b_results element throw an error.

freeze-element ol#b_results abort+subtree .organic-result

Any addition of a node to the entire subtree of ol#b_results element will throw an error, except for the elements with the organic-result class.

title

[freeze][changeId] action: selector

  • changeId - the # of the attempt

  • action - aborting/watching

  • selector - the first argument of the snippet

  • [freeze][0] watching: ol#b_results

  • [freeze][1] aborting: ol#b_results

property used

[freeze][changeId] using the function: "property"

  • changeId - the # of the attempt

  • property - the DOM mutation property used

  • [freeze][0] added the function: "innerHTML"

parent node

[freeze][changeId] added to node: parentNode

  • changeId - the # of the attempt

  • parentNode - the parent node where the added node attempts to be inserted

  • [freeze][0] added to node: <div id='parent'></div>

added node

[freeze][changeId] node: addedNode

  • changeId - the # of the attempt

  • addedNode - the blocked node

  • [freeze][0] node: <div class='ad'>ad</div>

title

[freeze][changeId] action: selector

  • changeId - the # of the attempt

  • action - aborting/watching

  • selector - the first argument of the snippet

  • [freeze][0] watching: ol#b_results

  • [freeze][1] aborting: ol#b_results

parent node

[freeze][changeId] content of node: parentNode

  • changeId - the # of the attempt

  • parentNode - the parent node where the added node attempts to be inserted

  • [freeze][0] content of node: <div id='parent'>child</div>

new content

[freeze][changeId] changed to: newContent

  • changeId - the # of the attempt

  • newContent - the new content for the parent node

  • [freeze][0] changed to: text add

property used

[freeze][changeId] using the function: "property"

  • changeId - the # of the attempt

  • property - the DOM mutation property used

  • [freeze][0] added the function: "textContent"

json-prune

The json-prune snippet traps calls to JSON.parse and, if the result of the parsing is an Object, it will remove the specified properties from the result before returning to the caller.

Use json-prune when you want to remove properties from an object parsed with JSON.parse.

Parameters

Name
Description
Mandatory

rawPrunePaths

A list of space-separated properties to remove.

Yes

rawNeedlePaths

A list of space-separated properties which must be all present for the pruning to occur. Can include placeholders {} and [] to iterate over nested objects and arrays respectively.

No

rawNeedleStack

A list of space-separated strings or regex which must be present in the JSON.prune call stack for the pruning to occur.

No

Filter examples

The following table lists examples that use the json-override snippet:

Filter
Result

json-prune ads

Removes any ads property (if found) from every object parsed with JSON.parse.

json-prune 'ads videoAds'

Removes all ads and videoAds properties (if found) from every object parsed with JSON.parse.

json-prune ads userId

Removes any ads property (if found) from every object parsed with JSON.parse with a userId property.

json-prune 'ads videoAds' userId

Removes all ads and videoAds properties (if found) from every object parsed with JSON.parse with a userId property.

json-prune 'ads videoAds' 'userId title'

Removes all ads and videoAds properties (if found) from every object parsed with JSON.parse that has both userId and title properties.

json-prune data.nested.[].ad

Removes all the ad properties listed inside an array: before {"data":{ "nested":[ {"ad":"delete me"}, {"ad":"delete me"}, {"ad":"delete me"}, {"not-ad":"don't delete me"}], "hello-world":"don't delete me"} } after {"data":{"nested":[{}, {}, {}, {"not-ad":"don't delete me"}],"hello-world":"don't delete me"}}

json-prune data.nested.{}.ad

Removes all the ad properties listed inside an object, without mentioning the key of each object: before {"data": {"nested": {"item1":{}, "item2":{}, "item3":{}, "item4":{"not-ad":"don't delete me"} }, "hello-world":"don't delete me"} } after {"data":{"nested":{"item1":{},"item2":{},"item3":{},"item4":{"not-ad":"don't delete me"}},"hello-world":"don't delete me"}}

json-prune ads '' functionName

Removes any ads if in the call stack trace functionName is found.

json-prune ads '' /innerFunctionName(.|\\n)*outerFunctionName/

Removes any ads if in the call stack trace innerFunctionName and outerFunctionName are found. The regex pattern (.|\\n) is used to match these function names, ignoring any content or new lines in between. However, note that regex flags for single-line (/s) or multi-line (/m) matching will not work. When crafting the regex for the call stack trace, remember that functions are listed from the innermost (most recent) to the outermost (earlier) calls. So, the innermost functions appear first in the trace, while previous function calls appear later.

Debugging

The following table contains messages you'll find useful during debugging:

Message
When the message occurs
Definition

Wrapped JSON.parse

After JSON.parse has been wrapped

The snippet was injected and the API was wrapped.

Iterating over array at [] or Iterating over object at {}

The snippet is parsing the placeholder.

The path leading up to the placeholder is accurate. If a success log does not follow this, it indicates that the filter needs further refinement beyond the placeholder.

Found needle in stack trace: <<rawNeedleStack>>

After comparing the passed <<rawNeedleStack>> param against the JSON.parse stack trace.

The needle has been successfully found.

Needle <<rawNeedleStack>> not found in stack trace: <<stack trace>>

After comparing the passed <<rawNeedleStack>> param against the JSON.parse stack trace.

The needle remains unfound. To assist in fine-tuning the <<rawNeedleStack>> parameter, the stack trace will be logged for further analysis.

Found <<rawPrunePaths>> and deleted. FILTER: json-prune '<<param>>'

After a property was deleted.

A property was found and deleted. If rawPrunePaths has multiple paths, we sill see a message for each found path, along with the filter that successfully deleted the property (the parameters will be individually wrapped in single quotes).

Conditional Hiding Snippets

prevent-listener

The prevent-listener snippet prevents the addition of event listeners.

You can use prevent-listener by wrapping EventTarget.prototype.addEventListener and not allowing listeners to be added for certain event types.

Parameters

Filter examples

The following table lists examples that use the abort-on-iframe-property-write snippet:

Debugging

The following table contains messages you'll find useful during debugging:

simulate-mouse-event

The simulate-mouse-event snippet triggers arbitrary mouse events on elements matched by a CSS or XPath selector by calling dispatchEvent for a selector.

The following table lists MouseEvent and PointerEvent events for this snippet:

Parameters

eyeo uses a custom, optional parameter syntax similar to the syntax used in specificClicker.

Mandatory parameter

Optional parameters

Optional parameters are added to the selectors with a $ sign. You can combine multiple parameters for a single selector by separating them with a comma. If you don't specify a parameter is, the default value will be assumed for that selector.

Filter examples

The following table lists examples that use the simulate-mouse-event snippet:

strip-fetch-query-parameter

The strip-fetch-query-parameter strips a query string parameter from fetch() calls.

You can use this snippet to remove parameters from fetch calls that mach a urlPattern, if provided. If urlPattern isn't provided, the parameter gets stripped from all fetch calls.

Parameters

Filter examples

The following table lists examples that use the strip-fetch-query-parameter snippet:

Name
Description
Mandatory
Filter
Result
Message
When the message occurs
Definition
MouseEvents
PointerEvents
Name
Description
Mandatory
Name
Description
Default
Mandatory
Filter
Result
Name
Description
Mandatory
Filter
Result

type

A pattern that matches the type(s) of events you want to prevent. If the string starts and ends with a slash (/), the text in between is treated as a regular expression.

Yes

handler

A pattern that matches the event handler's declaration. If the string starts and ends with a slash (/), the text in between is treated as a regular expression.

No

selector

The CSS selector that the event target must match. If the event target is not an HTML element, the event handler is added.

No

prevent-listener click

No event listener will be added for click events.

prevent-listener click console div

No click event listener will be added on div elements whose handler matches console.

For example, these listeners won't be added: window.addEventListener("click", ()=>console.log("click")) document.body.addEventListener("click", ()=>console.log("click")) But this listener would be added: omeDiv.addEventListener("click", ()=>console.log("click"))

prevent-listener click console

No listener will be added for click events whose handler matches console. For example, these listeners won't be added: someElement.addEventListener("click", () => console.log("click")) But these listeners would be added: someElement.addEventListener("click", () => alert("click"))

DEBUG [prevent] Wrapped addEventListener

After wrapping

Displayed after addEventListener has been wrapped.

DEBUG [prevent] was successful DEBUG [prevent] type: actualType matching providedType DEBUG [prevent]handler: actualHandler DEBUG [prevent] matching providedHandler DEBUG [prevent] on element actualElement matching selector DEBUG [prevent] was prevented from being added

Each time a listener is prevented from being added

This is a group of logs containing detailed information about the event type and its handler. They're displayed each time we prevent a listener from being added.

If the optional handler or selector parameter was omitted, the corresponding log(s) will be skipped.

auxclick

pointerover

click

pointerenter

dblclick

pointerdown

mousedown

pointermove

mouseenter

pointerup

mouseleave

pointercancel

mousemove

pointerout

mouseout

pointerleave

mouseover

gotpointercapture

mouseup

lostpointercapture

selectors

The CSS/XPath selector that an HTML element must match for the event to be triggered. A maximum of seven (7) selectors are supported.

Yes

$trigger

If this flag is not set, only the chosen event for the last selector will be triggered.

The $trigger flag can be used for the other selectors to ensure sure the event triggers for them, as well. You can omit the last selector, as $trigger is always true for the last selector.

false

No

$delay

This determines how much time the snippet should wait before simulating the event.

Default is 500 ms. If you don't want a delay, you must explicitly state $delay=0.

500

No

$continue

If set, the event will be triggered after each delay period ends.

For example, if the selected event is click and the delay is 500 ms, then the click event will be triggered every 500 ms instead of just once.

false

No

$event

Determines which event should be simulated for the selector.

click

No

simulate-mouse-event 'some-css-selector'

Simulates a click event for the elements that match the selector after 500 ms.

simulate-mouse-event 'css-selector1' 'css-selector2'

Simulates a click event for css-selector2 only if css-selector1 is present in the page. Does not click css-selector1.

simulate-mouse-event 'css-selector1$trigger' 'css-selector2'

Simulates a click event for both of the selectors if both of them are present in the page. The $trigger parameter for css-selector2 can be omitted, as it is the last parameter.

simulate-mouse-event 'xpath(some-xpath-selector)$delay=0'

Simulates a click event for the elements that are matched with the xpath selector with no delay.

simulate-mouse-event 'some-css-selector$continue,delay=100'

Simulates a click event every 100 ms.

simulate-mouse-event 'some-css-selector$continue,delay=100, event=mouseover'

Simulates a mouseover (hover) event over all elements matching the selector every 100 ms.

name

The parameter's name.

Yes

urlPattern

An optional pattern that the URL must match. If the string begins and ends with a slash (/), the text in between is treated as a regular expression.

No

strip-fetch-query-parameter ads

Strips the ads param from all fetch calls.

strip-fetch-query-parameter ads someadsserver.com/get-ads

Strips the ads param from fetch calls whose source matches the someadsserver.com/get-ads pattern.

replace-xhr-response

The replace-xhr-response snippet replaces the response of a XHR request if the response text matches a given regular expression pattern.

Parameters

Name
Description
Mandatory
Default value

search

String or regex pattern that will be run against the stringified XHR response. Everything that matches the regex will be replaced with the replacement value.

Yes

n.a.

replacement

Everything that matches the regex will be replaced with the replacement value. By default this will be an empty string, so everything that matches the regex will be removed from the XHR response.

No

empty string

needle

The replacement will only happen if the needle text is present in the response. By default this is an empty string. If the string begins and ends with a slash ( / ), the text in between is treated as a regular expression.

No

empty string

Filter examples

Filter
Result

replace-xhr-response '/ads:\\[(.*?)\\]/'

Will remove anything that looks like ads:[any-string] from every response body.

replace-xhr-response 'serve-ads:true' 'serve-ads:false'

Will replace the string serve-ads:true to serve-ads:false in the response body.

replace-xhr-response 'serve-ads:true' 'serve-ads:false' example.com

Will replace the string serve-ads:true to serve-ads:false in the response body only if the response contains "http://example.com"

Debugging

The following table contains messages you'll find useful during debugging:

Message
When the message occurs
Definition

XMLHttpRequest proxied

After we have wrapped the XMLHttpRequest object.

From this moment on XMLHttpRequests are intercepted by us.

Needle found in XHR response [original XHR response body]

A matching needle has been found in the response.

Needle found, we will look for the search parameter next.

Needle not found in XHR response [original XHR response body]

Needle not found in the response.

We will not modify this response.

Search * replaced with replacement in XHR response FILTER: replace-xhr-response param [replaced XHR response body]

The search parameter has been found and the response has been replaced with the replacement string.

This is a group of logs containing the filter that successfully replaced the XHR response (the parameters will be individually wrapped in single quotes) and the replaced response.

hide-if-canvas-contains

The hide-if-canvas-contains hides a canvas element, or a parent element specified by the selector parameter, if the canvas contains the specified search term in it.

We override the fillText and strokeText canvas methods. When a website uses this functions, it won’t use the native functions but instead use our overriden proxy. This allows us to know when a website writes a text we are interested in (Sponsored, Advertised etc.) to the and hide the ad.

Parameters

Name
Description
Mandatory
Default

search

String or regex pattern that will be searched in fillText and strokeText

Yes

-

selector

The selector identifies the HTML element to hide. This can be the canvas element itself or a parent of the canvas. Defaults to the element if not provided.

No

canvas

Filter examples

The following table lists examples that use the hide-if-canvas-contains snippet:

Filter
Result

hide-if-canvas-contains /sponsored/

Hides any canvas element whose text content matches sponsored and has been added with a fillText or strokeText call.

hide-if-canvas-contains /sponsored/ .canvas-parent

Hides any HTML element with a class class-parent that contains a canvas element whose text content matches sponsored and has been added with a fillText or strokeText call.

skip-video

Makes the video skip to its end or fast forwards it with the given amount. It does it by setting the currentTime attribute of the video object.

Parameters

Filter examples

The following table lists examples that use the skip-video snippet:

Name
Description
Mandatory
Default Value
Name
Description
Default Value
Example Value
Filter
Result

playerSelector

The CSS or the XPath selector to the video element in the page.

Yes

-

xpathCondition

The XPath selector that will be used to know when to trigger the skipping logic.

Yes

-

optionalParameters

Optional parameters to configure the snippet. Any number of the supported parameters from the table below can be added to this in any order. Separate the optional parameters with space as if they are different arguments to the filter.

No

-skip-to

Determines the time of the video to skip to. If the value is zero or negative, the snippet skips to the end of the video (video.currentTime = video.duration + skipTo). If the skipTo value is positive, the snippets skips the video by the given value (video.currentTime = video.currentTime + skipTo). A small negative value like (-0.1) or zero is preferred for most of the cases as it would cause the video to nearly instantly end. Large positive values can be used to quickly fast forward a video (5-10 seconds at a time) to better mimic user behaviour and escape some detection methods. Example: If there is a 30 second ad, -0.1 is given as the skipTo parameter, the video will be instantly skipped to 29.900 (0.1 seconds before the 30 second mark). If positive 10 seconds is given as the skipTo parameter, video will be skipped to 10 seconds, 20 seconds and to 30 seconds every time there is a tick of the snippet (happens at every page mutation). If 0 is given as the skipTo parameter, video will be instantly skipped to the end (30 second mark). Unit is in seconds.

-0.1

-skip-to:10

maxAttempts

If the video is not fully loaded by the time the xPath condition is met; there is a retry mechanism in the snippet. The snippet will try to skip the video once every retryMs interval. -max-attempts parameter will determine the maximum number of attempts the snippet should do before giving up. This parameter doesn't need to be changed for most of the cases but might be useful for some circumvention scenarios.

10

-max-attemps:20

retryMs

If the video is not fully loaded by the time the xPath condition is met; there is a retry mechanism in the snippet. The snippet will try to skip the video once every -retry-ms interval. This parameter doesn't need to be changed for most of the cases. Unit is in milliseconds.

10

-retry-ms:100

-wait-until

Optional parameter that can be used to delay the running of the snippet until the given state is reached. Accepts: loading, interactive, complete, load or any event name. Pass empty string to disable.-wait-until:"" (Snippet will run immediately).

Disabled (snippet runs immediately)

-wait-until:load

-run-once

Used to disable the snippet after it has skipped the video once.

False

-run-once:true

-stop-on-video-end

Used to pause the snippet when the video is already near its end. Video is considered near its end when the difference between the video duration and the current time is less than 0.5 seconds.

False

-stop-on-video-end:true

-start-from

Used to pause the snippet when the video is already near its end. Video is considered near its end when the difference between the video duration and the current time is less than 0.5 seconds.

0

-start-from:1000

-mute-video-when-skipping

Mutes the video when the skipping logic is running.

True

-mute-video-when-skipping:false

skip-video 'video.main-video-player' './/div[contains(@class,"player-container")][contains(@class, "ad"]'

Finds the video player with main-video-player class and skips it to the end whenever the div with player-container class has the class ad attached it.

skip-video 'some-css-selector-to-video' 'xpath-condition-on-when-to-run-skipping' '-run-once:true' '-skip-to:10'

This filter will only skip 10 seconds of the video when the xpath condition first matches.

skip-video 'some-css-selector-to-video' 'xpath-condition-on-when-to-run-skipping' '-wait-until:load' '-stop-on-video-end:true'

This filter will delay the running of the snippet until the page is fully loaded and it will pause the snippet once the video is close to its end. Any number of parameters can be added to customize the snippet.

hide-if-contains-and-matches-style

The hide-if-contains-and-matches-style snippet hides any HTML element (or its ancestors) that matches a CSS selector if the element's text content contains a given string and, optionally, if the element's computed style contains a given string.

You can use this snippet to hide an element based on text content and style.

Parameters

Name
Description
Mandatory

search

The string to look for in HTML elements. If the string begins and ends with a slash (/), the text in between is treated as a regular expression.

Yes

selector

The CSS selector that an HTML element must match for it to be hidden.

Yes

searchSelector

The CSS selector that an HTML element containing the given string must match; defaults to the value of the selector argument.

No

style

The string that the computed style of an HTML element matching selector must contain. If the string begins and ends with a slash (/), the text in between is treated as a regular expression.

No

searchStyle

The string that the computed style of an HTML element matching searchSelector must contain. If the string begins and ends with a slash (/), the text in between is treated as a regular expression.

No

waitUntil

Optional parameter that can be used to delay the running of the snippet until the given state is reached. Accepts: loading, interactive, complete, load or any event name.

No

windowWidthMin

Optional parameter that can be used to disable the snippet if the window.innerWidth is smaller than the given value.

No

windowWidthMax

Optional parameter that can be used to disable the snippet if the window.innerWidth is greater than the given value.

No

Filter examples

The following table lists examples that use the hide-if-contains-and-matches-style snippet:

Filter
Result

hide-if-contains-and-matches-style FAQ nav

Hides any nav element whose text content contains the word FAQ. The word FAQ doesn't need to be found inside the direct children of the nav element; it can be anywhere in its subtree.

hide-if-contains-and-matches-style FAQ nav a

Hides any nav element that has an a element inside its subtree whose text content contains the word FAQ.

hide-if-contains-and-matches-style /.*/ li.serp-item 'li.serp-item div.label'

Hides any li.serp-item element which has an 'li.serp-item div.label' element inside its subtree whose text content matches the /.*/ regex.

hide-if-contains-and-matches-style FAQ nav a 'color: blue'

Hides any nav element that has the color property set to blue and has an a element inside its subtree whose text content contains the word FAQ.

hide-if-contains-and-matches-style FAQ nav a 'color: blue' 'display: inline'

Hides any nav element which has the color property set to blue and has an a element inside its subtree whose text content contains the word FAQ and whose display is set to inline.

hide-if-contains-and-matches-style FAQ nav a /.?/ 'display: inline'

Hides any nav element whose style matches the /.?/ regex and has an a element inside its subtree whose text content contains the word FAQ and whose display is set to inline. The /.?/ regex will match anything, including empty strings.

hide-if-contains

The hide-if-contains snippet hides any HTML element (or its ancestors) that match a CSS selector if the element's text contains a given string.

You can use hide-if-contains to hide elements based on their text content.

Parameters

Name
Description
Mandatory

search

A pattern that matches the name of the cookie(s) you want to remove. If the string starts and ends with a slash (/), the text in between is treated as a regular expression.

Yes

selector

The CSS selector that an HTML element must match for it to be hidden.

Yes

searchSelector

The CSS selector that an HTML element containing the given string must match. Defaults to the value of the selector argument.

No

Filter examples

The following table lists examples that use the hide-if-contains snippet:

Filter
Result

hide-if-contains FAQ nav

Hides any nav element whose text content contains the word FAQ. The word FAQ doesn't need to be found inside the direct children of the nav element; it can be anywhere in its subtree.

hide-if-contains FAQ nav a

Hides any nav element that has an a element inside its subtree whose text content contains the word FAQ.

hide-if-contains /.*/ li.serp-item 'li.serp-item div.label'

Hides any li.serp-item element that has an 'li.serp-item div.label' element inside its subtree whose text content matches the /.*/ regular expression.

hide-if-contains-image

The hide-if-contains-image snippet hides any HTML element (or its ancestors) that match a CSS selector if they element background image matches a given pattern.

You can use hide-if-contains-image to hide elements based on a background image or the background image of any child element.

Parameters

Name
Description
Mandatory

search

The pattern to look for in the background images of HTML elements. This must be the hexadecimal representation of the image data for which to look. If the string begins and ends with a slash (/), the text in between is treated as a regular expression.

Yes

selector

The CSS selector that an HTML element must match for it to be hidden.

Yes

searchSelector

The CSS selector that an HTML element containing the given pattern must match. Defaults to the value of the selector argument.

No

Filter examples

The following table lists examples that use the hide-if-contains snippet:

Filter
Result

hide-if-contains-image ffd8ffe1001845 div

Hides any div element whose background-image's hex matches the ffd8ffe1001845 pattern.

hide-if-contains-image /^ffd8ffe1001845/ div

Hides any div element whose background-image's hex matches the /^ffd8ffe1001845/ pattern.

hide-if-contains-image ffd8ffe1001845 .container div

Hides any .container element that has a div element whose background-image's hex matches the ffd8ffe1001845 pattern.

hide-if-has-and-matches-style

The hide-if-has-and-matches-style snippet hides any HTML element (or its ancestors) that matches a CSS selector if a descendant of the element matches a given CSS selector and, optionally, if the element's computed style contains a given string.

This snippet has multiple uses, including the following:

  • Hiding an optional element given its style

  • Hiding an element's ancestor, optionally, giving its style

Ancestor hiding proves useful due to the lack of a CSS parent selector in browsers.

Parameters

Name
Description
Mandatory

search

The CSS selector against which to match the descendants of HTML elements.

Yes

selector

The CSS selector that an HTML element must match for it to be hidden.

Yes

searchSelector

The CSS selector that an HTML element containing the specified descendants must match; defaults to the value of the selector argument.

No

style

The string that the computed style of an HTML element matching selector must contain. If the string begins and ends with a slash (/), the text in between is treated as a regular expression.

No

searchStyle

The string that the computed style of an HTML element matching searchSelector must contain. If the string begins and ends with a slash (/), the text in between is treated as a regular expression.

No

waitUntil

Optional parameter that can be used to delay the running of the snippet until the given state is reached. Accepts: loading, interactive, complete, load or any event name.

No

windowWidthMin

Optional parameter that can be used to disable the snippet if the window.innerWidth is smaller than the given value.

No

windowWidthMax

Optional parameter that can be used to disable the snippet if the window.innerWidth is greater than the given value.

No

Filter examples

The following table lists examples that use the hide-if-has-and-matches-style snippet:

Filter
Result

hide-if-has-and-matches-style span.social-media-toolbar div

Hides any div element that has a span.social-media-toolbar element in its subtree.

hide-if-has-and-matches-style span.social-media-toolbar div nav

Hides any div element that has a nav element in its subtree with a span.social-media-toolbar in its subtree.

hide-if-has-and-matches-style span.social-media-toolbar div nav 'color: blue'

Hides any div element that has the color property set to blue and has a nav element in its subtree with a span.social-media-toolbar in its subtree.

hide-if-has-and-matches-style span.social-media-toolbar div nav 'color: blue' 'display: inline'

Hides any div element that has the color property set to blue and has a nav element in its subtree that has its display property set to inline and a span.social-media-toolbar in its subtree.

hide-if-has-and-matches-style span.social-media-toolbar div nav /.?/ 'display: inline'

Hides any div element whose style matches the /.?/ regex and has a nav element in its subtree and has its display property set to inline and has a span.social-media-toolbar in its subtree. The /.?/ regular expression will match anything, including empty strings.

hide-if-matches-computed-xpath

The hide-if-matches-computed-xpath hides specific element whose class name or ID changes in runtime through a dynamically-built XPath query.

This snippet takes as a first parameter an XPath selector that's incomplete, due to a placeholder in the form {{}}. The next parameters, searchQuery and searchRegex, tell the snippet how to fill the placeholder.

You can use hide-if-matches-computed-xpath to:

  • Hide elements whose classes or IDs are randomized when a page refreshes

  • Hide elements that write flexible queries to take stylesheets, inline scripts, and regex into account

  • Hide elements that change at runtime

Always use double quotes instead of single quotes inside selectors. Though both are valid, eyeo uses single-quotes to enclose the selector as part of the filter syntax.

Parameters

Name
Description
Mandatory

query

The template XPath query that targets the element to hide. Use {{}} to dynamically insert into the query.

Yes

searchQuery

The XPath query that searches for an element to be used alongside searchRegex.

Yes

searchRegex

The regular expression used to extract text from the innerHTML of the element that matches searchQuery. The extracted text gets injected into the query.

Yes

waitUntil

An optional parameter that can be used to delay the running of the snippet until the given state is reached. Accepts loading, interactive, complete, load or any event name.

No

Filter examples

The following table lists examples that use the hide-if-contains-and-matches-style snippet:

Filter
Result

hide-if-matches-computed-xpath '//[@class="{{}}"]' '//div[@id="target"]' '/./'

Hides all elements with a class whose name matches any string in the div with an id="target".

hide-if-matches-computed-xpath '//[@class="{{}}"]/child::text()[contains(.,"Sponsored")]' '//div[@id="target"]' '/./'

Hides all elements that contain the text Sponsored with a class whose name matches any string in the div with an id="target".

hide-if-matches-computed-xpath '//[@class="{{}}"]/child::text()[contains(.,"Sponsored")]' '//div[@id="target"]' '/test(.)test/' interactive

Hides all elements that:

  • contain the text Sponsored

  • with a class whose name matches any string that starts with test, followed by any sequence of characters

  • end with test in the div with an id="target"

This filter runs when the document state is interactive.

Debugging

Message
When the error occurs
Definition

No query or searchQuery provided

Right after the snippet fires

Mandatory parameters are missing; double check your filter.

Started searching for <<searchQuery>

When the snippet begins to look for the searchQuery

A node is searched for to find the string that matches the regular expression.

Found node: <<searchNode>>

When a node matches the searchQuery

A node element was found that will be used to find the string that matches the regular expression.

Searching in <<searchNode.innerHTML>>

After searchQuery finds a matching node

A node search was matched by the searchQuery for a string that matches the regular expression to fill the XPath query.

Matched search query: <<foundText>>

After comparing the text inside the <<searchNode>> against the regular expression

A string was found that matches the regular expression. This string will be used to fill the XPath query.

Starting hiding elements that match query: <<computedQuery>>

After the placeholder in the XPath query has been replaced with the <<foundText>>

The snippet has filled the placeholder and is looking for HTML elements that match the computed XPath query.

Matched: <<HTML element>> for selector: <<query>>

Right after an HTML element has been matched and hidden

The snippet has successfully matched and hidden a HTML element.

Other resources

hide-if-labelled-by

The hide-if-labelled-by snippet hides any HTML element that uses an aria-labelledby, or one of its ancestors, if the related aria element contains the targeted text.

Use this snippet to hide elements based on searched text.

Parameters

Filter examples

The following table lists examples that use the hide-if-labelled-by snippet:

The following table contains messages you'll find useful during :

Name
Description
Mandatory
Filter
Result
debugging
Getting started with XPath filters
CSS to XPath converter
DevHints XPath cheatsheet

search

The string to look for in HTML elements. If the string begins and ends with a slash (/), the text in between is treated as a regular expression.

Yes

selector

The CSS selector of an HTML element that uses an aria-labelledby attribute.

Yes

searchSelector

The CSS selector of an ancestor of the HTML element that uses an aria-labelledby attribute. Defaults to the value of the selector argument.

No

hide-if-labelled-by 'Sponsored' FAQ nav

Hides any nav element labelled as Sponsored FAQ. The word FAQ doesn't need to be found inside the direct children of the nav element; it can be anywhere in its subtree.

hide-if-labelled-by inline FAQ nav a

Hides any nav element that has an an inline element whose text content contains the word FAQ.

hide-if-contains-visible-text

The hide-if-contains-visible-text snippet hides any HTML element that matches a CSS selector if the element's visible text content contains a given string. It can also check an unlimited amount of CSS attributes of a node to locate a specific string, even when a website employs methods to obscure or conceal the text.

Parameters

Name
Description
Mandatory

search

The string to match against the visible text (text that isn't hidden by CSS properties or other means). If the string begins and ends with a slash (/), the text in between is treated as a regular expression.

Yes

selector

The CSS selector that an HTML element must match for it to be hidden.

Yes

searchSelector

The CSS selector that an HTML element containing the given string must match. Defaults to the value of the selector argument.

No

optionalParameters

The CSS attributes a computed style map of a node should have in order to consider that node hidden. You can provide any number of optional parameters by following these syntax rules:

  • key:value, where can be a string or a regex (if it starts and ends with a /)

  • each parameter is wrapped in single quotes, for example: '-snippet-box-margin:10px' 'width:0px'

No

Default Parameters

In order to tackle common circumvention patterns, the snippet checks already some styles in the matched element, even if you don't add any optional parameter. You can see the default values in the "Default value" column.

Note that you can override the default parameters by adding them as optional parameter, following the syntax rules explained above. You can give any value, the "How to overwrite" column shows only examples. Adjust the values according to your needs.

Name
Description
Default Value
How to overwrite

-snippet-box-margin

Used to expand the bounding box of the overflow parent. This is useful if the website is pushing some elements outside of a overflow:hidden parent. Unit is pixels.

'-snippet-box-margin:2'

'-snippet-box-margin:10'

-disable-bg-color-check

Used to disable the check where we categorize elements with the same text color and background color as "not visible".

'-disable-bg-color-check:false'

'-disable-bg-color-check:true'

-check-is-contained

Used to categorize elements that are pushed outside of a parent even if the parent does not have the style overflow:hidden.

'-check-is-contained:false'

'-check-is-contained:true'

-pseudo-box-margin

Used to set the pseudo elements (:before , :after etc.) translate threshold. Any pseudo elements that have a transform(translate) value higher than this threshold will be counted as invisible. Unit is pixels.

'-pseudo-box-margin:2'

'-pseudo-box-margin:0'

-ignore-padding

Used to sustract the padding values from the calculations when determining if the child element is contained within the parent’s bounding box. To use when it is the padding of a child that makes the text visible.

'-ignore-padding:false'

'-ignore-padding:true'

opacity

Used to check if the gibberish text that scrambles the string we are looking for is contained in a transparent element.

'opacity:0'

'opacity:1'

font-size

Used to check if the gibberish text that scrambles the string we are looking is made invisible by the font-size.

'font-size:0'

'font-size:10'

color

Used to check if the gibberish text that scrambles the string we are looking is made invisible by the font color.

'color:rgba(0, 0, 0, 0)'

'color:rgba(255, 99, 71, 0.6)'

Filter examples

The following table lists examples that use the hide-if-contains-visible-text snippet:

Filter
Result

hide-if-contains-visible-text FAQ nav

Hides any nav element whose visible text content contains the word FAQ. The word FAQ doesn't need to be found inside the direct children of the nav element; it can be anywhere in its subtree.

hide-if-contains-visible-text FAQ nav a

Hides any nav element that has an a element inside its subtree whose visible text content contains the word FAQ.

hide-if-contains-visible-text /.*/ li.serp-item 'li.serp-item div.label'

Hides any li.serp-item element which has an 'li.serp-item div.label' element inside its subtree whose visible text content matches the /.*/ regex.

hide-if-contains-visible-text /.*/ li.serp-item 'li.serp-item div.label' 'color:rgb(255, 255, 255)'

Hides any li.serp-item element which has an li.serp-item div.label element inside its subtree whose visible text content matches the /.*/ regex and whose font color is not white.

hide-if-matches-xpath3

The hide-if-matches-xpath3 hides a specific element through a XPath 3.1 query string.

hide-if-matches-xpath3 requires Browser Ad-Filtering Solution version 117+ with Snippet library version 0.8.1+.

hide-if-matches-xpath3 should be used only when hide-if-matches-xpath is not enough for your use case, because it is slower and, at this point in time, not backward compatible with hide-if-matches-xpath.

Parameters

Name
Description
Mandatory

query

The XPath query that targets the element to hide.

Yes

scopeQuery

XPath selector that the filter devs can use to restrict the scope of the Mutation Observer. It is important that the selector is as specific as possible to avoid to match too many nodes.

No

Filter examples

The following table lists examples that use the hide-if-matches-xpath3 snippet:

Filter
Result

hide-if-matches-xpath3 '//*[@id="sponsored"]'

Hides all elements withid="sponsored".

hide-if-matches-xpath3 '//*[lower-case(text())="sponsored"]'

Hides any element that contains the text "sponsored" in its text content, regardless of the element type or the case (upper or lower) of the text (e.g.: "sPoNSoReD").

hide-if-matches-xpath3 '//div and matches(@class,"Spon(.+)sored")]'

Hides all divs with a class containing a value that matches the regular expression pattern "Spon(.+)sored" (e.g.: "Spon12345sored").

Other resources

hide-if-shadow-contains

The hide-if-shadow-contains snippet hides any HTML element (or one of its ancestors) that matches a CSS selector if the text content of the element's shadow contains a given string.

You can use the hide-if-shadow-contains snippet to hide an element based on its shadow's text.

Parameters

Name
Description
Mandatory

search

The string to look for in every HTML element's shadow. If the string begins and ends with a slash (/), the text in between is treated as a regular expression.

Yes

selector

The CSS selector that an HTML element must match for it to be hidden.

Yes

Filter examples

The following table lists examples that use the hide-if-shadow-contains snippet:

Filter
Result

hide-if-shadow-contains ads nav

Hides any nav element whose shadow's text content contains the word ads.

hide-if-shadow-contains /^[0-9]+$/ .container

Hides any .container element whose shadow's text matches the /^[0-9]+$/ regular expression. (consists in a number)

Other resources

Debugging Snippets

You can use the debug snippet to debug snippet filters. Snippet debugging works by logging messages to the browser's console about the snippet and its current status.

Consider the following example:

example.com#$#debug; log Hello

In this filter, the debug snippet after the domain sets a debugging flag that remains true until the end of the snippets chain. Because you can chain multiple snippets into a single filter, debug affects all snippets in the filter.

For more information, view the debug snippet documentation.

log

The log snippet logs its arguments to the console.

You can use the log snippet for testing and debugging. For example, with the log snippet, you can check filter domain syntax and verify that snippets are executed inside content scripts without errors.

Filter examples

The following table lists examples that use the log snippet:

Filter
Result

log OK

Logs OK to the console.

log Hello, world!

Logs Hello, world! to the console with two parameters.

log `Hello, world!`

Logs Hello, world! to the console with one parameter.

Debugging

In debug mode, the string DEBUG precedes each snippet logged by log.

hide-if-contains-similar-text

The hide-if-contains-similar-text snippet hides any HTML element based on similar text content.

Parameters

Name
Description
Mandatory

search

The string to match to the similar text. The text is considered similar text assuming it's not hidden by CSS properties or other means. If the string begins and ends with a slash (/), the text in between is treated as a regular expression.

Yes

selector

The CSS selector that an HTML element must match for it to be hidden.

Yes

searchSelector

The CSS selector that an HTML element containing the given string must match; defaults to the value of the selector argument.

No

Filter examples

The following table lists examples that use the hide-if-contains-similar-text snippet:

Filter
Result

hide-if-contains-similar-text FAQ nav

Hides any nav element whose similar text content contains the word FAQ. The word FAQ doesn't need to be found inside the direct children of the nav element; it can be anywhere in its subtree.

hide-if-contains-similar-text FAQ nav a

Hides any nav element that has an a element inside its subtree whose similar text content contains the word FAQ.

hide-if-contains-similar-text /.*/ li.serp-item 'li.serp-item div.label'

Hides any li.serp-item element which has an 'li.serp-item div.label' element inside its subtree whose similar text content matches the /.*/ regex.

hide-if-matches-xpath

The hide-if-matches-xpath snippet hides specific elements through an XPath 1.0 query string.

You can use the hide-if-matches-xpath snippet to hide an element based on its children or siblings. This snippet also lets you use flexible queries to hide elements.

Parameters

Name
Description
Mandatory

query

The XPath query that targets the element to hide.

Yes

scopeQuery

XPath query that defines the scope of the Mutation Observer. It is crucial for the selector to be as specific as possible to prevent matching an excessive number of nodes. If the scopeQuery fails to find a match, the Mutation Observer will default to being attached to the document.

No

waitUntil

Optional parameter that can be used to delay the running of the snippet until the given state is reached. Accepts: loading, interactive, complete, load or any event name.

No

Filter examples

The following table lists examples that use the hide-if-matches-xpath snippet:

Filter
Result

hide-if-matches-xpath '//*'

Hides all elements.

hide-if-matches-xpath '//*[@id="Ad"]'

Hides the element with the id of Ad.

hide-if-matches-xpath '//*[contains(concat(" ",normalize-space(@class)," ")," ad-container ")]'

Hides all elements with a class named ad-container.

hide-if-matches-xpath '//*[@id="Ad"]' '' complete

Waits until the document state is complete before hiding elements with the id of Ad.

Observations

Always use double-quotes instead of single-quotes inside selectors. While both are valid, eyeo uses single-quotes for enclosing a selector as part of the filter syntax.

Other resources

The log snippet accepts the same arguments as the console.log() method. For more information, view .

This snippet uses a pre-sorted for cases where the content has chuffled characters or text.

Getting started with XPath filters
DevHints XPath cheatsheet
CSS to XPath converter
Fonto XPath playground
W3C XPath 3.1 documentation
Getting started with XPath filters
CSS to XPath converter
DevHints XPath cheatsheet
Mozilla's console.log documentation
Levenstein distance
Getting started with XPath filters
CSS to XPath converter
DevHints XPath cheatsheet

profile

The profile snippet activates profile mode, enabling performance monitoring for specific snippets.

When used, it logs an object containing performance data for the monitored snippet.

Rounded values in Firefox

Firefox reduces the precision of timestamps to protect user privacy, which can result in rounded values such as 0 or 1.

To address this, you can adjust the privacy.reduceTimerPrecision setting in about:config:Open Firefox and type about:config in the address bar.Search for privacy.reduceTimerPrecision.Toggle the setting to false.Verify if the duration values now include decimals.

If you continue to see rounded values, you may also want to toggle the privacy.resistFingerprinting setting.

Use cases

The profile snippet is ideal for monitoring the performance of specific snippets. It is particularly useful when combined with behavioral or conditional hiding snippets.

Filter examples

The table below provides examples of filters that use the profile snippet:

Filter
Result

profile; abort-on-property-read atob

Activates profile mode for the abort-on-property-read snippet, logging its performance whether it succeeds or fails.

profile; debug; abort-on-property-read atob

Combines profile mode with debug for enhanced monitoring and debugging.

Snippets Support by Platform

The following table details platform availability for all eyeo snippets.

Snippet
@eyeo/snippets
Adblock Plus
Chromium
Notes

abort-current-inline-script

Supported since before module

3.4.3

Supported

abort-on-property-read

Supported since before module

3.4.1

Supported

abort-on-property-write

Supported since before module

3.4.3

Supported

abort-on-iframe-property-read

0.1.1

3.10.1

Supported

abort-on-iframe-property-write

0.1.1

3.10.1

Supported

array-override

1.7.0

4.8

Supported

blob-override

2.2.0

next release

Supported

cookie-remover

0.2.0

3.11.2

Supported

event-override

2.2.0

next release

Supported

freeze-element

0.1.0

3.10

Supported

json-override

0.2.0

3.11.2

Supported

json-prune

Supported since before module

3.9.0

Supported

override-property-read

Supported since before module

3.9.4

Supported

prevent-listener

0.2.0

3.11.2

Supported

replace-fetch-response

1.4.0

4.4

Supported

replace-xhr-response

1.4.0

4.4

Supported

simulate-event-poc

0.2.0

3.11.2

Not supported

simulate-mouse-event

0.6.0

3.17

Supported

strip-fetch-query-parameter

Supported since before module

3.5.1

Supported

hide-if-canvas-contains

1.5.0

4.7

Supported

hide-if-classifies

0.9.0

3.20

Not supported

hide-if-contains

Supported since before module

3.3

Supported

hide-if-contains-image

Supported since before module

3.4.2

Supported

hide-if-contains-similar-text

0.5.2

3.14.2

Supported

hide-if-contains-visible-text

Supported since before module

3.6

Supported

hide-if-contains-and-matches-style

Supported since before module

3.3.2

Supported

hide-if-graph-matches

Supported since before module

3.8

Not supported

hide-if-has-and-matches-style

Supported since before module

3.4.2

Supported

hide-if-labelled-by

Supported since before module

3.9

Supported

hide-if-matches-computed-xpath

0.7.0

3.18.1

Supported

hide-if-matches-xpath

Supported since before module

3.9.0

Supported

hide-if-matches-xpath3

0.8.0

3.19

Supported

hide-if-shadow-contains

Supported since before module

3.3

Supported

skip-video

0.10.0

3.21

Supported

debug

Supported since before module

3.8

Supported

log

Supported since before module

3.3

Supported

trace

Supported since before module

3.3

Supported

race

0.4.0

3.14.1

Supported

Node Highlighting

Element hiding and some snippets can hide content on a page. Debugging such filters can prove tricky, since it's easy to lose track of hidden elements.

Highlight mode modifies the behavior of hiding filters so that they highlight targeted elements instead of hiding them altogether.

Enable highlight mode

Follow these steps to enable highlight mode:

  1. Open the settings page of an extension.

  2. Open the developer console.

  3. Enter and run the following command:

Highlight mode is now enabled.

To disable highlight mode, change the value property to false in the previous command and run it again.

trace

The trace snippet logs arguments in the document rather than in a content script.

You can use the trace snippet for testing and debugging. For example, with the trace snippet, you can verify that snippet injection into a document works without errors.

Filter examples

The following table lists examples that use the trace snippet:

Debugging

In debug mode, the string DEBUG precedes each snippet logged by trace.

This mode uses the to mark key points (like the beginning and end of the main logic in a snippet) and measure the elapsed time between them, expressed in milliseconds (ms).

Deprecated with Removed with

This snippet requires a service worker backend to work properly. Deprecated with Removed with

ML snippet requires a dependency and an appropriate dependency injection logic in the SDK. Deprecated with Removed with

The trace snippet accepts the same arguments as the console.log() method. For more information, view .

Filter
Result
Performance API
Snippets Releases
Adblock and Adblock Plus Releases
browser.runtime.sendMessage({type: "prefs.set", key: "elemhide_debug", value: true});

trace OK

Logs OK to the console.

trace Hello, world!

Logs Hello, world! to the console with two parameters.

trace `Hello, world!`

Logs Hello, world! to the console with one parameter.

@eyeo/snippets v0.6.0
@eyeo/snippets v1.0.0
@eyeo/snippets v2.0.0
@eyeo/snippets v2.0.0
@eyeo/snippets v0.7.0
@eyeo/snippets v0.9.0
Mozilla's console.log documentation

Data collection at eyeo

eyeo’s data collection methods are designed to help us capture insights across our user base while safeguarding individual user privacy.

This guide provides an overview of eyeo’s data collection policies, including our telemetry, collection methods, and the way we use the data we collect.

Telemetry at eyeo

elemetry involves the automated collection of data from eyeo’s platform. At eyeo, telemetry is designed to collect, store, and analyze data from various sources to monitor and enhance platform performance.

Data collection process

eyeo collects telemetry data through pings sent at specific intervals to achieve comprehensive and accurate data capture.

URL data collection

We also collect domain data to understand user interactions while ensuring privacy. eyeo collects this data at the following levels:

  • Domain-level collection: We collect data for every domain that users visit, but not for every URL. Instead, we capture summary data that gives an overview of a user’s visit to a specific domain. Our goal is to understand general patterns without storing detailed browsing histories that could compromise individual privacy.

  • Subdomain-level collection: In some cases, eyeo collects data at the subdomain level to provide finer granularity.

  • Anonymized aggregates: eyeo collects data using techniques that aggregate and anonymize user information. With this approach, individual identities are protected, but we can still gain valuable insights from the data.

Sampling

We implement data sampling techniques to manage data volume and enhance privacy. Initially, 100% of data gets collected to establish a dataset.

Telemetry endpoint

eyeo collects data through secure telemetry endpoints designed to handle large volumes of data efficiently. For our extensions, eyeo collects data through a secure, first-party telemetry endpoint. This endpoint is used for automated ad filtering and data collection.

Security

eyeo implements strict security measures to protect user data throughout the telemetry process. In addition to anonymized aggregation, all collected data is encrypted during transmission and storage to prevent unauthorized access.

How eyeo uses the data we collect

eyeo’s outreach efforts focus on transparency regarding data collection practices. eyeo informs users about the data we collect, as well as our purpose in collecting it. At all times, we emphasize the fact that we anonymize data to protect user privacy.

The data that eyeo collects is vital for enhancing our products and meeting user needs while upholding privacy and security standards. Here’s how we use the collected data:

  • To improve user experience: By analyzing user interactions and behavior across different domains and platforms, we can identify areas for improvement and optimize the user experience. This includes making eyeo’s products more intuitive, responsive, and aligned with user expectations.

  • Product optimization: The insights eyeo gains from telemetry data help us refine our products, optimizing their performance and effectiveness. This includes identifying and resolving issues, enhancing features, and maintaining compatibility across various environments.

  • Security enhancements: Collecting anonymized and aggregated data lets eyeo monitor and improve the security of our products. We can identify potential threats and vulnerabilities, keeping our products secure and reliable for all users.

  • User support: Analyzing telemetry data helps us provide better support to our users. We can quickly identify common issues and provide effective solutions, improving the overall user support experience.

  • Innovation and development: The data eyeo collects guides our research and development efforts, letting us innovate and develop new features that enhance our product offerings. By understanding user needs and behaviors, we can create solutions that are both relevant and impactful.

Today, and in the future, we’re committed to prioritizing privacy, data security, and compliance as fundamental user rights in all our data collection practices.

Working with filters

Adblock Plus comes equipped with several pre-installed filter lists. These filter lists are designed to improve the browsing experience by blocking unwanted content. They include:

  • Acceptable Ads: This list allows certain non-intrusive ads to ensure that websites relying on advertising can still generate revenue.

  • EasyList: The primary filter list that blocks most ads, automatically adjusting based on the user's browser language settings.

  • ABP Anti-circumvention Filter List: Specifically targets and blocks ads that attempt to circumvent ad blockers.

In addition to the pre-installed filter lists, Adblock Plus offers users the ability to create their own custom filters. Custom filters enhance your control over what gets blocked, allowing for a personalized browsing experience.

Creating Filters

Filters in Adblock Plus are categorized into different types, each serving a unique purpose:

  1. Blocking Filters: These are used at the network level to decide whether a request to load certain content should be blocked. They are the first line of defense against unwanted content.

  2. Content Filters: Also known as hiding filters, these are often referred to as element hiding filters. They are used to hide specific elements on a webpage, such as intrusive ad banners or pop-ups.

  3. Exception Filters: These filters are crucial for allowing certain requests or unhiding elements on specific websites. They are used to override other filters based on specific conditions.

Both blocking and hiding filters can be overridden by exception filters, which act as a 'whitelist' under certain conditions.

Follow these steps to create your own filters in Adblock Plus:

  1. Access the Adblock Plus Settings page in your browser.

  2. For versions 3.4 and higher, supporting browsers like Chrome, Edge, Firefox, Opera, and Yandex Browser:

    • Click the Adblock Plus icon and select the gear icon in the upper-right corner.

    • Navigate to the Advanced tab and find 'Create and edit your filter list'.

    • Click 'Start creating my filter list', enter your filter, and hit 'Save'.

Basic Filter Rules

The simplest form of a filter is the address of the request you want to block. However, due to the dynamic nature of web addresses, it is often more effective to use more general filters. For instance, http://example.com/ads/banner*.gif blocks all GIF banners in the ads directory of example.com.

Note: Overusing wildcards can be counterproductive. For example, a filter like http://example.com/* could unintentionally block all content from 'example.com', including necessary website features.

Defining Exception Rules

Exception rules are essential when you find that a filter is blocking something it shouldn't. They allow you to define scenarios where the normal blocking rules should not apply. These rules are similar to regular filter rules and can include wildcards or regular expressions for flexibility.

Example 1: If your filter adv unintentionally blocks http://example.com/advice.html, you can create an exception rule @@advice to allow this specific page.

Example 2: Suppose a filter blocks access to http://example.com/admin. You can create an exception rule @@admin to ensure that this important administrative page remains accessible.

Matching at the Beginning or End of an Address

Adblock Plus generally interprets filters as having implied wildcards at the beginning and end. However, there are instances where you need a filter to match only at the start or end of an address.

Example 1: To block only Flash files and not HTML pages that contain 'swf' in their address, use a filter like swf|. This filter blocks http://example.com/annoyingflash.swf but not http://example.com/swf/index.html.

Example 2: If you wish to block a specific domain but not URLs containing that domain as a parameter, use a filter like |http://baddomain.example/. This filter blocks http://baddomain.example/banner.gif but not http://gooddomain.example/analyze?http://baddomain.example.

Marking Separator Characters

In some scenarios, you might need to allow any separator character in a filter. The caret symbol (^) is used as a placeholder for a single separator character in such cases.

Example: A filter like http://example.com^ effectively blocks both http://example.com/ and http://example.com:8000/, but not http://example.com.ar/.

Comments

Rules that start with exclamation marks (!) are considered comments and are ignored by Adblock Plus during the filtering process. Comments are useful for adding descriptions, notes, or authorship details to your filters.

Advanced Features

Specifying Filter Options

Adblock Plus allows you to specify additional options to modify the behavior of a filter. These options are appended after a dollar sign ($) at the end of the filter and separated by commas.

Example: /ads/*$script,match-case specifies that the filter /ads/* should apply only to scripts and be case-sensitive.

The available options include:

  • Type options: Specify the types of elements a filter can block, such as script, image, stylesheet, and others.

  • Inverse type options: Indicate what types of requests the filter should not apply to, like ~script, ~image, etc.

  • Restriction to third-party/first-party requests: Filters can be restricted to either third-party or first-party requests using third-party or ~third-party.

  • Domain restrictions: Filters can be restricted to specific domains using domain=example.com. You can specify multiple domains or exclude certain domains using ~.

  • Sitekey restrictions: These allow filters to be applied only to pages with a specific public key and signature.

Example: ||example.com/banner.gif$domain=example.com|example.net restricts the filter to example.com and example.net domains.

Content Security Policies

Content Security Policies (CSP) can be set via filters to control the type of content that is allowed to load on a webpage. This feature is crucial in preventing certain types of content from loading, thereby enhancing security and user experience.

Example: The filter option csp=script-src: 'none' injects a CSP header of script-src: 'none' into the matching filter requests, effectively blocking all scripts in the document. This is particularly useful when dealing with advanced ad circumvention techniques.

Redirecting Requests to Internal Resources

The rewrite= option allows you to redirect requests to internal resources, deactivating them without causing errors. This feature is useful for handling requests in a way that doesn’t break page functionality.

Example 1: The filter $rewrite=abp-resource:blank-js sends an empty JavaScript file in place of the original request. This can be used to neutralize JavaScript-based ads or trackers.

Example 2: For an image request, $rewrite=abp-resource:1x1-transparent-gif can replace it with a transparent 1x1 pixel GIF, effectively removing visual ads without affecting layout.

Using Regular Expressions

Adblock Plus supports regular expressions in filters, allowing for more complex and flexible matching patterns. Regular expressions are a powerful tool for creating precise filters.

Example 1: The regex filter /banner\d+/ matches any URL containing 'banner' followed by any digit, such as 'banner123'.

Example 2: To block URLs with specific file names, a regex like /\d{3}banner\.gif/ matches any '.gif' file name that starts with three digits and follows with 'banner'.

Special Comments

Special comments in Adblock Plus are used in downloaded filter lists to set parameters like the homepage, title, update interval, and version. These comments do not affect the actual blocking behavior but provide meta-information about the filter list.

Example: A comment like ! Expires: 5 days sets the update interval for the filter list to 5 days, ensuring the list is regularly updated for effectiveness.

Content Filters

Content filters are crucial for dealing with ads embedded as text in webpages. They include element hiding and snippet filters, which target specific elements or run code snippets to block complex ads.

Element Hiding Filters:

  • Basic Rules: Element hiding filters use CSS selectors to hide elements. They follow the structure <domains><separator><body>.

  • Limiting Rules to Certain Domains: You can specify domains to restrict the application of these rules.

  • Attribute Selectors: These are used when ads don’t have distinct IDs or classes. For example, ##div[title*="adv"] hides divs with titles containing 'adv'.

Snippet Filters:

  • Implementation: They allow running JavaScript code snippets on specified domains.

  • Example: A snippet filter like example.com#$#snippet would run the 'snippet' code on pages from 'example.com'.

Exception Rules:

  • Usage: These are used to deactivate existing rules on particular domains.

  • Example: The rule example.com#@#.textad deactivates the hiding rule for elements with class 'textad' on 'example.com'.

Accessing shadow DOM elements

How to access shadow DOM elements

Shadow DOM elements are elements that are isolated from the main DOM of the web page: instead of being part of the main document subtree, they belong to a document fragment which is just another subtree of nodes that are not as vulnerable to scripts (and styles) as normal DOM nodes are.

We can see and inspect them in the browser but we cannot reach them by writing a normal selector.

We are currently able to tackle:

  • svg-use pattern: another encapsulating pattern used by CV providers. In SVG, the element is used to reference and reuse existing elements defined elsewhere in the document, whose id matches the value stored in the href or xlink:href attribute.

The demarcators

The following snippets can handle the new demarcators:

  • hide-if-contains

  • hide-if-contains-image

  • hide-if-contains-similar-text

  • hide-if-contains-visible-text (^^sh^^ only, does NOT support ^^svg^^)

  • hide-if-contains-and-matches-style

  • hide-if-has-and-matches-style (currently only in selector and searchSelector params, not in the search parameter!)

  • hide-if-labelled-by

  • simulate-mouse-event

The blank spaces around the demarcators are irrelevant and will be ignored: "div.shadowRootParent ^^sh^^ span.childNode" will be behave the same as "div.shadowRootParent^^sh^^span.childNode". In this document the demarcators are surround by blank spaces for readability's sake. More than one demarcator can be used in the same selector, in order to access nested encapsulated elements.

type of encapsulation
demarcator
selector example
how it works

open or closed shadow root

^^sh^^

.shadowRootParent ^^sh^^ span.childNode

svg-use pattern

^^svg^^

.shadowRootParent ^^svg^^

The 1st part of the query before the demarcator is executed, which will likely point to a element. The value of the xlink:href or href attribute is extracted from the found element and it is used to find the matching original element by its id. The referenced ids until no more demarcators are found in the selector.

Browser compatibility

While all our snippets are supported from Chrome 77+ or Opera 64+, keep in mind that snippets that use the new demarcator for the shadow root (^^sh^^) will work only from Chrome 88+ and Opera 74+, because we rely on an API that was introduced with Chrome 88 / Opera 74.

Since the API we use to access shadow-roots is available only for extensions, the ^^sh^^ demarcator won't work on Chromium-based browsers.

Even though the snippet filters using the new ^^sh^^ demarcator are expected to fail in older browsers and Chromium browsers, no breakage, visible errors or disruptive behaviors are expected. The filters will fail silently without interfering with the user experience.

No limitations have been observed on our oldest supported Firefox version, Firefox 68.

How to write filters

Shadow roots

Write your CSS selector as usual: the first part of the selector should target the closest shadow root parent in the light DOM, then use the demarcator ^^sh^^ and continue by adding any other reference to nodes inside the shadow root.

1. Simple shadow root example:

<div class="myDiv">
   #shadow-root (closed)
  <span id="sponsored">Sponsored</span>
</div>

Filter example:

example.com#$#hide-if-contains /Sponsored/ '.myDiv' '.myDiv ^^sh^^ #sponsored'

2. Nested shadow root example:

<div class="myDiv">
    #shadow-root (closed)
        <span class="mySpan">
            #shadow-root (closed)
                <span id="sponsored">Sponsored</span>
        </span>
</div>

Filter example:

example.com#$#hide-if-contains /Sponsored/ '.myDiv' '.myDiv ^^sh^^ .mySpan ^^sh^^ #sponsored'

Svg-use pattern

The first part of the selector will always point to the parent of the enclosed DOM element (i.e.: to the <use> element).

When entering the ^^svg^^ the snippet will take care of finding the original content by the id referenced in or , which in the following example is <text>, so further selectors are needed after ^^svg^^

1. Simple svg-use:

<svg>
    <text id="sponsored">Sponsored</text>
</svg>
 
<div class="myDiv">
    <svg class="mySvg">
        <use href="#sponsored">
            #shadow-root (user-agent)
                <text id="sponsored">Sponsored</text>
        </use>
    </svg>
</div>

Filter example:

example.com#$#hide-if-contains /Sponsored/ '.myDiv' '.myDiv .mySvg use ^^svg^^'

2. Referenced element has children:

In this case the "Sponsored" string lives in a child of the referenced element, so after the ^^svg^^ demarcator we add the the selector to target the subtree element that hosts the string we are looking for.

<svg>
    <text id="sponsored">
        <tspan>Sponsored</tspan>
    </text>
</svg>
 
<div class="myDiv">
    <svg class="mySvg">
        <use href="#sponsored">
            #shadow-root (user-agent)
                <text id="sponsored">
                    <tspan>Sponsored</tspan>
                </text>
        </use>
    </svg>
</div>

Filter example:

example.com#$#hide-if-contains /Sponsored/ '.myDiv' '.myDiv .mySvg use ^^svg^^ tspan'

3. Nested <use> elements:

More than one ^^svg^^ demarcator can be used in the same selector, allowing to follow a series of nested <use> tags.

<svg>
    <text id="sponsored">Sponsored</text>
</svg>
<svg>
    <use id="nested-sponsored" href="#sponsored">
        #shadow-root (user-agent)
            <text id="sponsored">Sponsored</text>
    </use>
</svg>
 
 
<div class="myDiv">
    <svg class="mySvg">
        <use href="#nested-sponsored">
            #shadow-root (user-agent)
                 <use id="nested-sponsored" href="sponsored">
                      #shadow-root (user-agent)
                          <text id="sponsored">Sponsored</text>
                 </use>
        </use>
    </svg>
</div>

Filter example:

example.com#$#hide-if-contains /Sponsored/ '.myDiv' '.myDiv .mySvg use ^^svg^^ ^^svg^^'

debug

The debug snippet enables debug mode for all snippets that follow the debug snippet in the filter's snippet chain.

Filter examples

The following table lists examples that use the debug snippet:

For snippet-specific debugging information, view the debugging section of the snippet's documentation.

race

A race condition can occur between competing snippets, like snippets based on the same environment, or snippets that signal a winning strategy but can also stop executing.

Parameters

Filter examples

Other resources

open or closed shadow roots (see paragraph about browser compatibility below): they are created by calling the DOM API or via . CV providers can use shadow roots to hide the elements that distinguish the sponsored content from the non-sponsored content.

The selector is split at the demarcator. The first part of the query is executed. This leads to the shadow root parent. Then the shadow root is accessed with . At this point nodes inside the shadow root are targeted by using the second part of the selector.

View for more information.

Filter
Result

Only are raceable.

Name
Description
Mandatory
Filter
Result

element.attachShadow
declarative shadow DOM

debug; log OK

Logs OK to the console; preceded by the string debug.

debug; abort-on-property-read atob

Activates debug mode for the abort-on-property-read snippet.

race start;

Begins a race, passing an arbitrary amount of winners which, by default, is 1.

Yes

race stop;

Stops a race.

Yes

!# snippet, another, first, second example.com#$#race start; snippet 1 2 3; other 4 5 6; another 7 8 9; race stop; example.com#$#race start 2; first 1; second 2; third 3; fourth 4; race stop;

A snippet wins the race, and all others are flagged as losers. A registered callback to stop losing snippets from executing is then invoked.

Debugging Snippets
Conditional Hiding Snippets
this specific API
Racing snippets: a PoC around competing snippets with N amount of possible winners
Highlight mode enabled in the extension
Multiple domains using the same sitekey
Server-side flow for sitekey generation
Browser-side handling of sitekeys
Parts of a snippet
Adding a filter to the My filter list field
Acceptable Ads explained during onboarding
Acceptable Ads on the Settings UI
Parts of a snippet
A screenshot of Acceptable Ads being shown during an onboarding page
A screenshot of Acceptable Ads being shown in a browser's ad-filtering settings