Reference

Linkumori CLN Format 1.0

Status
Current
Version
CLN 1.0
Published
Oct 2, 2026
Editor
@Subham
Source
docs/filter-syntax.md

This page describes CLN Format 1.0 in its final form. The changes from the earlier 1.0 text, and why, are in CLN Format 1.0 (Final).

Linkumori CLN (Clean Link Notation) is the JSON rule format Linkumori uses to strip tracking parameters, rewrite URL text, and redirect around trackers. A rule file is one JSON object with a providers object (and, optionally, cln, metadata, defaults and, in a remote file, patches). Each key under providers is a name you choose; its value is a provider object.

The optional top-level cln key names the format version. Its only valid value is "1.0"; a file without it loads as 1.0 too, and a file with any other value is rejected (a remote file is not loaded and Remote Rules Health reports it; a built-in or custom file fails lint-rules). It is not called version because the ClearURLs new rule format already uses that key.

JSON
{
  "cln": "1.0",
  "providers": {
    "amazon": {
      "domainPatterns": ["||amazon.*^"],
      "rules": ["qid", "$removeparam=/^pd_rd_[a-z]*$/i"],
      "referralMarketing": ["tag"],
      "exceptions": ["||amazon.com^/gp/redirector.html"],
      "rawRules": ["\\/ref=[^/?]*"]
    }
  }
}

Provider fields

FieldWhat it holds
domainPatternswhich URLs this provider handles — one pattern or an array of patterns (§Patterns below). Use this or urlPattern, never both. Example: "domainPatterns": ["||amazon.*^"]
urlPatterndoes the same job as domainPatterns, but as one regex string tested against the full URL, case-insensitive. Example: "urlPattern": "^https?:\\/\\/(?:[a-z0-9-]+\\.)*?google\\."
indexPatternonly meaningful alongside urlPattern — a ||host^-style hint (or array of them) so the engine only checks this provider against matching hosts, instead of testing the regex on every URL. Example: "indexPattern": "||google.com^"
rulesarray of query/fragment parameters to strip. Example: "rules": ["utm_source", "fbclid"]
referralMarketingsame entry syntax as rules, but this array only runs while the person has not turned on "allow referral marketing" in settings. Example: "referralMarketing": ["ref", "tag"]
rawRulesarray of regexes run against the whole URL string; every match is deleted outright. Example: "rawRules": ["\\/ref=[^/?]*"]
exceptionsarray of URLs (regex or domain pattern) this provider leaves completely alone — none of its other fields run when one matches. Example: "exceptions": ["||accounts.google.com^"]
redirectionsarray sending matching requests to a different URL instead of editing them. Example: "redirections": ["||go.example.com^$redirect=https://example.com/"]
fieldRedirectionsarray naming a parameter whose own value becomes the new URL — used for "click-through" redirect links. Example: "fieldRedirections": ["redirect", "continue_url"]
completeProviderboolean; true blocks every request this provider matches outright (a full domain/URL block, not just parameter stripping)
forceRedirectionboolean; true means a redirect on a page load (main_frame) navigates the whole browser tab, not just the underlying network request
methodsarray restricting this provider to specific HTTP methods. Example: "methods": ["GET"]
resourceTypesarray restricting this provider to specific request types. Example: "resourceTypes": ["main_frame", "xmlhttprequest"]. Left out, the provider handles every request type
historyBypassProtectionboolean, default true; false makes this whole provider skip same-page URL changes made via the History API (pushState/replaceState), while still applying to ordinary network requests
activeboolean; false disables the entire provider without deleting it from the file

Patterns

Used in domainPatterns, and in front of exceptions, redirections, $removeparam, and raw rules.

PatternMatches
||example.com^example.com and every subdomain
||example.*^example on any suffix — .de, .co.uk, …
||example.com^/paththat host when the path starts with /path
|https://example.com/URLs starting with exactly this text
…|URLs ending with exactly this text
/regex/ithe full URL as a regex
example.com/path (no leading |)contains this text anywhere
*everything

