Built-in rules
Ship with each release of the extension. On by default. Switch them off in settings to run only remote or custom rules.
Linkumori can take rules from several places at once. Before any request is cleaned, it picks the sources to use, merges them, puts your custom rules on top, and removes what you switched off. This page walks through each step, with every case.
Rules are loaded at startup and again whenever you save custom rules or refresh remote rules in settings. Each load runs these steps, in order, and the engine then uses the result for every request until the next load.
Ship with each release of the extension. On by default. Switch them off in settings to run only remote or custom rules.
Off by default. Each is a pair of addresses: the rule file and a hash file. Linkumori fetches both, and loads the file only if its SHA-256 matches the hash.
The last remote rules that passed verification. Used when every remote file fails to load, if the cache belongs to the files you have configured.
The providers you write in the custom rules editor. Always applied last, on top of whatever else loaded.
Safety net. If the built-in rules file can't be read, Linkumori uses the remote cache, then the last rule set that loaded, then a small fallback list, so cleaning never stops entirely.
providers object.Both requests skip the browser cache, so a file and its hash always come from the same moment. Files are fetched in parallel, and one failing file doesn't stop the others.
Three settings and what happens to the remote files decide the base rule set. Change the switches to see the path Linkumori takes.
Every decision as a card. A setting that isn't shown makes no difference in that case. Custom rules, if you have any, go on top in every one.
No base rules: custom rules only
Built-in
Remote replaces built-in
Built-in and remote, merged
Remote: overload needs built-in on
Cached remote and built-in, merged
Cached remote
Built-in
No base rules: custom rules only
Remote rules switched on with no valid pair of addresses count as off.
Without overload mode, remote rules replace the built-in ones. With it, both load and providers for the same site merge into one, so you can add to the built-in rules instead of copying them.
domainPatterns (in any order) or the same urlPattern, and the same methods, resourceTypes, completeProvider and forceRedirection. Anything else stays a separate provider.rules, rawRules and referralMarketing, built-in entries first. Exact copies count once.order it keeps the earlier one's place and order.||amazon.*^\/ref=[^/?]*rawRulesqidtokenorder 1||amazon.*^tokenno orderpsc||amazon.*^\/ref=[^/?]*rawRulesqidtokenremote wins, keeps order 1pscBuilt-in Remote show where each rule came from.
Each case shows the files as JSON, what runs, and the merged provider Linkumori builds. Pick a case to see it.
{
"providers": {
"shop": {
"domainPatterns": ["||shop.example^"],
"rules": [
{
"matchPattern": "token",
"order": 1
}
]
}
}
}{
"providers": {
"shop": {
"domainPatterns": ["||shop.example^"],
"rules": [
{
"matchPattern": "token",
"order": 50
}
]
}
}
}||shop.example^tokenorder 50, its ownRemotetokenreplacedBuilt-in{
"providers": {
"shop": {
"domainPatterns": ["||shop.example^"],
"rules": [
{
"matchPattern": "token",
"order": 1
},
{
"matchPattern": "token",
"order": 50
}
]
}
}
}The lists join, so both definitions are in the merged provider. At run time the later one, from the remote file, wins whole, including its own order.
{
"providers": {
"shop": {
"domainPatterns": ["||shop.example^"],
"rules": [
{
"matchPattern": "token",
"order": 1
}
]
}
}
}{
"providers": {
"shop": {
"domainPatterns": ["||shop.example^"],
"rules": ["token"]
}
}
}||shop.example^tokenkeeps order 1 and the first placeRemotetokenreplacedBuilt-in{
"providers": {
"shop": {
"domainPatterns": ["||shop.example^"],
"rules": [
{
"matchPattern": "token",
"order": 1
},
"token"
]
}
}
}The remote copy wins, but it has no order key, so it inherits the built-in order: 1. It also takes the first definition's position.
{
"providers": {
"shop": {
"domainPatterns": ["||shop.example^"],
"rules": [
{
"matchPattern": "token",
"order": 1
}
]
}
}
}{
"providers": {
"shop": {
"domainPatterns": ["||shop.example^"],
"rules": [
{
"matchPattern": "token",
"order": null
}
]
}
}
}||shop.example^tokenno orderRemotetokenreplacedBuilt-in{
"providers": {
"shop": {
"domainPatterns": ["||shop.example^"],
"rules": [
{
"matchPattern": "token",
"order": 1
},
{
"matchPattern": "token",
"order": null
}
]
}
}
}"order": null means no order, and don't inherit one. The rule runs with the unordered entries, at the first definition's position.
{
"providers": {
"shop": {
"domainPatterns": ["||shop.example^"],
"rules": [
{
"matchPattern": "token",
"order": 1
}
]
}
}
}{
"providers": {
"shop": {
"domainPatterns": ["||shop.example^"],
"rules": [
{
"matchPattern": "token",
"order": 20
}
]
}
}
}{
"providers": {
"shop": {
"domainPatterns": ["||shop.example^"],
"rules": [
{
"matchPattern": "token",
"order": 30
}
]
}
}
}||shop.example^tokenorder 30, from file 2Remotetokenfile 1, replacedRemotetokenreplacedBuilt-in{
"providers": {
"shop": {
"domainPatterns": ["||shop.example^"],
"rules": [
{
"matchPattern": "token",
"order": 1
},
{
"matchPattern": "token",
"order": 20
},
{
"matchPattern": "token",
"order": 30
}
]
}
}
}Remote files merge in the order you list them, so the last-listed file's definition is the last one, and it wins.
{
"providers": {
"shop": {
"domainPatterns": ["||shop.example^"],
"rules": [
{
"matchPattern": "token",
"order": 1
}
]
}
}
}{
"providers": {
"shop": {
"domainPatterns": ["||shop.example^"],
"rules": [
{
"matchPattern": "token",
"order": 20
}
]
}
}
}{
"providers": {
"shop": {
"domainPatterns": ["||shop.example^"],
"rules": ["token"]
}
}
}||shop.example^tokenfrom file 2, order 20 from file 1Remotetokenfile 1, replacedRemotetokenreplacedBuilt-in{
"providers": {
"shop": {
"domainPatterns": ["||shop.example^"],
"rules": [
{
"matchPattern": "token",
"order": 1
},
{
"matchPattern": "token",
"order": 20
},
"token"
]
}
}
}File 2 wins. With no order of its own, it takes the order of the nearest earlier definition that has one: file 1's 20.
{
"providers": {
"shop": {
"domainPatterns": ["||shop.example^"],
"rules": [
{ "matchPattern": "a", "order": 1 },
{ "matchPattern": "b", "order": 2 }
]
}
}
}{
"providers": {
"shop": {
"domainPatterns": ["||shop.example^"],
"rules": [
{ "matchPattern": "b", "order": 1 },
{ "matchPattern": "a", "order": 2 }
]
}
}
}||shop.example^bruns 1st, order 1Remotearuns 2nd, order 2Remote{
"providers": {
"shop": {
"domainPatterns": ["||shop.example^"],
"rules": [
{ "matchPattern": "a", "order": 1 },
{ "matchPattern": "b", "order": 2 },
{ "matchPattern": "b", "order": 1 },
{ "matchPattern": "a", "order": 2 }
]
}
}
}Each text resolves on its own: the remote a (order 2) and the remote b (order 1) win, so b now runs before a.
{
"providers": {
"shop": {
"domainPatterns": ["||shop.example^"],
"rules": [
{
"matchPattern": "fromBuiltIn",
"order": 5
}
]
}
}
}{
"providers": {
"shop": {
"domainPatterns": ["||shop.example^"],
"rules": [
{
"matchPattern": "fromRemote",
"order": 5
}
]
}
}
}||shop.example^fromBuiltInruns 1stBuilt-infromRemoteruns 2ndRemote{
"providers": {
"shop": {
"domainPatterns": ["||shop.example^"],
"rules": [
{
"matchPattern": "fromBuiltIn",
"order": 5
},
{
"matchPattern": "fromRemote",
"order": 5
}
]
}
}
}Different text, so both run. At equal order, position decides, and built-in entries come first in the joined list.
{
"providers": {
"site": {
"domainPatterns": ["||site.example^"],
"rules": [
{
"matchPattern": "token",
"order": 1
}
]
}
}
}{
"providers": {
"other": {
"domainPatterns": ["||other.example^"],
"rules": [
{
"matchPattern": "token",
"order": 50
}
]
}
}
}||site.example^tokenorder 1Built-in||other.example^tokenorder 50Remote{
"providers": {
"site": {
"domainPatterns": ["||site.example^"],
"rules": [
{
"matchPattern": "token",
"order": 1
}
]
},
"other": {
"domainPatterns": ["||other.example^"],
"rules": [
{
"matchPattern": "token",
"order": 50
}
]
}
}
}Providers merge only with the same pattern and settings. These stay two providers, each with its own token.
{
"providers": {
"shop": {
"domainPatterns": ["||shop.example^"],
"rules": ["tag"]
}
}
}{
"providers": {
"shop": {
"domainPatterns": ["||shop.example^"],
"referralMarketing": ["tag"]
}
}
}||shop.example^tagreferralMarketing, in the rules entry's placeRemotetagrules, replacedBuilt-in||shop.example^tagrules, runs aloneBuilt-in{
"providers": {
"shop": {
"domainPatterns": ["||shop.example^"],
"rules": ["tag"],
"referralMarketing": ["tag"]
}
}
}While referral-marketing rules run, the referral entry replaces the field entry with the same text. When you allow referral marketing, only the rules entry runs.
Remote Rules Health in settings lists each rule a merge replaced as a notice, naming the file that won. Errors are kept for files and entries that didn't load.
A remote file can change single rules that are already loaded, from the built-in rules or another remote file, without shipping a copy of them. It lists the changes in a top-level patches array. Each patch names one rule and the rule that takes its place.
{
"cln": "1.0",
"patches": [
{ "target": "amazon::field-qid", "section": "rules",
"replace": { "matchPattern": "qid", "requestTypes": ["main_frame"] } }
]
}| Key | What it holds |
|---|---|
target | The rule to replace, written like its on/off toggle key: provider::id, domainPattern:<pattern>::id or urlPattern:<regex>::id. The id can be the rule's id, an alias, or its generated id |
section | The list the rule is in: rules, referralMarketing, rawRules, exceptions, redirections or fieldRedirections |
replace | The new rule, a plain entry or a rule object, as it would be written in that list |
description | A note for people reading the file |
patches needs no providers. When every remote file is one, the patches apply to the built-in rules. Without overload mode, built-in rules aren't loaded next to remote files with providers, so patches then reach only those files' rules.domainPattern: / urlPattern: form is the one that always matches.redirect for that file.patches array rejects the whole file. Remote Rules Health lists each patch as applied, unmatched or skipped.The full syntax is in Filter syntax → Rule patches.
Custom rules go on top of whatever base rule set loaded. Unlike overload mode, they don't join lists. Each custom provider either replaces every base provider with the same pattern, or is added next to the others.
Only the pattern decides: the same urlPattern, or the same domainPatterns in any order. A custom provider overrides a base provider even when its methods, resourceTypes, completeProvider or forceRedirection differ. (Overload mode is stricter: there, providers merge only when all of those match too.)
Changed after 100.66.0 In Linkumori 100.66.0 and earlier, a custom provider replaced a base provider only when its methods, resourceTypes, completeProvider and forceRedirection matched too. If any differed, it was added next to the base provider and both ran.
||amazon.*^qidpd_rd_[a-z]*tagreferralMarketing||amazon.*^qidref_||amazon.*^qidref_pd_rd_[a-z]*no longer removedtagno longer removedThe base rules here are the built-in ones; remote rules behave the same way.
{
"providers": {
"amazon": {
"domainPatterns": ["||amazon.*^"],
"rules": ["qid", "pd_rd_[a-z]*"],
"referralMarketing": ["tag"]
}
}
}{
"providers": {
"amazon": {
"domainPatterns": ["||amazon.*^"],
"rules": ["qid", "ref_"]
}
}
}||amazon.*^qidCustomref_Custompd_rd_[a-z]*no longer removedBuilt-intagno longer removedBuilt-in{
"providers": {
"amazon": {
"domainPatterns": ["||amazon.*^"],
"rules": ["qid", "ref_"]
}
}
}The custom provider replaces the built-in one whole. Its rules are not combined, so the built-in pd_rd_[a-z]* and tag stop running.
{
"providers": {
"amazon": {
"domainPatterns": ["||amazon.*^"],
"rules": ["qid", "pd_rd_[a-z]*"],
"referralMarketing": ["tag"]
}
}
}{
"providers": {
"amazon-get": {
"domainPatterns": ["||amazon.*^"],
"methods": ["GET"],
"rules": ["ref_"]
}
}
}||amazon.*^GET onlyref_Customqidno longer removedBuilt-inpd_rd_[a-z]*no longer removedBuilt-intagno longer removedBuilt-in{
"providers": {
"amazon-get": {
"domainPatterns": ["||amazon.*^"],
"methods": ["GET"],
"rules": ["ref_"]
}
}
}Only the pattern decides. The custom provider replaces the built-in one even though its methods differ, so amazon requests other than GET are no longer cleaned at all.
{
"providers": {
"amazon": {
"domainPatterns": ["||amazon.*^"],
"rules": ["qid", "pd_rd_[a-z]*"],
"referralMarketing": ["tag"]
},
"amazon-block": {
"domainPatterns": ["||amazon.*^"],
"resourceTypes": ["script"],
"completeProvider": true
}
}
}{
"providers": {
"amazon": {
"domainPatterns": ["||amazon.*^"],
"rules": ["qid", "ref_"]
}
}
}||amazon.*^qidCustomref_Custompd_rd_[a-z]*no longer removedBuilt-in||amazon.*^replaced too: scripts no longer blocked{
"providers": {
"amazon": {
"domainPatterns": ["||amazon.*^"],
"rules": ["qid", "ref_"]
}
}
}One custom provider replaces every base provider with its pattern, whatever their settings, including the one that blocks scripts.
{
"providers": {
"amazon": {
"domainPatterns": ["||amazon.*^"],
"rules": ["qid", "pd_rd_[a-z]*"],
"referralMarketing": ["tag"]
}
}
}{
"providers": {
"amazon-de": {
"domainPatterns": ["||amazon.de^"],
"rules": ["ref_"]
}
}
}||amazon.*^qidBuilt-inpd_rd_[a-z]*Built-intagreferralMarketingBuilt-in||amazon.de^ref_Custom{
"providers": {
"amazon": {
"domainPatterns": ["||amazon.*^"],
"rules": ["qid", "pd_rd_[a-z]*"],
"referralMarketing": ["tag"]
},
"amazon-de": {
"domainPatterns": ["||amazon.de^"],
"rules": ["ref_"]
}
}
}Added. On amazon.de both providers match, so both clean the request, one pass after another.
{
"providers": {
"amazon": {
"domainPatterns": [
"||amazon.*^",
"||amzn.to^"
],
"rules": ["qid", "pd_rd_[a-z]*"]
}
}
}{
"providers": {
"amazon": {
"domainPatterns": [
"||amzn.to^",
"||amazon.*^"
],
"rules": ["qid"]
}
}
}||amazon.*^ ||amzn.to^qidCustompd_rd_[a-z]*no longer removedBuilt-in{
"providers": {
"amazon": {
"domainPatterns": [
"||amzn.to^",
"||amazon.*^"
],
"rules": ["qid"]
}
}
}Patterns are compared as a set, sorted, so the order you write them in doesn't matter. This is the same provider, and it is replaced.
{
"providers": {
"amazon": {
"domainPatterns": ["||amazon.*^"],
"rules": ["qid", "pd_rd_[a-z]*"],
"referralMarketing": ["tag"]
}
}
}{
"providers": {
"amazon": {
"domainPatterns": ["||amazon.de^"],
"rules": ["ref_"]
}
}
}||amazon.*^qidBuilt-inpd_rd_[a-z]*Built-intagreferralMarketingBuilt-in||amazon.de^renamedref_Custom{
"providers": {
"amazon": {
"domainPatterns": ["||amazon.*^"],
"rules": ["qid", "pd_rd_[a-z]*"],
"referralMarketing": ["tag"]
},
"amazon_1": {
"domainPatterns": ["||amazon.de^"],
"rules": ["ref_"]
}
}
}Names don't decide matching; patterns do. The custom provider is added, and because amazon is taken, it becomes amazon_1.
{
"providers": {
"amazon": {
"domainPatterns": ["||amazon.*^"],
"rules": ["qid", "pd_rd_[a-z]*"],
"referralMarketing": ["tag"]
}
}
}{
"providers": {
"amazon": {
"domainPatterns": ["||amazon.*^"],
"rules": ["ref_"]
}
}
}The provider for ||amazon.*^
||amazon.*^switched offqidBuilt-inref_CustomNo provider for this pattern.
Switching a provider off in the custom rules editor removes it from both the base rules and the custom rules, before they are combined.
{
"providers": {
"amazon": {
"domainPatterns": ["||amazon.*^"],
"rules": ["qid", "pd_rd_[a-z]*"],
"referralMarketing": ["tag"]
}
}
}{
"providers": {
"broken": { "rules": ["utm_extra"] }
}
}||amazon.*^qidBuilt-inpd_rd_[a-z]*Built-intagreferralMarketingBuilt-inno patterndroppedutm_extraCustom{
"providers": {
"amazon": {
"domainPatterns": ["||amazon.*^"],
"rules": ["qid", "pd_rd_[a-z]*"],
"referralMarketing": ["tag"]
}
}
}Without domainPatterns or urlPattern a provider can't match anything, so it is dropped.
When both a base provider and a custom provider match a request, both still get to clean it. The first provider that changes, redirects or blocks the URL ends that pass, and the cleaned URL starts a new pass, so the other provider runs next.
You can switch off a single rule, or a whole provider, without editing any file. Switched-off rules are left out when the providers are built.
| Scope | Saved as | Switches the rule off |
|---|---|---|
| Provider | provider::id | Everywhere in that provider |
| Pattern | domainPattern:||shop.example^::id | Only for URLs matching that one pattern |
id pins its generated id, so the setting keeps working when the rule's text changes a little. A pin that no longer matches any rule shows as an orphaned toggle in the editor.id changes, its old ids in aliases keep saved toggles working.Each rule file can have a defaults block, for example request types or exceptions that every rule in the file gets unless it sets its own. In the custom rules editor, Manage rule defaults sets your own block and where it applies.
| Setting | Built-in rules use | Remote files use | Custom rules use |
|---|---|---|---|
| Each source's own (the default) | Their own | Each file's own | Their own |
| Yours for built-in and remote rules | Yours | Yours | Their own |
| Yours for all rules | Yours | Yours | Yours |
A rule's own value always wins, and a provider's exceptions list is never changed by defaults. Defaults are applied to each file when it loads, so they stay with their file through overload mode.
When files with different defaults merge, nothing has to be looked up later: each file's defaults are written into that file's own rules as it loads, before any merge. Every rule then carries its values with it, so one merged provider can hold rules with different defaults side by side.
||shop.example^noneqidtoken||shop.example^"requestTypes": ["main_frame"]psctoken||shop.example^qidevery request typetokenpage loads only: the remote copy wins, with its file's valuepscpage loads onlyrequestTypes or exceptions.exceptions list goes into that file's rules only. Merging never pools one file's exceptions into another file's rules.historyBypassProtection beats the file default. When providers merge, it is copied onto each of that provider's rules, since the merged provider can hold only one value."completeProvider": true, a file's requestTypes default becomes its resourceTypes, and default exceptions join its own. That happens before merging, and resourceTypes is part of what makes providers match, so the block can end up as a separate provider.Two different things get called merging defaults. Linkumori does one on its own every time rules load. The other only happens when you start it in the custom rules editor.
When: every time rules load: at startup, when you save custom rules, and when you refresh remote rules in settings.
What happens: each source's defaults block is chosen, by the setting under Rule defaults, and written into that source's own rules. Then the rules merge: remote files with each other, with built-in in overload mode, and custom rules on top.
What it never does: combine two defaults blocks. Each rule keeps its own file's values, as shown above.
When: only when you open Manage rule defaults in the custom rules editor and choose Merge from sources.
What happens: the defaults blocks of the sources you tick (yours, built-in, each remote file, custom) combine into one block, shown as Merged defaults.
What it never does: change anything by itself. Nothing is stored until you copy the merged block into one of your sets and save. The next load then writes it into rules automatically.
| You set | Where | What the next load does with it |
|---|---|---|
| Where your defaults apply: each source's own, yours for built-in and remote, or yours for all | Custom rules editor → Manage rule defaults | Picks, for each source, whether its own block or yours is written into its rules |
| Your edit of the built-in rules' or one remote file's defaults | The same form | Uses your edit in place of that file's whole defaults block wherever the file's own would be used |
| Your own defaults block, and the custom rules' block | The same form | Written into the sources the setting above gives them to |
| Overload mode | Settings | Merges built-in and remote rules after their defaults are written in |
| Key | Sources agree | Sources disagree |
|---|---|---|
exceptions | Taken as it is | Automatic added together: the set on screen first, then every other source's, without duplicates |
requestTypes | Taken as it is | You choose one source's list, or the combined list, which is preselected. A source that leaves it out allows every type, so the combined list does too |
preprocessors | Taken as it is | You choose one source's list, or the combined list, which is preselected |
active, description, historyBypassProtection | Taken as it is | You choose one source's value. The first source's is preselected |
{
"defaults": {
"requestTypes": ["main_frame"],
"exceptions": [
"^https:\\/\\/shop\\.example\\/cart"
]
}
}{
"defaults": {
"requestTypes": [
"main_frame",
"xmlhttprequest"
],
"historyBypassProtection": false,
"exceptions": [
"^https:\\/\\/shop\\.example\\/login"
]
}
}{
"defaults": {
"requestTypes": ["main_frame"],
"description": "Shop rules"
}
}{
"defaults": {
"requestTypes": [
"main_frame",
"xmlhttprequest"
],
"exceptions": [
"^https:\\/\\/shop\\.example\\/cart",
"^https:\\/\\/shop\\.example\\/login"
]
}
}exceptionsAdded together from every sourcedescriptionYou choose: left out from Your defaults, Built-in rules · "Shop rules" from rules.example.org. Bold is preselected.requestTypesYou choose: ["main_frame"] from Your defaults, rules.example.org · ["main_frame", "xmlhttprequest"] (combined) from Built-in rules. Bold is preselected.historyBypassProtectionYou choose: left out from Your defaults, rules.example.org · false from Built-in rules. Bold is preselected.Nothing is stored until you copy the merged block into one of your defaults sets and save. Picking another option for a key changes only that key.
Merging never looks back at the original files. Everything it needs later is written onto the rules first.
| Carried on the rule | Written when | Used for |
|---|---|---|
Its file's defaults: requestTypes, exceptions, preprocessors, active, description, historyBypassProtection | Its file loads | Where and how the rule runs |
Its provider's historyBypassProtection | Providers merge | Whether the rule runs on History API changes |
| The file it came from | Providers merge | Remote Rules Health naming the file whose definition won |
| Whether it may redirect | Its remote file loads, from the capabilities you accepted for that file | A file's rewriting raw rules can't send a URL to another site until you accept redirect for that file |
Order on load: a remote file's defaults are written in first, then its capabilities are applied, and only then does it merge. Before merging, a file without an accepted capability also loses the entries that need it: its redirect lists without redirect, and completeProvider without block. The file tags never leave the extension: the custom rules editor strips them when you export a rule.
{
"providers": {
"shop": {
"domainPatterns": ["||shop.example^"],
"rules": ["qid"]
}
}
}{
"defaults": {
"requestTypes": ["main_frame"]
},
"providers": {
"shop": {
"domainPatterns": ["||shop.example^"],
"rules": ["psc"]
}
}
}||shop.example^qidevery request typeBuilt-inpscpage loads onlyRemote{
"providers": {
"shop": {
"domainPatterns": ["||shop.example^"],
"rules": [
"qid",
{
"matchPattern": "psc",
"requestTypes": ["main_frame"]
}
]
}
}
}The remote file's requestTypes default is written into psc as the file loads. After the merge, only psc carries it.
{
"providers": {
"shop": {
"domainPatterns": ["||shop.example^"],
"rules": ["token"]
}
}
}{
"defaults": {
"requestTypes": ["main_frame"]
},
"providers": {
"shop": {
"domainPatterns": ["||shop.example^"],
"rules": ["token"]
}
}
}||shop.example^tokenpage loads onlyRemotetokenreplacedBuilt-in{
"providers": {
"shop": {
"domainPatterns": ["||shop.example^"],
"rules": [
"token",
{
"matchPattern": "token",
"requestTypes": ["main_frame"]
}
]
}
}
}The remote copy wins whole, and it brings the value its file wrote into it.
{
"defaults": {
"requestTypes": ["main_frame"]
},
"providers": {
"shop": {
"domainPatterns": ["||shop.example^"],
"rules": ["token"]
}
}
}{
"providers": {
"shop": {
"domainPatterns": ["||shop.example^"],
"rules": ["token"]
}
}
}||shop.example^tokenevery request typeRemotetokenreplaced, with its limitBuilt-in{
"providers": {
"shop": {
"domainPatterns": ["||shop.example^"],
"rules": [
{
"matchPattern": "token",
"requestTypes": ["main_frame"]
},
"token"
]
}
}
}The remote copy wins whole. It has no requestTypes, so the built-in file's limit goes with the replaced copy.
{
"defaults": {
"exceptions": [
"^https:\\/\\/shop\\.example\\/cart"
]
},
"providers": {
"shop": {
"domainPatterns": ["||shop.example^"],
"rules": ["a"]
}
}
}{
"defaults": {
"exceptions": [
"^https:\\/\\/shop\\.example\\/login"
]
},
"providers": {
"shop": {
"domainPatterns": ["||shop.example^"],
"rules": ["b"]
}
}
}||shop.example^askips /cartBuilt-inbskips /loginRemote{
"providers": {
"shop": {
"domainPatterns": ["||shop.example^"],
"rules": [
{
"matchPattern": "a",
"exceptions": [
"^https:\\/\\/shop\\.example\\/cart"
]
},
{
"matchPattern": "b",
"exceptions": [
"^https:\\/\\/shop\\.example\\/login"
]
}
]
}
}
}Each file's exceptions go into its own rules. Merging never pools them, so a skips only /cart and b only /login.
{
"defaults": { "active": false },
"providers": {
"shop": {
"domainPatterns": ["||shop.example^"],
"rules": [
"a",
{
"matchPattern": "c",
"active": true
}
]
}
}
}{
"providers": {
"shop": {
"domainPatterns": ["||shop.example^"],
"rules": ["b"]
}
}
}||shop.example^csets "active": true itselfBuilt-inbRemoteaoff by its file's defaultBuilt-in{
"providers": {
"shop": {
"domainPatterns": ["||shop.example^"],
"rules": [
{
"matchPattern": "a",
"active": false
},
{
"matchPattern": "c",
"active": true
},
"b"
]
}
}
}"active": false switches off every rule of its file that doesn't say "active": true. The remote file isn't affected.
{
"defaults": {
"requestTypes": ["main_frame"]
},
"providers": {
"shop": {
"domainPatterns": ["||shop.example^"],
"rules": [
{
"matchPattern": "token",
"requestTypes": ["script"]
},
"psc"
]
}
}
}||shop.example^tokenscripts: its own valueRemotepscpage loads: the defaultRemote{
"providers": {
"shop": {
"domainPatterns": ["||shop.example^"],
"rules": [
{
"matchPattern": "token",
"requestTypes": ["script"]
},
{
"matchPattern": "psc",
"requestTypes": ["main_frame"]
}
]
}
}
}A default only fills a key the rule leaves out. token sets requestTypes, so the default doesn't touch it.
{ "requestTypes": ["main_frame"] }{
"providers": {
"shop": {
"domainPatterns": ["||shop.example^"],
"rules": ["qid"]
}
}
}{
"defaults": {
"exceptions": [
"^https:\\/\\/shop\\.example\\/cart"
]
},
"providers": {
"shop": {
"domainPatterns": ["||shop.example^"],
"rules": ["psc"]
}
}
}||shop.example^qidpage loads: your defaultBuilt-inpscpage loads; the file's /cart exception is ignoredRemote{
"providers": {
"shop": {
"domainPatterns": ["||shop.example^"],
"rules": [
{
"matchPattern": "qid",
"requestTypes": ["main_frame"]
},
{
"matchPattern": "psc",
"requestTypes": ["main_frame"]
}
]
}
}
}With "Yours for built-in and remote rules", both files get your block in place of their own before merging. Custom rules keep their own.
{
"defaults": {
"requestTypes": ["main_frame"]
},
"providers": {
"shop": {
"domainPatterns": ["||shop.example^"],
"rules": ["psc"]
}
}
}{}||shop.example^pscevery request type: your empty block replaced the file'sRemote{
"providers": {
"shop": {
"domainPatterns": ["||shop.example^"],
"rules": ["psc"]
}
}
}An edit replaces the file's whole defaults block, and an empty block means no defaults. The file itself doesn't change: your edit is kept in the extension, and still applies after the file is updated.
{
"providers": {
"shop": {
"domainPatterns": ["||shop.example^"],
"historyBypassProtection": false,
"rules": ["a"]
}
}
}{
"providers": {
"shop": {
"domainPatterns": ["||shop.example^"],
"rules": ["b"]
}
}
}||shop.example^askipped on History API changesBuilt-inbruns on History API changes tooRemote{
"providers": {
"shop": {
"domainPatterns": ["||shop.example^"],
"rules": [
{
"matchPattern": "a",
"historyBypassProtection": false
},
"b"
]
}
}
}The merged provider can hold only one value, so the built-in provider's setting is copied onto its own rule first.
{
"providers": {
"trackers": {
"domainPatterns": ["||tracker.example^"],
"completeProvider": true
}
}
}{
"defaults": {
"requestTypes": ["main_frame"]
},
"providers": {
"trackers": {
"domainPatterns": ["||tracker.example^"],
"completeProvider": true
}
}
}||tracker.example^blocks every request||tracker.example^blocks page loads, once you accept block{
"providers": {
"trackers": {
"domainPatterns": ["||tracker.example^"],
"completeProvider": true,
"resourceTypes": ["main_frame"]
}
}
}The default becomes the remote provider's resourceTypes as it loads, and resourceTypes is part of what makes providers match. So these two stay separate providers.
The custom rules editor shows the defaults each loaded source used. Its Merge from sources tool is separate: it combines several defaults blocks into one block you can save, and doesn't change how rules merge.
A remote file gets capabilities from what it contains. Removing, rewriting and excepting work as soon as it loads. Redirecting and blocking wait until you accept them for that file in Remote Rules Health.
| Capability | The file contains | Active |
|---|---|---|
strip | rules, rawRules, referralMarketing or $removeparam entries | On load |
rewrite | An entry with a replacePattern | On load |
except | Provider exceptions or @@ entries | On load |
redirect | redirections, fieldRedirections or forceRedirection | After you accept |
block | A provider with "completeProvider": true | After you accept |
Built-in and custom rules hold every capability. A file that gains a capability in an update waits for acceptance again.
Source: partials/rules.html on the website branch.