Guide

How rules work

Covers
Sources, merging, custom rules
Applies to
Linkumori after 100.66.0

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.

The pipeline

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.

  1. 1Pick the sourcesBuilt-in, remote, the verified cache, or none
  2. 2MergeRemote files with each other; with built-in in overload mode; then remote patches
  3. 3Custom rules on topA matching custom provider replaces; others are added
  4. 4Switch things offExcluded providers go; switched-off rules are skipped
  5. 5Clean requestsProviders run in order, pass after pass

Where rules come from

Built-in

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.

Remote

Remote rule files

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.

Cache

Verified cache

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.

Custom

Custom rules

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.

How a remote file is checked

  1. Fetch the hash file. It must hold 32 to 128 hexadecimal characters.
  2. Fetch the rule file and compare its SHA-256 with the hash. A mismatch rejects the file.
  3. Parse it as a CLN rule file with a providers object.
  4. Merge the files that passed, in the order you listed them, and save them as the verified cache.

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.

Which sources load

Three settings and what happens to the remote files decide the base rule set. Change the switches to see the path Linkumori takes.

Built-in rules
Remote rules
Remote files
Verified cache
Overload mode
Custom rules

    Every combination

    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.

    Built-in
    Off
    Remote
    Off
    No base rules

    No base rules: custom rules only

    Built-in
    On
    Remote
    Off
    Built-in rules

    Built-in

    Remote
    On
    Remote files
    Verified
    Overload
    Off
    Remote rules

    Remote replaces built-in

    Built-in
    On
    Remote
    On
    Remote files
    Verified
    Overload
    On
    Remote rules
    Built-in rules

    Built-in and remote, merged

    Built-in
    Off
    Remote
    On
    Remote files
    Verified
    Overload
    On
    Remote rules

    Remote: overload needs built-in on

    Built-in
    On
    Remote
    On
    Remote files
    All failed
    Cache
    Available
    Overload
    On
    Verified cache
    Built-in rules

    Cached remote and built-in, merged

    Remote
    On
    Remote files
    All failed
    Cache
    Available
    Overload
    Off
    Verified cache

    Cached remote

    Built-in
    On
    Remote
    On
    Remote files
    All failed
    Cache
    None
    Built-in rules

    Built-in

    Built-in
    Off
    Remote
    On
    Remote files
    All failed
    Cache
    None
    No base rules

    No base rules: custom rules only

    Remote rules switched on with no valid pair of addresses count as off.

    Overload mode: merging sources

    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.

    Order and matching

    1. Remote files merge first, with each other, in the order you list them.
    2. Then with built-in: built-in providers first, remote providers after.
    3. Providers merge only if they match: the same domainPatterns (in any order) or the same urlPattern, and the same methods, resourceTypes, completeProvider and forceRedirection. Anything else stays a separate provider.
    4. Lists join in load order: rules, rawRules and referralMarketing, built-in entries first. Exact copies count once.
    5. The same text twice: the later definition, from remote, wins. Without its own order it keeps the earlier one's place and order.

    Example: one site in both sources

    Built-in||amazon.*^
    • \/ref=[^/?]*rawRules
    • qid
    • tokenorder 1
    Remote||amazon.*^
    • tokenno order
    • psc
    Merged||amazon.*^
    • \/ref=[^/?]*rawRules
    • qid
    • tokenremote wins, keeps order 1
    • psc

    Built-in Remote show where each rule came from.

    Every overload case

    Each case shows the files as JSON, what runs, and the merged provider Linkumori builds. Pick a case to see it.

    1

    A remote copy with its own order

    1. You setYou turned on overload mode in settings, with built-in rules on and a remote rule file set up.
    2. AutomaticEvery load merges the files. The same text is resolved when rules run.
    Built-inBuilt-in rules
    JSON
    {
      "providers": {
        "shop": {
          "domainPatterns": ["||shop.example^"],
          "rules": [
            {
              "matchPattern": "token",
              "order": 1
            }
          ]
        }
      }
    }
    RemoteRemote file
    JSON
    {
      "providers": {
        "shop": {
          "domainPatterns": ["||shop.example^"],
          "rules": [
            {
              "matchPattern": "token",
              "order": 50
            }
          ]
        }
      }
    }
    What runs
    ||shop.example^
    • tokenorder 50, its ownRemote
    • tokenreplacedBuilt-in
    Merged provider as JSON
    JSON
    {
      "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.

    2

    A remote copy without an order

    1. You setYou turned on overload mode in settings, with built-in rules on and a remote rule file set up.
    2. AutomaticEvery load merges the files. The same text is resolved when rules run.
    Built-inBuilt-in rules
    JSON
    {
      "providers": {
        "shop": {
          "domainPatterns": ["||shop.example^"],
          "rules": [
            {
              "matchPattern": "token",
              "order": 1
            }
          ]
        }
      }
    }
    RemoteRemote file
    JSON
    {
      "providers": {
        "shop": {
          "domainPatterns": ["||shop.example^"],
          "rules": ["token"]
        }
      }
    }
    What runs
    ||shop.example^
    • tokenkeeps order 1 and the first placeRemote
    • tokenreplacedBuilt-in
    Merged provider as JSON
    JSON
    {
      "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.

    3

    Dropping an inherited order

    1. You setYou turned on overload mode in settings, with built-in rules on and a remote rule file set up.
    2. AutomaticEvery load merges the files. The same text is resolved when rules run.
    Built-inBuilt-in rules
    JSON
    {
      "providers": {
        "shop": {
          "domainPatterns": ["||shop.example^"],
          "rules": [
            {
              "matchPattern": "token",
              "order": 1
            }
          ]
        }
      }
    }
    RemoteRemote file
    JSON
    {
      "providers": {
        "shop": {
          "domainPatterns": ["||shop.example^"],
          "rules": [
            {
              "matchPattern": "token",
              "order": null
            }
          ]
        }
      }
    }
    What runs
    ||shop.example^
    • tokenno orderRemote
    • tokenreplacedBuilt-in
    Merged provider as JSON
    JSON
    {
      "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.

    4

    Two remote files, both with an order

    1. You setYou turned on overload mode in settings, with built-in rules on and a remote rule file set up.
    2. You setYou listed file 1 before file 2 in settings.
    3. AutomaticEvery load merges the files. The same text is resolved when rules run.
    Built-inBuilt-in rules
    JSON
    {
      "providers": {
        "shop": {
          "domainPatterns": ["||shop.example^"],
          "rules": [
            {
              "matchPattern": "token",
              "order": 1
            }
          ]
        }
      }
    }
    RemoteRemote file 1
    JSON
    {
      "providers": {
        "shop": {
          "domainPatterns": ["||shop.example^"],
          "rules": [
            {
              "matchPattern": "token",
              "order": 20
            }
          ]
        }
      }
    }
    RemoteRemote file 2
    JSON
    {
      "providers": {
        "shop": {
          "domainPatterns": ["||shop.example^"],
          "rules": [
            {
              "matchPattern": "token",
              "order": 30
            }
          ]
        }
      }
    }
    What runs
    ||shop.example^
    • tokenorder 30, from file 2Remote
    • tokenfile 1, replacedRemote
    • tokenreplacedBuilt-in
    Merged provider as JSON
    JSON
    {
      "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.

    5

    Two remote files, the last without an order

    1. You setYou turned on overload mode in settings, with built-in rules on and a remote rule file set up.
    2. You setYou listed file 1 before file 2 in settings.
    3. AutomaticEvery load merges the files. The same text is resolved when rules run.
    Built-inBuilt-in rules
    JSON
    {
      "providers": {
        "shop": {
          "domainPatterns": ["||shop.example^"],
          "rules": [
            {
              "matchPattern": "token",
              "order": 1
            }
          ]
        }
      }
    }
    RemoteRemote file 1
    JSON
    {
      "providers": {
        "shop": {
          "domainPatterns": ["||shop.example^"],
          "rules": [
            {
              "matchPattern": "token",
              "order": 20
            }
          ]
        }
      }
    }
    RemoteRemote file 2
    JSON
    {
      "providers": {
        "shop": {
          "domainPatterns": ["||shop.example^"],
          "rules": ["token"]
        }
      }
    }
    What runs
    ||shop.example^
    • tokenfrom file 2, order 20 from file 1Remote
    • tokenfile 1, replacedRemote
    • tokenreplacedBuilt-in
    Merged provider as JSON
    JSON
    {
      "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.

    6

    The same two rules, orders swapped

    1. You setYou turned on overload mode in settings, with built-in rules on and a remote rule file set up.
    2. AutomaticEvery load merges the files. The same text is resolved when rules run.
    Built-inBuilt-in rules
    JSON
    {
      "providers": {
        "shop": {
          "domainPatterns": ["||shop.example^"],
          "rules": [
            { "matchPattern": "a", "order": 1 },
            { "matchPattern": "b", "order": 2 }
          ]
        }
      }
    }
    RemoteRemote file
    JSON
    {
      "providers": {
        "shop": {
          "domainPatterns": ["||shop.example^"],
          "rules": [
            { "matchPattern": "b", "order": 1 },
            { "matchPattern": "a", "order": 2 }
          ]
        }
      }
    }
    What runs
    ||shop.example^
    • bruns 1st, order 1Remote
    • aruns 2nd, order 2Remote
    Merged provider as JSON
    JSON
    {
      "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.

    7

    Different rules with the same order

    1. You setYou turned on overload mode in settings, with built-in rules on and a remote rule file set up.
    2. AutomaticEvery load merges the files. The same text is resolved when rules run.
    Built-inBuilt-in rules
    JSON
    {
      "providers": {
        "shop": {
          "domainPatterns": ["||shop.example^"],
          "rules": [
            {
              "matchPattern": "fromBuiltIn",
              "order": 5
            }
          ]
        }
      }
    }
    RemoteRemote file
    JSON
    {
      "providers": {
        "shop": {
          "domainPatterns": ["||shop.example^"],
          "rules": [
            {
              "matchPattern": "fromRemote",
              "order": 5
            }
          ]
        }
      }
    }
    What runs
    ||shop.example^
    • fromBuiltInruns 1stBuilt-in
    • fromRemoteruns 2ndRemote
    Merged provider as JSON
    JSON
    {
      "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.

    8

    A different pattern

    1. You setYou turned on overload mode in settings, with built-in rules on and a remote rule file set up.
    2. AutomaticEvery load keeps the two apart, because their patterns differ.
    Built-inBuilt-in rules
    JSON
    {
      "providers": {
        "site": {
          "domainPatterns": ["||site.example^"],
          "rules": [
            {
              "matchPattern": "token",
              "order": 1
            }
          ]
        }
      }
    }
    RemoteRemote file
    JSON
    {
      "providers": {
        "other": {
          "domainPatterns": ["||other.example^"],
          "rules": [
            {
              "matchPattern": "token",
              "order": 50
            }
          ]
        }
      }
    }
    What runs
    ||site.example^
    • tokenorder 1Built-in
    ||other.example^
    • tokenorder 50Remote
    Merged provider as JSON
    JSON
    {
      "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.

    9

    The same text in rules and referralMarketing

    1. You setYou turned on overload mode in settings, with built-in rules on and a remote rule file set up.
    2. You setAllow referral marketing is a switch in settings.
    3. AutomaticEvery load merges the files. The same text is resolved when rules run.
    Built-inBuilt-in rules
    JSON
    {
      "providers": {
        "shop": {
          "domainPatterns": ["||shop.example^"],
          "rules": ["tag"]
        }
      }
    }
    RemoteRemote file
    JSON
    {
      "providers": {
        "shop": {
          "domainPatterns": ["||shop.example^"],
          "referralMarketing": ["tag"]
        }
      }
    }
    What runs
    Referral marketing not allowed
    ||shop.example^
    • tagreferralMarketing, in the rules entry's placeRemote
    • tagrules, replacedBuilt-in
    Referral marketing allowed
    ||shop.example^
    • tagrules, runs aloneBuilt-in
    Merged provider as JSON
    JSON
    {
      "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.

    Remote rule patches

    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.

    JSON
    {
      "cln": "1.0",
      "patches": [
        { "target": "amazon::field-qid", "section": "rules",
          "replace": { "matchPattern": "qid", "requestTypes": ["main_frame"] } }
      ]
    }
    KeyWhat it holds
    targetThe 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
    sectionThe list the rule is in: rules, referralMarketing, rawRules, exceptions, redirections or fieldRedirections
    replaceThe new rule, a plain entry or a rule object, as it would be written in that list
    descriptionA note for people reading the file

    The full syntax is in Filter syntax → Rule patches.

    Custom rules: replace or add

    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.

    A custom provider with the same pattern replaces the whole provider. Its rules are not combined with the built-in or remote ones. To add one rule to a built-in provider, copy that provider into the editor and add your rule to the copy. Or use a different pattern, so yours is added alongside.

    Example: the same pattern replaces

    Built-in||amazon.*^
    • qid
    • pd_rd_[a-z]*
    • tagreferralMarketing
    Custom||amazon.*^
    • qid
    • ref_
    Runs||amazon.*^
    • qid
    • ref_
    • pd_rd_[a-z]*no longer removed
    • tagno longer removed

    Every custom-rule case

    The base rules here are the built-in ones; remote rules behave the same way.

    1

    The same pattern

    1. You setYou saved a custom provider in the custom rules editor.
    2. AutomaticEvery load replaces the built-in provider with yours. Saving starts a load straight away.
    Built-inBuilt-in rules
    JSON
    {
      "providers": {
        "amazon": {
          "domainPatterns": ["||amazon.*^"],
          "rules": ["qid", "pd_rd_[a-z]*"],
          "referralMarketing": ["tag"]
        }
      }
    }
    CustomCustom rules
    JSON
    {
      "providers": {
        "amazon": {
          "domainPatterns": ["||amazon.*^"],
          "rules": ["qid", "ref_"]
        }
      }
    }
    What runs
    Customamazon||amazon.*^
    • qidCustom
    • ref_Custom
    • pd_rd_[a-z]*no longer removedBuilt-in
    • tagno longer removedBuilt-in
    Providers that run as JSON
    JSON
    {
      "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.

    2

    The same pattern, different settings

    1. You setYou saved a custom provider in the custom rules editor.
    2. AutomaticEvery load replaces the built-in provider, whatever the settings.
    Built-inBuilt-in rules
    JSON
    {
      "providers": {
        "amazon": {
          "domainPatterns": ["||amazon.*^"],
          "rules": ["qid", "pd_rd_[a-z]*"],
          "referralMarketing": ["tag"]
        }
      }
    }
    CustomCustom rules
    JSON
    {
      "providers": {
        "amazon-get": {
          "domainPatterns": ["||amazon.*^"],
          "methods": ["GET"],
          "rules": ["ref_"]
        }
      }
    }
    What runs
    Customamazon-get||amazon.*^GET only
    • ref_Custom
    • qidno longer removedBuilt-in
    • pd_rd_[a-z]*no longer removedBuilt-in
    • tagno longer removedBuilt-in
    Providers that run as JSON
    JSON
    {
      "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.

    3

    Two base providers on the same pattern

    1. You setYou saved a custom provider in the custom rules editor.
    2. AutomaticEvery load replaces both built-in providers on the pattern.
    Built-inBuilt-in rules
    JSON
    {
      "providers": {
        "amazon": {
          "domainPatterns": ["||amazon.*^"],
          "rules": ["qid", "pd_rd_[a-z]*"],
          "referralMarketing": ["tag"]
        },
        "amazon-block": {
          "domainPatterns": ["||amazon.*^"],
          "resourceTypes": ["script"],
          "completeProvider": true
        }
      }
    }
    CustomCustom rules
    JSON
    {
      "providers": {
        "amazon": {
          "domainPatterns": ["||amazon.*^"],
          "rules": ["qid", "ref_"]
        }
      }
    }
    What runs
    Customamazon||amazon.*^
    • qidCustom
    • ref_Custom
    • pd_rd_[a-z]*no longer removedBuilt-in
    Offamazon-block||amazon.*^replaced too: scripts no longer blocked
    Providers that run as JSON
    JSON
    {
      "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.

    4

    A different pattern

    1. You setYou saved a custom provider in the custom rules editor.
    2. AutomaticEvery load adds yours next to the built-in provider.
    Built-inBuilt-in rules
    JSON
    {
      "providers": {
        "amazon": {
          "domainPatterns": ["||amazon.*^"],
          "rules": ["qid", "pd_rd_[a-z]*"],
          "referralMarketing": ["tag"]
        }
      }
    }
    CustomCustom rules
    JSON
    {
      "providers": {
        "amazon-de": {
          "domainPatterns": ["||amazon.de^"],
          "rules": ["ref_"]
        }
      }
    }
    What runs
    Built-inamazon||amazon.*^
    • qidBuilt-in
    • pd_rd_[a-z]*Built-in
    • tagreferralMarketingBuilt-in
    Customamazon-de||amazon.de^
    • ref_Custom
    Providers that run as JSON
    JSON
    {
      "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.

    5

    The same patterns in another order

    1. You setYou saved a custom provider in the custom rules editor.
    2. AutomaticEvery load compares the patterns as a set and replaces.
    Built-inBuilt-in rules
    JSON
    {
      "providers": {
        "amazon": {
          "domainPatterns": [
            "||amazon.*^",
            "||amzn.to^"
          ],
          "rules": ["qid", "pd_rd_[a-z]*"]
        }
      }
    }
    CustomCustom rules
    JSON
    {
      "providers": {
        "amazon": {
          "domainPatterns": [
            "||amzn.to^",
            "||amazon.*^"
          ],
          "rules": ["qid"]
        }
      }
    }
    What runs
    Customamazon||amazon.*^ ||amzn.to^
    • qidCustom
    • pd_rd_[a-z]*no longer removedBuilt-in
    Providers that run as JSON
    JSON
    {
      "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.

    6

    A name that is already taken

    1. You setYou saved a custom provider in the custom rules editor.
    2. AutomaticEvery load adds yours and renames it amazon_1.
    Built-inBuilt-in rules
    JSON
    {
      "providers": {
        "amazon": {
          "domainPatterns": ["||amazon.*^"],
          "rules": ["qid", "pd_rd_[a-z]*"],
          "referralMarketing": ["tag"]
        }
      }
    }
    CustomCustom rules
    JSON
    {
      "providers": {
        "amazon": {
          "domainPatterns": ["||amazon.de^"],
          "rules": ["ref_"]
        }
      }
    }
    What runs
    Built-inamazon||amazon.*^
    • qidBuilt-in
    • pd_rd_[a-z]*Built-in
    • tagreferralMarketingBuilt-in
    Customamazon_1||amazon.de^renamed
    • ref_Custom
    Providers that run as JSON
    JSON
    {
      "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.

    7

    A provider you switched off

    1. You setYou switched the provider off in the custom rules editor.
    2. AutomaticEvery load removes it from the base and the custom rules.
    Built-inBuilt-in rules
    JSON
    {
      "providers": {
        "amazon": {
          "domainPatterns": ["||amazon.*^"],
          "rules": ["qid", "pd_rd_[a-z]*"],
          "referralMarketing": ["tag"]
        }
      }
    }
    CustomCustom rules
    JSON
    {
      "providers": {
        "amazon": {
          "domainPatterns": ["||amazon.*^"],
          "rules": ["ref_"]
        }
      }
    }
    OffSwitched off in the editor

    The provider for ||amazon.*^

    What runs
    Offamazon||amazon.*^switched off
    • qidBuilt-in
    • ref_Custom
    Providers that run as JSON

    No 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.

    8

    A provider with no pattern

    1. You setYou saved a custom provider without a pattern.
    2. AutomaticEvery load drops it.
    Built-inBuilt-in rules
    JSON
    {
      "providers": {
        "amazon": {
          "domainPatterns": ["||amazon.*^"],
          "rules": ["qid", "pd_rd_[a-z]*"],
          "referralMarketing": ["tag"]
        }
      }
    }
    CustomCustom rules
    JSON
    {
      "providers": {
        "broken": { "rules": ["utm_extra"] }
      }
    }
    What runs
    Built-inamazon||amazon.*^
    • qidBuilt-in
    • pd_rd_[a-z]*Built-in
    • tagreferralMarketingBuilt-in
    Offbrokenno patterndropped
    • utm_extraCustom
    Providers that run as JSON
    JSON
    {
      "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.

    Switching rules off

    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.

    ScopeSaved asSwitches the rule off
    Providerprovider::idEverywhere in that provider
    PatterndomainPattern:||shop.example^::idOnly for URLs matching that one pattern

    Rule defaults

    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.

    SettingBuilt-in rules useRemote files useCustom rules use
    Each source's own (the default)Their ownEach file's ownTheir own
    Yours for built-in and remote rulesYoursYoursTheir own
    Yours for all rulesYoursYoursYours

    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.

    Defaults when rules merge

    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.

    1. 1Pick each file's defaultsIts own, your edit of them, or yours, by the setting above
    2. 2Write them into its rulesOnly keys a rule doesn't set; the block is then removed
    3. 3Then mergeRules keep the values their file gave them

    Example: two files, two sets of defaults

    Built-in||shop.example^
    defaultsnone
    • qid
    • token
    Remote||shop.example^
    defaults"requestTypes": ["main_frame"]
    • psc
    • token
    Merged||shop.example^
    • qidevery request type
    • tokenpage loads only: the remote copy wins, with its file's value
    • pscpage loads only

    How it works

    Automatic, or started by you

    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.

    Automatic

    Writing defaults into rules

    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.

    You start it

    Merge from sources

    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.

    Which of your settings feed the automatic step

    You setWhereWhat the next load does with it
    Where your defaults apply: each source's own, yours for built-in and remote, or yours for allCustom rules editor → Manage rule defaultsPicks, 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 defaultsThe same formUses 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' blockThe same formWritten into the sources the setting above gives them to
    Overload modeSettingsMerges built-in and remote rules after their defaults are written in

    How Merge from sources combines blocks

    KeySources agreeSources disagree
    exceptionsTaken as it isAutomatic added together: the set on screen first, then every other source's, without duplicates
    requestTypesTaken as it isYou 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
    preprocessorsTaken as it isYou choose one source's list, or the combined list, which is preselected
    active, description, historyBypassProtectionTaken as it isYou choose one source's value. The first source's is preselected

    Merge from sources: three defaults blocks

    1. You setYou chose Merge from sources in Manage rule defaults and ticked these three sources.
    2. You setYou copy the merged block into one of your sets and save. Until then nothing is stored.
    3. AutomaticFrom then on, every load writes the saved block into the sources it applies to.
    YoursYour defaults
    JSON
    {
      "defaults": {
        "requestTypes": ["main_frame"],
        "exceptions": [
          "^https:\\/\\/shop\\.example\\/cart"
        ]
      }
    }
    Built-inBuilt-in rules
    JSON
    {
      "defaults": {
        "requestTypes": [
          "main_frame",
          "xmlhttprequest"
        ],
        "historyBypassProtection": false,
        "exceptions": [
          "^https:\\/\\/shop\\.example\\/login"
        ]
      }
    }
    Remoterules.example.org
    JSON
    {
      "defaults": {
        "requestTypes": ["main_frame"],
        "description": "Shop rules"
      }
    }
    Merged defaults, with the preselected choices
    JSON
    {
      "defaults": {
        "requestTypes": [
          "main_frame",
          "xmlhttprequest"
        ],
        "exceptions": [
          "^https:\\/\\/shop\\.example\\/cart",
          "^https:\\/\\/shop\\.example\\/login"
        ]
      }
    }
    • AutomaticexceptionsAdded together from every source
    • You choosedescriptionYou choose: left out from Your defaults, Built-in rules · "Shop rules" from rules.example.org. Bold is preselected.
    • You chooserequestTypesYou choose: ["main_frame"] from Your defaults, rules.example.org · ["main_frame", "xmlhttprequest"] (combined) from Built-in rules. Bold is preselected.
    • You choosehistoryBypassProtectionYou 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.

    What each rule carries into a merge

    Merging never looks back at the original files. Everything it needs later is written onto the rules first.

    Carried on the ruleWritten whenUsed for
    Its file's defaults: requestTypes, exceptions, preprocessors, active, description, historyBypassProtectionIts file loadsWhere and how the rule runs
    Its provider's historyBypassProtectionProviders mergeWhether the rule runs on History API changes
    The file it came fromProviders mergeRemote Rules Health naming the file whose definition won
    Whether it may redirectIts remote file loads, from the capabilities you accepted for that fileA 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.

    Every defaults case

    1

    Each file's defaults stay with its rules

    1. You setYou turned on overload mode in settings, with built-in rules on and a remote rule file set up.
    2. AutomaticEvery load writes each file's own defaults into its rules, then merges them.
    Built-inBuilt-in rules
    JSON
    {
      "providers": {
        "shop": {
          "domainPatterns": ["||shop.example^"],
          "rules": ["qid"]
        }
      }
    }
    RemoteRemote file
    JSON
    {
      "defaults": {
        "requestTypes": ["main_frame"]
      },
      "providers": {
        "shop": {
          "domainPatterns": ["||shop.example^"],
          "rules": ["psc"]
        }
      }
    }
    What runs
    ||shop.example^
    • qidevery request typeBuilt-in
    • pscpage loads onlyRemote
    Merged provider as JSON
    JSON
    {
      "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.

    2

    The same rule, the remote file has a default

    1. You setYou turned on overload mode in settings, with built-in rules on and a remote rule file set up.
    2. AutomaticEvery load writes each file's own defaults into its rules, then merges them.
    Built-inBuilt-in rules
    JSON
    {
      "providers": {
        "shop": {
          "domainPatterns": ["||shop.example^"],
          "rules": ["token"]
        }
      }
    }
    RemoteRemote file
    JSON
    {
      "defaults": {
        "requestTypes": ["main_frame"]
      },
      "providers": {
        "shop": {
          "domainPatterns": ["||shop.example^"],
          "rules": ["token"]
        }
      }
    }
    What runs
    ||shop.example^
    • tokenpage loads onlyRemote
    • tokenreplacedBuilt-in
    Merged provider as JSON
    JSON
    {
      "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.

    3

    The same rule, the built-in file has a default

    1. You setYou turned on overload mode in settings, with built-in rules on and a remote rule file set up.
    2. AutomaticEvery load writes each file's own defaults into its rules, then merges them.
    Built-inBuilt-in rules
    JSON
    {
      "defaults": {
        "requestTypes": ["main_frame"]
      },
      "providers": {
        "shop": {
          "domainPatterns": ["||shop.example^"],
          "rules": ["token"]
        }
      }
    }
    RemoteRemote file
    JSON
    {
      "providers": {
        "shop": {
          "domainPatterns": ["||shop.example^"],
          "rules": ["token"]
        }
      }
    }
    What runs
    ||shop.example^
    • tokenevery request typeRemote
    • tokenreplaced, with its limitBuilt-in
    Merged provider as JSON
    JSON
    {
      "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.

    4

    Different exceptions in each file

    1. You setYou turned on overload mode in settings, with built-in rules on and a remote rule file set up.
    2. AutomaticEvery load writes each file's own defaults into its rules, then merges them.
    Built-inBuilt-in rules
    JSON
    {
      "defaults": {
        "exceptions": [
          "^https:\\/\\/shop\\.example\\/cart"
        ]
      },
      "providers": {
        "shop": {
          "domainPatterns": ["||shop.example^"],
          "rules": ["a"]
        }
      }
    }
    RemoteRemote file
    JSON
    {
      "defaults": {
        "exceptions": [
          "^https:\\/\\/shop\\.example\\/login"
        ]
      },
      "providers": {
        "shop": {
          "domainPatterns": ["||shop.example^"],
          "rules": ["b"]
        }
      }
    }
    What runs
    ||shop.example^
    • askips /cartBuilt-in
    • bskips /loginRemote
    Merged provider as JSON
    JSON
    {
      "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.

    5

    A file whose rules are off by default

    1. You setYou turned on overload mode in settings, with built-in rules on and a remote rule file set up.
    2. AutomaticEvery load writes each file's own defaults into its rules, then merges them.
    Built-inBuilt-in rules
    JSON
    {
      "defaults": { "active": false },
      "providers": {
        "shop": {
          "domainPatterns": ["||shop.example^"],
          "rules": [
            "a",
            {
              "matchPattern": "c",
              "active": true
            }
          ]
        }
      }
    }
    RemoteRemote file
    JSON
    {
      "providers": {
        "shop": {
          "domainPatterns": ["||shop.example^"],
          "rules": ["b"]
        }
      }
    }
    What runs
    ||shop.example^
    • csets "active": true itselfBuilt-in
    • bRemote
    • aoff by its file's defaultBuilt-in
    Merged provider as JSON
    JSON
    {
      "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.

    6

    A rule's own value beats its file's default

    1. AutomaticEvery load writes the file's defaults into its rules. Nothing for you to set.
    RemoteRemote file
    JSON
    {
      "defaults": {
        "requestTypes": ["main_frame"]
      },
      "providers": {
        "shop": {
          "domainPatterns": ["||shop.example^"],
          "rules": [
            {
              "matchPattern": "token",
              "requestTypes": ["script"]
            },
            "psc"
          ]
        }
      }
    }
    What runs
    ||shop.example^
    • tokenscripts: its own valueRemote
    • pscpage loads: the defaultRemote
    Rules after loading as JSON
    JSON
    {
      "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.

    7

    Your defaults for built-in and remote rules

    1. You setIn Manage rule defaults, you filled in your own block and chose Yours for built-in and remote rules.
    2. You setYou turned on overload mode in settings, with built-in rules on and a remote rule file set up.
    3. AutomaticEvery load writes your block into both files' rules instead of their own, then merges them.
    YoursYour defaults
    JSON
    { "requestTypes": ["main_frame"] }
    Built-inBuilt-in rules
    JSON
    {
      "providers": {
        "shop": {
          "domainPatterns": ["||shop.example^"],
          "rules": ["qid"]
        }
      }
    }
    RemoteRemote file
    JSON
    {
      "defaults": {
        "exceptions": [
          "^https:\\/\\/shop\\.example\\/cart"
        ]
      },
      "providers": {
        "shop": {
          "domainPatterns": ["||shop.example^"],
          "rules": ["psc"]
        }
      }
    }
    What runs
    ||shop.example^
    • qidpage loads: your defaultBuilt-in
    • pscpage loads; the file's /cart exception is ignoredRemote
    Merged provider as JSON
    JSON
    {
      "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.

    8

    You edited a file's defaults

    1. You setIn Manage rule defaults, you edited the remote file's defaults to an empty block.
    2. AutomaticEvery load uses your edit in place of the file's own block.
    RemoteRemote file
    JSON
    {
      "defaults": {
        "requestTypes": ["main_frame"]
      },
      "providers": {
        "shop": {
          "domainPatterns": ["||shop.example^"],
          "rules": ["psc"]
        }
      }
    }
    YoursYour edit of this file's defaults
    JSON
    {}
    What runs
    ||shop.example^
    • pscevery request type: your empty block replaced the file'sRemote
    Rules after loading as JSON
    JSON
    {
      "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.

    9

    A provider-level History API setting

    1. You setYou turned on overload mode in settings, with built-in rules on and a remote rule file set up.
    2. AutomaticEvery load copies the provider's setting onto its rules, then merges them.
    Built-inBuilt-in rules
    JSON
    {
      "providers": {
        "shop": {
          "domainPatterns": ["||shop.example^"],
          "historyBypassProtection": false,
          "rules": ["a"]
        }
      }
    }
    RemoteRemote file
    JSON
    {
      "providers": {
        "shop": {
          "domainPatterns": ["||shop.example^"],
          "rules": ["b"]
        }
      }
    }
    What runs
    ||shop.example^
    • askipped on History API changesBuilt-in
    • bruns on History API changes tooRemote
    Merged provider as JSON
    JSON
    {
      "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.

    10

    A complete provider with a requestTypes default

    1. You setYou turned on overload mode in settings, with built-in rules on and a remote rule file set up.
    2. You setYou accepted block for the remote file in Remote Rules Health.
    3. AutomaticEvery load writes the default into the remote provider as resourceTypes, so the two stay apart.
    Built-inBuilt-in rules
    JSON
    {
      "providers": {
        "trackers": {
          "domainPatterns": ["||tracker.example^"],
          "completeProvider": true
        }
      }
    }
    RemoteRemote file
    JSON
    {
      "defaults": {
        "requestTypes": ["main_frame"]
      },
      "providers": {
        "trackers": {
          "domainPatterns": ["||tracker.example^"],
          "completeProvider": true
        }
      }
    }
    What runs
    Built-in||tracker.example^blocks every request
    Remote||tracker.example^blocks page loads, once you accept block
    The remote provider after loading as JSON
    JSON
    {
      "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.

    What a remote file may do

    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.

    CapabilityThe file containsActive
    striprules, rawRules, referralMarketing or $removeparam entriesOn load
    rewriteAn entry with a replacePatternOn load
    exceptProvider exceptions or @@ entriesOn load
    redirectredirections, fieldRedirections or forceRedirectionAfter you accept
    blockA provider with "completeProvider": trueAfter you accept

    Built-in and custom rules hold every capability. A file that gains a capability in an update waits for acceptance again.

    At run time

    Source: partials/rules.html on the website branch.