^ means end-of-host or any separator (/ ? : or end of URL). * is a wildcard. A single \| needs a scheme after it (\|https://…) — for a domain you always want \|\|.

Worked example

||smile.amazon.*^
PieceMeaning
||domain anchor — matches the host and every subdomain
smile.amazonthe literal label required
.*any public suffix — .com, .co.jp, .de, …
^end of host — nothing else may follow directly

rules / referralMarketing

Each entry removes a parameter, from the query (?a=1) or fragment (#a=1):

EntryRemoves
"utm_source"that exact parameter
"utm_[a-z]+"any parameter whose whole name matches
"$removeparam=fbclid"see below — lets you add domain/method/party limits

To strip a parameter on only some of a provider's URLs, put a pattern in front of $removeparam:

JSON
"rules": ["qid", "||amazon.de^$removeparam=tag"]

referralMarketing uses the exact same syntax, but only runs while the person hasn't turned on "allow referral marketing."

$removeparam filters

Syntax

[@@][pattern]$removeparam[=value][,modifier,modifier,…]

Five pieces, four of them optional:

Value

The first character after = decides what's targeted:

ValueRemoves
(nothing after =, or no = at all)every parameter
~nameevery parameter except name
/regex/iany parameter whose name — or name=value together — matches; add i for case-insensitive
|prefixany parameter whose name starts with prefix
namejust that one parameter, by exact name
\~name, \|name, \/name/the parameter with that exact name, ~, | or / included

A backslash makes the next character literal, so any parameter name can be targeted:

ValueRemoves the parameter named
\~foo~foo
\|foo|foo
\/foo//foo/
a\,ba,b — the comma doesn't start the modifier list
\\foo\foo

Modifiers

Everything after the first comma — one comma-separated condition per modifier. Every modifier listed must hold; there's no "or" between them. ~ in front of a domain, method, or request-type value excludes it instead of requiring it. The four *-party modifiers are mutually exclusive with each other (combining opposites is rejected).

ModifierGroupMeaning
domain=a.com|~b.comWhere from/tothe page that made the request must (or, with ~, must not) be one of these — a |-separated list, regex values allowed
to=a.com|~b.comWhere from/tothe request's own target must (or must not) be one of these, independent of what page made it
method=get|~postWhere from/tothe HTTP method must (or must not) be one of get, head, options, post, put, patch, delete, connect
first-partyPartyrequest target shares the page's registrable domain — a.example.com and b.example.com count as the same party
third-partyPartyrequest target has a different registrable domain than the page
strict-first-partyPartyrequest target is the exact same hostname as the page
strict-third-partyPartyrequest target is any different hostname than the page — even a subdomain counts as third-party here
documentRequest typethe top-level page load itself
subdocumentRequest typean iframe's own document
scriptRequest typea JavaScript file
stylesheetRequest typea CSS file
imageRequest typean image file
imagesetRequest typeone candidate of an <img srcset> set
mediaRequest typean audio or video file
fontRequest typea web font file
objectRequest typeembedded plugin content (<object>, <embed>)
xmlhttprequestRequest typean XHR or fetch() call made by page script
websocketRequest typea WebSocket connection
pingRequest typea navigator.sendBeacon() or link-ping request
otherRequest typeanything not covered by the types above
match-caseMiscparameter-name comparison becomes case-sensitive (default: case-folded)
history-bypass-protection=falseMiscthis filter is skipped on same-page URL changes (pushState/replaceState), though it still applies to normal network requests. Accepts true/false, 1/0, or yes/no

Any request-type row above can be written with a leading ~ (e.g. ~xmlhttprequest) to exclude that type instead of requiring it.

Worked example

||example.com^$removeparam=sid,domain=~partner.com,method=get,third-party
PieceMeaning
||example.com^pattern — only on example.com
$removeparam=sidvalue — strip the sid parameter
domain=~partner.commodifier — but not when the page making the request is partner.com
method=getmodifier — and only for GET requests
third-partymodifier — and only when that page is a different registrable domain than example.com

All four conditions must hold at once for sid to be stripped.

Exceptions (@@)

A filter beginning with @@ keeps the parameter instead of removing it — the pattern and modifiers work exactly the same way, they just flip the outcome:

JSON
"rules": ["$removeparam=ref", "@@||github.com^$removeparam=ref"]

Here every provider-matched URL loses ref, except on github.com, where it's kept. An @@ entry also reaches into other providers' filters when the request comes from a page this provider matches — handy for carving out one site from a site-wide rule defined elsewhere.

An @@ entry isn't a step with a place in the run order — where you list it doesn't matter, and it can't carry an order. For each parameter, the provider checks its @@ entries first and its $removeparam filters second, and a matching @@ entry keeps the parameter. It only guards against $removeparam filters: a plain rules entry such as "ref" still removes ref (use a rule object's exceptions for that), and raw rules have their own @@…$rawrule= entries. Its pattern and modifiers are checked against the URL as the provider received it at the start of the current cycle — before the provider's raw rules run — so an @@ entry scoped to a path that a raw rule deletes still matches:

JSON
"rawRules": ["\\/ref=[^/?]*"],
"rules": ["$removeparam=tag", "@@||shop.example^/ref=$removeparam=tag"]

For https://shop.example/ref=abc?tag=1 the raw rule deletes /ref=abc, and tag is kept: the @@ pattern is checked against the URL that still has /ref=abc.

rawRules

Regexes run against the whole URL — every match gets deleted:

JSON
"rawRules": ["\\/ref=[^/?]*"]

They run before rules, so they can strip things that aren't name=value pairs — like Amazon's /ref=… path segment. A raw rule can also carry a pattern and $removeparam-style options, with rawrule= last: \|\|amazon.*^/dp/$rawrule=\\/ref=[^/?]*. An @@…$rawrule= entry stops raw rules from running instead of matching anything itself. With nothing after rawrule= it stops every raw rule of the provider where its pattern matches; with a regex it stops the raw rules with that regex; as a rule object with a targetId it stops only the raw rule with that id or alias.

Worked example

||amazon.*^/dp/$rawrule=\/ref=[^/?]*
PieceMeaning
||amazon.*^/dp/pattern — only on Amazon URLs whose path starts with /dp/
$rawrule=switches this from a plain regex into a pattern-scoped one
\/ref=[^/?]*the regex — deletes /ref= and everything after it, up to the next / or ?

exceptions

Each entry is a regex against the full URL, or a domain pattern starting with \|:

JSON
"exceptions": ["^https?:\\/\\/mail\\.google\\.com\\/mail\\/u\\/", "||accounts.google.com^"]

If the URL matches, none of the provider's rules run for that request.

Worked example

^https?:\/\/mail\.google\.com\/mail\/u\/
PieceMeaning
^https?:\/\/start of the URL, http or https
mail\.google\.comthe literal host
\/mail\/u\/the literal path prefix that must follow

Any URL matching this stops the whole provider — Gmail keeps its tracking-looking parameters intact.

redirections

Either a regex with exactly one capture group — the request goes to whatever that group captures:

^https?:\/\/(?:[a-z0-9-]+\.)*?google(?:\.[a-z]{2,}){1,}\/url\?.*?(?:url|q)=(https?[^&]+)

Or a fixed domain redirect:

JSON
"||go.example.com^$redirect=https://example.com/"

Redirect targets

A redirect only happens to an absolute http or https URL with a host. This holds for all three kinds of target — the capture group (or replacePattern) of a redirections regex, the fixed target of a $redirect= entry, and the parameter value a fieldRedirections entry picks — and is checked after the entry's preprocessors (and after percent-decoding). An invalid target makes the entry count as not matching: no redirect happens, and the provider's later stages run on the unchanged URL. lint-rules rejects a $redirect= entry whose fixed target isn't http or https.

TargetRedirects?
https://real.example/pageyes
https%3A%2F%2Freal.example%2Fpageyes, to https://real.example/page
javascript:alert(1), ftp://files.example/xno — scheme is not http or https
//real.example/page, /local/page, real.example/pageno — not an absolute URL

A raw rule whose result has a different scheme, host or port from its input is a redirect too, whether it rewrites with a replacePattern or only deletes text (secure- deleted from https://secure-bank.example/ lands on another site): it needs a valid target, and in a remote file the redirect capability (§Remote file capabilities). Otherwise the rule leaves the URL as it was.

Worked example

^https?:\/\/(?:[a-z0-9-]+\.)*?google(?:\.[a-z]{2,}){1,}\/url\?.*?(?:url|q)=(https?[^&]+)
PieceMeaning
(?:[a-z0-9-]+\.)*?any subdomains in front of google
google(?:\.[a-z]{2,}){1,}google on any public suffix
\/url\?the redirect endpoint's path
(?:url|q)=either a url= or q= parameter introduces the target
(https?[^&]+)the one capture group — its contents become the redirect URL

fieldRedirections

Names a parameter directly — its own value becomes the new URL, no regex needed:

JSON
"fieldRedirections": ["redirect", "continue_url"]

Same entry types as rules (name, name regex, or $removeparam filter used just to pick the parameter). Whichever matching parameter comes first in the URL wins.

Worked example

Given https://site.example/away?redirect=https://real-destination.example/page:

PieceMeaning
redirectthe parameter name listed in fieldRedirections
https://real-destination.example/pageits value — becomes the entire new request URL, verbatim, as long as it is a valid redirect target (§Redirect targets)

Rule objects

Any entry, in any list above, can be an object instead of a string — for a stable id, a custom run order, or a rewrite instead of a delete:

JSON
{
  "id": "token-rewrite",
  "matchPattern": "token",
  "replacePattern": "clean-§1§",
  "requestTypes": ["main_frame"],
  "exceptions": ["^https:\\/\\/example\\.com\\/keep"],
  "order": 5,
  "active": true
}
KeyDoes
matchPatternrequired — the exact string that would otherwise be written as a plain entry (a parameter name, a name regex, a $removeparam filter, a raw regex, a domain pattern, etc., depending which list this object sits in)
ida stable identifier of your choosing (letters, digits, -, _) that the on/off toggle keys off. Leave it out and one is generated from the list and matchPattern text — fine until you edit that text, which changes the generated id and loses anyone's toggle setting
aliasesarray of this rule's previous id values. When you rename id, add the old one here so a setting someone saved under the old id keeps applying
replacePatternpresent → rewrite the matched text instead of deleting it. Reference capture groups from matchPattern (or, for a parameter-based rewrite, the parameter's value) as §1§, §2§, … Example: "replacePattern": "clean-§1§"
preprocessorsarray of transforms applied to captured values before they're used in a rewrite or redirect, in order. Each is {"type": <name>, "inputs": "all"} or an index array. Types: urlEncode, urlDecode, doubleUrlEncode, doubleUrlDecode, base64Encode, base64Decode
requestTypesarray restricting this one rule to specific request types (same names as the $removeparam request-type option above). Cleaning without a request — Copy clean link, the Cleaning tool, a page changing its URL with the History API — counts as main_frame
exceptionsarray of URLs (regex) this specific rule skips, independent of the provider's own exceptions
ordernumber controlling when this entry runs relative to the other entries of its stage — lower numbers run earlier. Raw rules always run before field rules, whatever their order; inside a stage, every entry with an order runs before every entry without one. "order": null means "no order, and don't inherit one" (§Same text twice). $removeparam filters and @@ entries take no order, null included — lint-rules rejects it there. The exact sequence is under §Processing order
referralMarketingtrue, set on an entry inside rules, makes it also behave as a referral-marketing rule without moving it into the separate referralMarketing array
activefalse disables just this one rule, leaving it in the file for later re-enabling
flagsregex flags for this entry's matchPattern, as a string. Left out, an entry uses i (case-insensitive); a raw rule uses gi, or g with match-case. A rule's own flags always wins. Example: "flags": "g"
historyBypassProtectionboolean; the same switch as the provider key above, for this one rule. It beats the provider's value and the file default
descriptiona note for people reading the file; the engine ignores it. It must be a string
targetIdonly on an @@…$rawrule= exception: stops just the raw rule whose id or one of whose aliases equals this value, instead of every raw rule with that regex. Example: { "matchPattern": "@@||amazon.*^$rawrule=", "targetId": "strip-ref" }

Worked example

Using the token-rewrite object above, against a URL containing ?token=abc123:

PieceMeaning
matchPattern: "token"selects the token parameter, same as a plain entry in rules
replacePattern: "clean-§1§"§1§ is the parameter's current value; the new value becomes clean- followed by it
order: 5this rewrite runs after every raw rule, then after any of the provider's rules/referralMarketing entries with a lower order, and before every field entry that has no order

Result: ?token=abc123 becomes ?token=clean-abc123.

defaults

A top-level defaults block gives every rule of the file values it doesn't set itself, like the ClearURLs new rule format's defaults:

JSON
{
  "defaults": { "requestTypes": ["main_frame"], "exceptions": ["^https:\\/\\/example\\.com\\/keep"] },
  "providers": { … }
}
KeyDefault for each rule's…
activeactive; false switches every rule of the file off unless it says "active": true
descriptiondescription
requestTypesrequestTypes; "all" (or leaving it out) means every type
preprocessorspreprocessors
exceptionsexceptions
historyBypassProtectionhistoryBypassProtection

Processing order

For each matching provider: exceptions (skip if matched) → redirections → fieldRedirections → completeProvider → rawRules → rules/referralMarketing → $removeparam filters. A rule's order can move it earlier or later within its own stage, never across stages. First provider to change, redirect, or block the URL wins, then the cycle repeats on the new URL (§Termination).

Run order

Stages 5 and 6 — every rawRules, rules and referralMarketing entry of the provider, bare strings and rule objects alike, except $removeparam filters and their @@ exceptions, which always run afterwards (§Exceptions) — run in ascending order of one sort key:

(stage, orderGroup, order, rank, arrayIndex)

PartValue
stage0 for a rawRules entry; 1 for a rules or referralMarketing entry
orderGroup0 if the entry is a rule object with a numeric order; 1 otherwise
orderthe entry's own order. Compared only between two orderGroup 0 entries of the same stage. Negative numbers and fractions are allowed
rankwhich array the entry sits in, from the table below
arrayIndexthe entry's zero-based position in its own array, with no exceptions
Arraystagerank
rawRules00
rules10
rules, object with "referralMarketing": true11
referralMarketing12

Entries that are off ("active": false, toggled off, or referral-marketing entries while the person allows referral marketing) are left out, and entries with the same text count once (§Same text twice). Read the key left to right; the first part that differs decides:

Same text twice

Two entries with the same matchPattern text in one group are one entry, and only one definition of it takes effect. The groups are:

GroupHolds
rawrawRules
fieldrules entries without "referralMarketing": true
referralrules objects with "referralMarketing": true, then referralMarketing
First definitionLater definitionWhat runs
token, order: 1"token"order: 1; first definition's index
token, order: 1token, order: 50order: 50; own index
token, order: 1token, "order": nullno order; first definition's index
"token"token with a replacePatternthe rewrite, at the first definition's index

Inheritance exists for merges across files, not as an authoring feature: lint-rules and the editor reject two different entries with the same text in one array, and warn about an exact copy. They also warn about the same text in rules and referralMarketing, and in rules with and without "referralMarketing": true. $removeparam filters don't count here — each one runs.

Overload mode

In Patch mode + merge and No patch mode + merge, built-in rules and remote rule files load together, and one site can have a provider in more than one of them. Provider merging in either mode follows these rules:

The overload settings offer three strategies: Patch mode only applies remote patches to the built-in rules and omits remote provider rules; Patch mode + merge merges built-in and remote providers, then applies patches; No patch mode + merge merges the providers and skips remote patches. The strategy is used only while overload mode is enabled. If built-in rules are disabled, patch-only mode has no built-in rules to patch.

  1. Load order. Your remote files are merged with each other first, in the order you list them. The result is then merged with the built-in rules: built-in providers first, remote ones after.
  2. Which providers merge. Only providers with the same domainPatterns (or the same urlPattern) and the same methods, resourceTypes, completeProvider and forceRedirection. Any other provider stays separate and keeps its own rules.
  3. Joining the lists. Each of rules, rawRules and referralMarketing is joined in load order — built-in entries first, then each remote file's.
  4. Exact copies. Only entries that are exactly alike count once while joining. order is part of what makes two entries alike, "order": null included.

The merged provider then runs like any other, so §Same text twice applies: after a merge the last definition is the remote one — with several remote files, the last-listed file's. A remote copy without an order keeps the order of the copy it replaces; to drop it, the remote copy sets "order": null.

Built-inRemoteWhat runs
token, order: 1token, order: 50token at order: 50
token, order: 1"token"token at order: 1
token, order: 1token, "order": nulltoken with no order
token, order: 1file 1: token, order: 20; file 2: token, order: 30token at order: 30
token, order: 1file 1: token, order: 20; file 2: "token"token at order: 20
a order: 1, b order: 2b order: 1, a order: 2b, then a
fromBuiltIn, order: 5fromRemote, order: 5both; fromBuiltIn first
token order: 1 on ||site.example^token order: 50 on ||other.example^not merged — two providers
rules: "tag"referralMarketing: "tag"the referralMarketing entry replaces the rules one while referral-marketing rules run

Remote Rules Health lists each rule a merge replaces as a notice naming the file whose definition won; an error is reserved for a file or entry that did not load. It also warns when a merge puts the same text in rules from one file and in referralMarketing (or a rules entry with "referralMarketing": true) from another.

Worked example

JSON
{
  "cln": "1.0",
  "providers": {
    "shop": {
      "domainPatterns": ["||shop.example^"],
      "rawRules": [
        "\\/ref=[^/?]*",
        { "id": "strip-jsessionid", "matchPattern": ";jsessionid=[^/?#]*", "order": 20 }
      ],
      "rules": [
        "utm_source",
        { "id": "token-rewrite", "matchPattern": "token", "replacePattern": "clean-§1§", "order": 5 },
        "fbclid",
        { "id": "aff-id", "matchPattern": "aff_id", "referralMarketing": true },
        { "id": "sid", "matchPattern": "sid", "order": 20 },
        "$removeparam=/^pk_/"
      ],
      "referralMarketing": ["tag"]
    }
  }
}

With "allow referral marketing" off, the provider runs:

#EntrySort key
stageorderGrouporderrankarrayIndex
1rawRules[1] strip-jsessionid002001
2rawRules[0] "\\/ref=[^/?]*"01–00
3rules[1] token-rewrite10501
4rules[4] sid102004
5rules[0] "utm_source"11–00
6rules[2] "fbclid"11–02
7rules[3] aff-id11–13
8referralMarketing[0] "tag"11–20

Then rules[5] "$removeparam=/^pk_/", with the provider's other $removeparam filters — it's outside the sort. With "allow referral marketing" on, 7 and 8 are left out and the rest keep their order. Both raw rules finish before token-rewrite reads the URL.

Worked example — whole numbers

JSON
{
  "cln": "1.0",
  "providers": {
    "numbers": {
      "domainPatterns": ["||numbers.example^"],
      "rawRules": ["r", "3"],
      "rules": ["a", "20", { "matchPattern": "9", "referralMarketing": true }, "b"],
      "referralMarketing": ["rm", "5"]
    }
  }
}

With "allow referral marketing" off:

#EntrySort key
stageorderGrouporderrankarrayIndex
1rawRules[0] "r"01–00
2rawRules[1] "3"01–01
3rules[0] "a"11–00
4rules[1] "20"11–01
5rules[3] "b"11–03
6rules[2] "9"11–12
7referralMarketing[0] "rm"11–20
8referralMarketing[1] "5"11–21

Every entry runs where the file lists it. Rows 6 to 8 follow the unmarked rules entries because of rank, not because of their text.

Rule ids and toggles

A rule's on/off toggle is keyed by provider and rule together, providerKey::id (for example shop::token-rewrite), so two providers can use the same rule id without sharing a switch. The custom rules editor may also save it under the provider's match pattern (domainPattern:||shop.example^::token-rewrite); both forms work. An id can't contain a colon, so a key splits at its last ::.

The built-in rules define token with "id": "token-rewrite" in provider shop, and the person switches shop::token-rewrite off. A remote file then replaces that rule with a definition whose id is tok: the remote definition runs, the saved toggle keeps it off, and both shop::tok and shop::token-rewrite switch it.

Termination

Processing a request always ends:

Remote file capabilities

A remote file's capabilities are derived from its content when it loads; a file does not declare them.

CapabilityA file has it when it containsActive on load
stripa rules, rawRules or referralMarketing entry, or a $removeparam filteryes
rewritean entry with a replacePatternyes
excepta provider exceptions entry or an @@ entryyes
redirecta redirections or fieldRedirections entry, or forceRedirectionafter acceptance
blocka provider with "completeProvider": trueafter acceptance

Rule patches

A remote rule file can replace rules that are already loaded, from the built-in rules or from another remote file, without publishing a whole copy of them. It lists the replacements in a top-level patches array:

JSON
{
  "cln": "1.0",
  "patches": [
    {
      "target": "amazon::field-qid",
      "section": "rules",
      "replace": { "matchPattern": "qid", "requestTypes": ["main_frame"] },
      "description": "Only strip qid on page loads"
    },
    {
      "target": "domainPattern:||amazon.*^::strip-ref",
      "section": "rawRules",
      "replace": "\\/ref=[^/?#]*"
    }
  ]
}
KeyDoes
targetrequired — the rule to replace, written like its on/off toggle key (§Rule ids and toggles): providerKey::id, domainPattern:<pattern>::id or urlPattern:<regex>::id. The id can be the rule's id, one of its aliases, or its generated id
sectionrequired — the list the rule is in: rules, referralMarketing, rawRules, exceptions, redirections or fieldRedirections
replacerequired — the new rule: a plain entry or a rule object, as it would be written in that list
descriptiona note for people reading the file; it must be a string

Possible 2.0 direction

Left for 2.0 (see CLN Format 1.0 (Final)):

User whitelist

Separate from a provider's exceptions — this is a site the person has told the extension to leave alone entirely, no rule file involved. Entries look like example.com, *.example.com (root + subdomains), or example.* (any suffix). Whitelisting a page also covers everything it loads.

Generated from docs/filter-syntax.md on the main branch. Found a problem? Open an issue.