Feature
Tracker blocking and link cleaning
- 40
- Tracking parameters stripped
- 4
- Tracker lists shipped
- 3
- Rule sets in the profile extension
- This computer only
- Where the counters live
Blocking happens in the network stack, not inside the page
Every profile does the same two jobs. It refuses requests to tracker hosts, and it cuts tracking parameters out of the addresses you navigate to. How that is carried out depends on which engine the profile runs.
On ARMANOS Browser the app writes a small extension into the profile folder at launch and loads it with --load-extension. Its rules are declarativeNetRequest rules, so a match is decided inside the network stack. Nothing appears in the page for a site to notice, and no request travels back to the app for a verdict.
The built-in Electron engine has no such road, so the app does the work in its own process. A matching request is cancelled in session.webRequest.onBeforeRequest, and an address that can be cleaned is redirected to its clean form.
Both roads compile from one function, buildBlocker in tracker-rules.js. That is deliberate. Protection was originally written against Electron alone, so when ARMANOS Browser became the default engine it delivered the fingerprint and nothing else, and the Protection screen sat at zero forever.
A profile that cannot be protected does not open
Four lists ship with the app, and the use case decides which apply
The general list holds 31 entries and goes to every use case. It is analytics, product measurement, crash reporting and session replay: google-analytics.com, googletagmanager.com, doubleclick.net, app-measurement.com, sentry.io, hotjar.com, fullstory.com, appsflyer.com and their neighbours.
The other three are use case specific and merge into the general one. A Privacy profile ends up with 31 unique entries, a Social profile with 74, an Ad accounts profile with 56. Nothing is loaded that the scenario did not ask for: an unknown list name is refused and named in the log instead of silently loading nothing.
The ads list is the most restrained on purpose. Every host an ad console needs to sign in, load, upload creatives, bill or answer its own API is deliberately absent, and so is every host that answers a top level navigation. A rule that fires inside the console you are paid to run is a business risk, not protection.
One entry can be matched three ways. A bare host matches that host and its subdomains. An entry containing a slash matches as a substring of the whole address. An entry starting with a double slash is anchored at the start of the authority, which is how log.pinterest.com is blocked without touching the real blog.pinterest.com.
| List | Entries | Goes to | What it holds |
|---|---|---|---|
| general | 31 | every use case | analytics, crash reporting, session replay, mobile attribution |
| 23 | Work, Social | LinkedIn ad and analytics hosts, the insight tag, tr.lnkd.in | |
| social | 33 | Social | Meta, TikTok, X, Pinterest, Snapchat and Reddit pixels |
| ads | 25 | Ad accounts | conversion and audience endpoints, data brokers |
A platform watching you with its own requests needs path rules
A domain list catches other people's counters. It cannot catch the platform itself, because those calls go to the very site you came to, from its own address. For that there are separate sets of rules matched against the path.
The LinkedIn set covers /li/track, /px/, /li/fta, /csp/fta and the profile view endpoint. Two of its rules are query scoped: a messaging conversation call is dropped only when it carries seen or typing, and a search call only when it carries track, analytics or impression.
The social set covers Meta, X and Pinterest. Two Meta entries earn their place above all the others: facebook.com/ig_xsite_user_ and instagram.com/accounts/xuserid are the cross app identity handshake that ties a Facebook account to an Instagram one, and they fire on a plain page load of either site.
Every set is locked to its own hosts, and that is not tidiness. The LinkedIn set contains the bare words beacon, telemetry and /px/. Applied everywhere, a LinkedIn profile had an unrelated shop's /assets/beacon.js and a news site's /px/ image blocked with no explanation, so a scenario now gets only the rules that were tested against it.
LinkedIn set
/li/track, /px/, /li/fta, /csp/fta, /voyager/api/identity/profileView, viewedEntity. Fires only on linkedin.com and licdn.com.
Social set
/ajax/bz, /logging_client_events, /cavalry_endpoint.php, instagram.com/logging/, /i/jot, /1.1/attribution, pinterest.com/_/_/trace/. Fires only on those platforms' own hosts.
Ad consoles
No bare path rules at all. Only host plus needle pairs, such as ads.google.com together with /gen_204, /jserror or /csi_204.
Link cleaning removes 40 parameters before the page sees them
All six use cases have link cleaning switched on. The parameter names live in one shared list, so both engines strip exactly the same set and cannot drift apart.
On the built-in engine a main frame request is passed through cleanUrl. If anything was removed, the request is redirected to the clean address and the Links cleaned counter goes up. On ARMANOS Browser it is one declarativeNetRequest redirect rule with a query transform that removes those names from main frame and sub frame navigations.
Doing it in the network stack rather than in a redirect loop matters for what you see: the address bar shows the clean address, and the parameter never reaches the page at all.
The click identifiers are the whole point. The list once carried fbclid without its siblings, so a TikTok or an X click id survived cleaning and carried exactly the correlation that cleaning exists to cut. Eleven more were added for the platforms the social and ad use cases cover.
- Ad click ids
- fbclid, gclid, msclkid, dclid, ttclid, twclid, wbraid, gbraid, yclid, rdt_cid, ScCid, epik
- Campaign tags
- utm_source, utm_medium, utm_campaign, utm_content, utm_term, mc_cid, mc_eid
- Session and profile ids
- _ga, _gl, igshid, mibextid, li_fat_id
- LinkedIn trail
- trk, trkInfo, lipi, lici, trackingId, refId, midToken, midSig, trkEmail
Cleaning applies to navigations, not to every sub-resource a page loads afterwards.
Two kinds of tracking no request filter can see
Two things are structurally out of reach for any network rule. navigator.sendBeacon fires on unload and the payload is the tracking itself. WebSocket frames are opaque to a filter that only reads addresses.
Where the use case asks for it, a script running in the page's own world replaces both. sendBeacon reports the event and returns true, so the page believes it succeeded. WebSocket.send drops payloads shorter than 500 characters that name TYPING, READ_RECEIPT or SEEN, so typing indicators and read receipts stop leaving while the rest of the socket carries on.
A replacement has to look like the built-in it replaced. The name and the length are copied from the original, and one shared toString hides all of them, including itself. Measured against the shipped engine, sendBeacon.length is 1 and not the 2 the specification implies, which is why the number is copied rather than written down.
The two halves talk over a CustomEvent on a random name chosen per launch. It used to be window.postMessage, which handed a payload naming the product to every page with an ordinary message listener, and let a page forge counts of its own.
Beacons
sendBeacon is suppressed in the stealth scenarios and counted separately from network blocks.
Read receipts and typing
the message privacy scenarios drop those frames; nothing else on the socket is touched.
Nothing names the product
the page half and the extension half share a per launch random event name that a site cannot guess.
The counters are collected on your computer and stay there
On ARMANOS Browser the extension's service worker listens for rule matches, maps the ruleset that fired (block, telemetry or params) to a category, batches for 500 milliseconds and posts the batch to a loopback address on 127.0.0.1 with a random per profile token. It never leaves the machine.
Keeping that worker alive is what makes counting work at all. An MV3 worker is torn down between events, and matches are only observed while it runs. Measured, every counter came back zero for an hour of browsing while the blocking itself worked perfectly. A port held open by the top frame keeps the worker resident while a page is open.
The app treats those reports as local input rather than truth. Each batch is clamped, and only five categories are accepted. The numbers go into stats.json in the app data folder, keyed per day and per profile, with 14 days of history, and the file is written at most once a second so a busy page cannot turn counting into a performance problem.
The Protection screen shows today, the last 7 days, the total, a breakdown by type and by profile, and a bar for each day. Reset counters wipes the file locally, and there is nothing to sync, because nothing was ever sent.
- Trackers
- requests to hosts on the merged list
- LinkedIn telemetry
- first party telemetry paths, whichever set matched
- Links cleaned
- navigations a parameter was stripped from
- Beacons
- suppressed sendBeacon calls
- WebSocket tracking
- dropped read receipt and typing frames
Counted on this computer only, and kept when you close ARMANOS.

