Adblocker
Efficient
· Minimal
· JavaScript
· TypeScript
· uBlock Origin- and Easylist-compatible
Node.js
· Puppeteer
· Electron
· WebExtension
Getting Started
Install: npm install --save @cliqz/adblocker
.
Usage
There are multiple ways you can create an instance of the blocking engine to
start blocking ads:
If you already have filters locally:
import { FiltersEngine } from '@cliqz/adblocker';
const engine = FiltersEngine.parse(fs.readFileSync('easylist.txt', 'utf-8'));
Fetching lists from URLs:
import { FiltersEngine } from '@cliqz/adblocker';
engine = await FiltersEngine.fromLists(fetch, [
'https://easylist.to/easylist/easylist.txt'
]);
Use ready-made configs to block ads and optionally trackers:
import { FiltersEngine } from '@cliqz/adblocker';
engine = await FiltersEngine.fromPrebuiltAdsOnly(fetch);
engine = await FiltersEngine.fromPrebuiltAdsAndTracking(fetch);
Once you have your engine
, start matching requests and block ads:
import { Request } from '@cliqz/adblocker';
const { match } = engine.match(Request.fromRawDetails({
type: 'script',
url: 'https://domain.com/ads.js',
}));
Request Abstraction
To abstract over network requests independently from platforms (Node.js,
WebExtension, etc.), the Request
provides a unified APIs and helpers functions
for initialization on different platforms:
import { Request } from '@cliqz/adblocker';
const request = Request.fromRawDetails({
url: 'https://sub.example.com',
type: 'main_frame',
});
console.log(request.isMainFrame());
console.log(request.url);
console.log(request.hostname);
console.log(request.domain);
Manipulating Individual Filters
Content blockers usually manipulate two kinds of filters: network
and cosmetics. The former allows to specify which network requests
should be blocked (or redirected), usually from the WebRequest
API of
extensions. The later allows to alter the DOM of pages directly, hiding
elements or injecting scripts.
Network Filters
Here is how one can parse and match individual network filters using
the NetworkFilter class. It offers multiple
accessors and helpers to parse, match and manipulate network filters.
import { NetworkFilter } from '@cliqz/adblocker';
const filter = NetworkFilter.parse('||domain.com/ads.js$script');
console.log(filter.isHostnameAnchor());
console.log(filter.getHostname());
console.log(filter.getFilter());
console.log(filter.fromScript());
console.log(filter.fromImage());
Matching network filter against requests:
import { Request } from '@cliqz/adblocker';
const request = Request.fromRawDetails({
type: 'script',
url: 'https://sub.domain.com/ads.js?param=42',
sourceUrl: 'https://frame-domain.com',
});
console.log(filter.match(request));
Cosmetic Filters
Similarly, one can parse cosmetic filters using the CosmeticFilter class.
const { CosmeticFilter } = require('@cliqz/adblocker');
const filter = CosmeticFilter.parse('domain.*,domain2.com###selector');
console.log(filter.hasHostnameConstraint());
console.log(filter.getSelector());
console.log(filter.isUnhide());
filter.match('sub.domain.com', 'domain.com');
Filters Engine
Manipulating filters at a low level is useful to build tooling or
debugging, but they are not appropriate for efficient blocking of
requests (it would require iterating on all the filters to know if
a request needs to be blocked). Instead, we can make use of the
FiltersEngine class which can be seen as a "container" for both
network and cosmetic filters. The filters are organized in a very
compact way which also enables fast matching.
import { FiltersEngine, NetworkFilter, CosmeticFilter, Request } from '@cliqz/adblocker';
let engine = FiltersEngine.parse(`
! This is a custom list
||domain.com/ads.js$script
###selector
domain.com,entity.*##+js(script,args1)
`);
Updating an existing engine with new filters:
engine.update({
newNetworkFilters: [NetworkFilter.parse('/ads.js')]
newCosmeticFilters: [CosmeticFilter.parse('###selector')],
});
Serializing an engine to Uint8Array
and reloading it to its original form:
const serialized = engine.serialize();
engine = FiltersEngine.deserialize(serialized);
Matching requests:
const {
match,
redirect,
exception,
filter,
} = engine.match(Request.fromRawDetails({
type: 'script',
url: 'https://sub.domain.com/ads.js',
}));
Checking for CSP injection rules for a given frame:
const directives = engine.getCSPDirectives(Request.fromRawDetails({
type: 'main_frame',
url: 'https://sub.domain.com/',
}));
Checking for cosmetics injection:
const {
styles,
scripts,
} = engine.getCosmeticsFilters({
url: 'https://sub.domain.com/path',
hostname: 'sub.domain.com',
domain: 'domain.com',
});