# Declarative Net Request

> Install fixed block, redirect, and allow rules through Extended Preferences or the Provision rules file.

Source: https://console.getchrovia.com/en/docs/sdk-declarative-net-request

**Entitlement:** `declarativeNetRequest`. **Configuration:** `internal.declarative_net_request.rules` and/or `<Provision root>/dnr_rules.json`. These are kernel-owned fixed rules, not calls to an extension's dynamic-rules API.

## Add an EP rule

```json
{
  "internal": {
    "declarative_net_request": {
      "rules": [
        {
          "id": 1,
          "priority": 1,
          "action": { "type": "block" },
          "condition": {
            "urlFilter": "||example.com/sdk-block",
            "resourceTypes": ["main_frame"]
          }
        }
      ]
    }
  }
}
```

Merge the document and sign it when required. Fully restart, then navigate to `https://example.com/sdk-block` to verify blocking. Rule conditions use Chromium DNR syntax, **not** the wildcard syntax used by `network.intercept()` and `navigation_redirect`.

## Choose matching conditions

Use the [RuleCondition reference](https://developer.chrome.com/docs/extensions/reference/api/declarativeNetRequest#type-RuleCondition) for field syntax and the [Redirect reference](https://developer.chrome.com/docs/extensions/reference/api/declarativeNetRequest#type-Redirect) for destination options. Apply the Chrovia restrictions below; not every Chrome extension rule option is supported here.

| Field | Usage |
| --- | --- |
| `urlFilter` | DNR URL-filter string; `*` is a wildcard, `^` matches a separator or URL end, and the double-bar prefix used above anchors a hostname |
| `regexFilter` | RE2 regular expression; use instead of `urlFilter`, not alongside it |
| `isUrlFilterCaseSensitive` | Boolean; default false |
| `requestDomains`, `excludedRequestDomains` | Destination-domain arrays; entries also match subdomains |
| `initiatorDomains`, `excludedInitiatorDomains` | Arrays of domains that initiate a request; not necessarily the destination host |
| `resourceTypes`, `excludedResourceTypes` | Resource-type arrays, such as `main_frame`, `sub_frame`, `script`, `image`, or `xmlhttprequest` |
| `requestMethods`, `excludedRequestMethods` | Lowercase method arrays, such as `get` or `post` |
| `domainType` | `firstParty` or `thirdParty`; omit to match either |

All supplied conditions must match. Do not use `tabIds` or `excludedTabIds`: tab-specific filters are not supported for these fixed rules. Explicitly include `main_frame` when you want top-level navigations covered.

For example, this standalone Provision rules array blocks only POST requests to the API host:

```json
[
  {
    "id": 2,
    "priority": 1,
    "action": { "type": "block" },
    "condition": {
      "requestDomains": ["api.example.com"],
      "requestMethods": ["post"],
      "resourceTypes": ["xmlhttprequest"]
    }
  }
]
```

## Actions and precedence

| Action | Configuration |
| --- | --- |
| `block` | `{"type":"block"}` |
| `redirect` | `{"type":"redirect","redirect":{"url":"https://example.org/"}}` |
| `allow` | `{"type":"allow"}`; can override a lower-priority matching fixed block |

Use positive rule IDs that are unique across EP and Provision, and explicit positive priorities. For an exception, assign the matching allow rule a higher priority than the block. Specify `resourceTypes` intentionally; a `main_frame` rule does not cover every subresource.

Only `block`, `redirect`, and `allow` are supported. `allowAllRequests`, `upgradeScheme`, `modifyHeaders`, and redirect `extensionPath` are not supported.

For redirects, use `redirect.url` for a fixed absolute destination, `redirect.transform` to change URL components, or `redirect.regexSubstitution` with a `regexFilter` condition. Choose one destination form per rule. For example, `{"type":"redirect","redirect":{"transform":{"scheme":"https","host":"example.org"}}}` changes those URL components while retaining the others. Limit the condition to the original host to avoid a redirect loop.

## Distribute through Provision

For installation-wide rules, put the **rules array itself** in `dnr_rules.json`, not an object containing `internal` or `rules`:

```json
[
  {
    "id": 1001,
    "priority": 1,
    "action": { "type": "block" },
    "condition": {
      "urlFilter": "||example.com/sdk-install-block",
      "resourceTypes": ["main_frame"]
    }
  }
]
```

Both files require `declarativeNetRequest`. Protect access to `dnr_rules.json` separately; a signed EP file does not prevent edits to it.

After installing or updating the browser package, confirm that `dnr_rules.json` is present in the Provision root actually used by that installation. Keep it alongside `Extensions`, not inside a plugin directory. See [Provision packaging](https://console.getchrovia.com/en/docs/sdk-provision).

## Limits and troubleshooting

Fully restart after editing fixed rules; there is no Chrovia JS method for updating them live. Malformed entries are skipped and logged. Invalid rules or exceeding rule limits can prevent a ruleset from loading. Unsupported actions do not silently become blocks.

Verify the effective URL, resource type, unique IDs, priorities, License, and EP signature. Fixed rules do not depend on a live Service Worker callback. Use [network interception](https://console.getchrovia.com/en/docs/sdk-network-intercept) only when you need an application decision per matching request.
