In the previous section, you've learned how to configure ad-filtering. But the underlying filtering engine is more capable.
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
As long as you can express the filtering demands via the filtering language, you can probably use the Browser Ad-Filtering Solution to implement the behavior.
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
These settings are stored persistently in Preferences.
The default, ad-filtering configuration
These parameters are very similar to the ones you encountered in the previous section. In fact, the ad-filtering settings are implemented as a filtering configuration - with the name adblock. It is created by default in the Solution.
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.
importorg.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")
If you have FilteringConfirutation object for removed configuration, it becomes invalid. Any method called on a removed configuration will throw an IllegalStateException.
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:
importorg.chromium.components.adblock.FilteringConfiguration;// myConfiguration created by previous example.myConfiguration.isEnabled(); // truemyConfiguration.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(); // truemy_configuration->SetEnabled(false);my_configuration->IsEnabled(); // false
Add/Remove filter list
Filter lists are identified by URLs from which they are downloaded.
When you add a new filter list, a download starts, the list is then converted and installed. When you remove a filter list, it is uninstalled and removed from disk.
All changes to the filter lists configuration happen immediately, synchronously. The actual installation is asynchronous. You may observe installation progress separately.
// "my_configuration" created by previous example.// Without promises:chrome.eyeoFilteringPrivate.getFilterLists('my_configuration',function(subscriptions) {// subscriptions == [] });// With promises:constfilterList='http://filters.com/list.txt';awaitchrome.eyeoFilteringPrivate.subscribeToFilterList('my_configuration', filterList).then( () => {chrome.eyeoFilteringPrivate.getFilterLists('my_configuration').then( subscriptions => {// subscriptions = ['http://filters.com/list.txt'] })});awaitchrome.eyeoFilteringPrivate.unsubscribeFromFilterList('my_configuration', filterList).then( () => {chrome.eyeoFilteringPrivate.getFilterLists('my_configuration').then( subscriptions => {// subscriptions = [] })});
#include"components/adblock/core/configuration/filtering_configuration.h"FilteringConfiguration* my_configuration = ...; // Created or retrieved by previous examples.std::vector<GURL> filter_lists =my_configuration->GetFilterLists();// filter_lists == []constGURLfilter_list("http://filters.com/list.txt");my_configuration->AddFilterList(filter_list);filter_lists =my_configuration->GetFilterLists();// filter_lists == ["http://filters.com/list.txt"]my_configuration->RemoveFilterList(filter_list);filter_lists =my_configuration->GetFilterLists();// 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.
importorg.chromium.components.adblock.FilteringConfiguration;publicclassMySubscriptionUpdateObserverimplementsFilteringConfiguration.SubscriptionUpdateObserver { @OverridepublicvoidonSubscriptionDownloaded(finalURL url) {// url == "http://filters.com/list.txt" }}MySubscriptionUpdateObserver observer =newMySubscriptionUpdateObserver();// myConfiguration created by previous example.myConfiguration.addSubscriptionUpdateObserver(observer);URL filterList =newURL("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.constfilterList='http://filters.com/list.txt';chrome.eyeoFilteringPrivate.onSubscriptionUpdated.addListener(function(url) {// url == 'http://filters.com/list.txt'});awaitchrome.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"classObserver:public SubscriptionService::SubscriptionObserver {public:voidOnSubscriptionInstalled(constGURL& 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);constGURLfilter_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.
importorg.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.constallowed_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
Custom filters are filters that are not present on any of the installed filter list but are added individually, via the following API. The Browser Ad-Filtering Solution treats custom filters the same way as ordinary filters.
importorg.chromium.components.adblock.FilteringConfiguration;// Filter that allows every resource from trusted.org or its subdomains.String filter ="@@||trusted.org";// myConfiguration created by previous example.myConfiguration.addCustomFilter(filter);List<String> customFilters =myConfiguration.getCustomFilters();// customFilters = ["@@||trusted.org"]
// Filter that allows every resource from trusted.org or its subdomains.constfilter='@@||trusted.org';// "my_configuration" created by previous example.chrome.eyeoFilteringPrivate.addCustomFilter('my_configuration', filter);chrome.eyeoFilteringPrivate.getCustomFilters('my_configuration',function(filters) {// filters == ['@@||trusted.org'] });
#include"components/adblock/core/configuration/filtering_configuration.h"FilteringConfiguration* my_configuration = ...; // Created or retrieved by previous examples.const std::string filter ="@@||trusted.org";my_configuration->AddCustomFilter(filter);std::vector<std::string> custom_filters =my_configuration->GetCustomFilters();// custom_filters = ["@@||trusted.org"]
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:
importorg.chromium.components.adblock.FilteringConfiguration;publicclassMyConfigurationChangeObserverimplementsFilteringConfiguration.ConfigurationChangeObserver { @OverridepublicvoidonEnabledStateChanged() {// runs when someone calls setEnabled() to set a new state } @OverridepublicvoidonFilterListsChanged() {// runs when someone adds or removes filter lists } @OverridepublicvoidonAllowedDomainsChanged() {// runs when someone adds or removes allowed domains } @OverridepublicvoidonCustomFiltersChanged() {// runs when someone adds or removes custom filters }}MyConfigurationChangeObserver observer =newMyConfigurationChangeObserver();// myConfiguration created by previous example.myConfiguration.addObserver(observer);URL filterList =newURL("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 });constfilterList='http://filters.com/list.txt';awaitchrome.eyeoFilteringPrivate.subscribeToFilterList('my_configuration', filterList);// the second listener is called
#include"components/adblock/core/configuration/filtering_configuration.h"classObserver:public FilteringConfiguration::Observer {public:voidOnEnabledStateChanged(FilteringConfiguration* config) override { // runs when someone calls SetEnabled() to set a new state }voidOnFilterListsChanged(FilteringConfiguration* config) override { // runs when someone adds or removes filter lists }voidOnAllowedDomainsChanged(FilteringConfiguration* config) override { // runs when someone adds or removes allowed domains }voidOnCustomFiltersChanged(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);constGURLfilter_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.
importorg.chromium.components.adblock.ResourceClassificationNotifier;publicclassMyClassificationObserverimplementsResourceClassificationNotifier.AdBlockedObserver { @OverridepublicvoidonAdAllowed(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. } @OverridepublicvoidonAdBlocked(AdblockCounters.ResourceInfo info) {// Runs when a resource is blocked by a blocking filter// from at least one enabled filtering configuration. } @OverridepublicvoidonPageAllowed(AdblockCounters.ResourceInfo info) {// Runs when every enabled filtering configuration exempts// this domain from filtering via allowed domains. } @OverridepublicvoidonPopupAllowed(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. } @OverridepublicvoidonPopupBlocked(AdblockCounters.ResourceInfo info) {// Runs when a popup window is blocked by a blocking filter// from at least one enabled filtering configuration. }}MyClassificationObserver observer =newMyClassificationObserver();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"classMyClassificationObserver:public ResourceClassificationRunner::Observer {public:voidvoidOnAdMatched(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. } }voidvoidOnPageAllowed(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. }voidvoidOnPopupMatched(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);