On the built-in engine an installed blocker does not block on its own
Electron does not execute declarativeNetRequest. Measured with the same extension on both engines: on the built-in engine the request an ad blocker should have stopped reached the server, while ARMANOS Browser blocked it. A blocker installed there loads, shows its icon and stops nothing by itself.
The app closes part of that gap. It reads the rule files named in the extension's manifest, from inside the extension folder only, and runs them through request interception with the context each rule needs: which page is asking, what resource type it is, and which method.
What it will not do is pretend. A rule with its own regular expression, tab conditions, response header conditions or request domain conditions is counted as not understood and is not applied. A rule applied without its condition blocks more than was asked and leaves you with a white page instead of a site, so the two numbers, executed and not understood, are kept apart and written to the log.
Because the gap is real, the Extensions section carries a warning whenever the engine that will actually start is the built-in one. Choosing ARMANOS Browser without having installed it counts as built-in, since that is where the launch lands.

What you do with it
Nothing here has a switch of its own. The use case you pick for a profile selects the lists, the telemetry set and the page scripts, and the rest happens at launch.
- 1
Pick the use case when you create the profile
Privacy gets the general list alone. Social gets the general, LinkedIn and social lists plus both telemetry sets. Ad accounts gets the general and ads lists with the host scoped console rules.
- 2
Turn on ARMANOS Browser under Engine
Blocking and cleaning work on both engines, but an installed blocker extension's own rules only run in full there. The build shipped today is 153.0.7978.0.
- 3
Work as usual, then open Protection
Today, the last 7 days and the total, split by type and by profile. A profile at zero after real browsing is telling you its engine or its use case is not what you assumed.
- 4
Reset the counters before a measurement
The reset is local and immediate, so you can start a clean count on one machine without touching anything on the server.
What this does not do
- This is not an ad blocker. The lists are correlation infrastructure, between 31 and 74 entries per use case, so banners and sponsored posts keep showing.
- Sites you sign into still know you. A login is an identity you handed over yourself, and cutting third party callbacks does not take it back.
- The ad list spares ad consoles on purpose. Everything those consoles need to sign in, load, bill or answer their API is excluded, so working inside a console stays visible to the platform.
- The Protection screen still labels the telemetry row LinkedIn telemetry, even when the count came from the social or ad console rule sets.
- The four lists ship inside the app and change with an app update. There is no subscription list that refreshes itself on a schedule.
How to check
Open the file, then the stand that guards it.
- One function builds the rules for both engines, and each telemetry set is locked to its own hosts
- apps/desktop/src/lib/tracker-rules.js · apps/desktop/test/слежка-по-хостам.js
- On ARMANOS Browser the same rules become a per profile extension, measured live through a loopback proxy
- apps/desktop/src/lib/forkExtension.js · apps/desktop/test/блокировка-живьём.js
- The 40 stripped parameters live in one shared list used by both engines
- packages/shared/src/index.js · apps/desktop/test/блокировка-живьём.js
- An installed extension's rules are executed by the app on the built-in engine, and rules it cannot express are counted as skipped
- apps/desktop/src/lib/dnrBlock.js · apps/desktop/test/builtin-blocking.js
- The Extensions section warns whenever the built-in engine is the one that will start
- apps/desktop/src/manager/store.js · apps/desktop/test/extension-limits-honest.js
Read next
The ARMANOS engine
Where declarativeNetRequest rules actually run, and what the built-in fallback does instead.
Extensions
The catalog, per profile choices and the honest warning about the built-in engine.
Profiles
Where the use case, the lists and the page scripts are chosen for a profile.
Security
What stays on your computer, including these counters, and what reaches the server.
See it in your own profiles
Blocking, cleaning and the counters are on from the first profile you create.