This guide is for users who have enabled a configuration in Shadowrocket and want to add or troubleshoot blocking rules. First, distinguish match conditions from policies; then use a minimal rule example to check evaluation order. Finally, learn why same-domain requests, encrypted connections, and cached content limit blocking. All domains and addresses are examples. Any connection testing assumes you already have your own service provider and subscription.
1. REJECT Is a Policy, Not a Content-Detection Rule
Rules in Shadowrocket typically combine a match condition with a policy. For example, in DOMAIN-SUFFIX,example.com,REJECT, the first two fields determine which connections match, while the final REJECT denies a matching connection. It won’t detect and remove content just because a page contains a particular word, image, or layout.
With configuration-based routing, the process can be understood in five steps. This describes rule evaluation; it doesn’t mean the client can always obtain a full domain name for every connection, or read the contents of encrypted requests.
Rules are generally checked from top to bottom, and the first match determines the policy. As a result, a specific blocking rule at the end of a file may never run: the connection may already have matched a broader rule with DIRECT or another policy. When troubleshooting, check both what matched and which policy was ultimately applied. Searching the file for REJECT alone isn’t enough.
2. Check DOMAIN and DOMAIN-SUFFIX with a Minimal Rule Set
Back up the current configuration in Config first, then edit a copy for testing. The snippet below shows only how rules in [Rule] match; it is not a complete configuration to replace your existing settings. The reserved example domains are not real blocking targets.
[Rule]
DOMAIN,account.example.com,DIRECT
DOMAIN-SUFFIX,example.com,REJECT
FINAL,DIRECT
With this order, account.example.com matches the exact exception first. media.example.com and the root domain example.com are rejected by the suffix rule, while other connections fall through to FINAL. DIRECT is used here only to illustrate the logic; it doesn’t mean you should route all unmatched traffic directly in practice.
Exact exception
- Keyword
- DOMAIN
- Match value
- account.example.com
- Policy
- DIRECT
- Position
- Before the broader suffix rule
Allows only this hostname; it does not automatically allow subdomains.
Suffix blocking
- Keyword
- DOMAIN-SUFFIX
- Match value
- example.com
- Policy
- REJECT
- Coverage
- Root domain and its subdomains
Don’t include https://, a path, or a port in the suffix field, and don’t add an asterisk.
After saving, make sure the copy is selected as the active configuration in Config, then choose Config under Home → Global Routing. Proxy and Direct are not substitutes for enabling configuration rules. If you use Scene, first check the routing behavior it applies. Recreate the test connection after making changes so you don’t reuse an existing connection from before the update.
Takeaway: Start with an Exact Hostname, Then Expand
Add a DOMAIN rule first and check the match record. Once you’ve confirmed the target and scope, decide whether to use DOMAIN-SUFFIX. Don’t start by blocking an entire platform’s root domain.
3. REJECT vs. REJECT-DROP: How They Deny Connections
Both REJECT and REJECT-DROP deny connections, but they handle the rejection differently. REJECT typically makes a connection fail quickly, while REJECT-DROP silently discards it, leaving the requesting app to time out. The actual error behavior also depends on TCP or UDP, the app’s retry logic, and the current implementation; not every app is guaranteed to stop requesting immediately. Check the current rule editor and supported policies for the available names.
| Policy | Behavior | What to watch for |
|---|---|---|
REJECT | Rejects the connection, usually reporting failure quickly | The app may show an error immediately or switch to a backup hostname |
REJECT-DROP | Silently drops the connection and waits for the requester to time out | The app may keep loading for a while or repeatedly send requests |
Neither policy automatically makes a page hide content correctly. After a failed request, an app may leave an empty space, show an error icon, or use a backup endpoint. REJECT-DROP also doesn’t match more domains: if a connection didn’t match the rule in the first place, changing the final policy won’t broaden its scope.
- To verify whether a rule matched, check the request log first rather than guessing from how long the loading animation lasts.
- If loading continues indefinitely, first check whether you blocked a login, authentication, or initialization endpoint.
- When switching rejection policies, change one variable at a time and repeat the same action to compare the results.
4. Where Domain Blocking Falls Short: Same-Domain Content, HTTPS, and Shared IPs
Domain rules are usually easier to scope when the resource you want to block uses its own domain. But if both normal content and the target resource come from api.example.com, using /content and /promotion paths, DOMAIN and DOMAIN-SUFFIX can’t tell them apart. Blocking the hostname may also break the main content, login, and account status.
For common HTTPS connections, such as those using destination port 443, domain rules don’t decrypt HTTP requests. URL paths, query parameters, and response bodies are encrypted, so adding a path to a domain rule won’t enable content-level filtering. The rule examples here don’t involve HTTPS decryption.
| Request type | Can domain rules distinguish it? | Limit |
|---|---|---|
track.example.com and api.example.com | Can be matched separately by hostname | You still need to verify that the first hostname isn’t needed for essential functionality |
| Two HTTPS paths on the same hostname | DOMAIN alone can’t distinguish paths | Don’t put a full URL in the domain field |
| Multiple domains share one service IP address | Blocking by IP can’t preserve domain-level granularity | May also affect other, legitimate services |
| App reads from local cache | No new connection means there’s nothing to match | Content still appearing on the page doesn’t mean the rule failed |
Replacing a domain rule with IP-CIDR won’t solve the problem of mixed content on the same domain. For example, IP-CIDR,192.0.2.10/32,REJECT rejects the example IPv4 address, not just one website; 192.0.2.0/24 covers a much larger range. Real services may also use multiple addresses or IPv6. Expanding the range arbitrarily can block unrelated traffic without guaranteeing complete coverage.
Takeaway: Preserve Functionality First When Content Shares a Domain
When essential features and the target resource share a hostname, remove the broad rejection rule first to restore functionality. Add a narrower rule only after you’ve identified a request hostname you can verify independently. Don’t use a broad IP range as a substitute for identifying the content.
5. When a Rule Doesn’t Work, Troubleshoot Step by Step
Still seeing the original content doesn’t, by itself, prove that a rule failed. The app may not have made a new request, it may have switched to a backup hostname, or the connection may not have followed the expected rule path. Keep copies of the configuration from before and after changes, and record the test time, action, target hostname, and final policy so you can reproduce the result.
- Confirm the active configuration and routing mode. In
Config, check which file is enabled, then verifyHome → Global Routing → Config. Saving a file without enabling it won’t affect current connections. - Trigger a new network request. After saving, disconnect and reconnect. If needed, close and reopen the target app. When refreshing a page, check that it actually makes a new request instead of reading from cache.
- Check the request log. In the client’s connection or request log, find the entry for your test time and check the visible hostname, destination address, matched rule, and final policy. Seeing REJECT alone isn’t enough; make sure it corresponds to the request you just tested.
- Check rule order and available information. See whether a broader allow rule matched first. If the log shows only an IP address, don’t assume DOMAIN-SUFFIX had a usable hostname to match against. Check whether the app resolves names through encrypted DNS or connects directly to an address.
- Test one rule at a time. Temporarily disable the rule you just added and repeat the same action. If functionality returns, that rule is related to the issue. Next, narrow the match scope instead of stacking on more rejection rules.
Check rule order alongside GEOIP, IP-CIDR, and FINAL. These aren’t content classifiers: GEOIP matches based on an address’s geographic assignment, IP-CIDR matches an address range, and FINAL handles connections that didn’t match earlier rules. If a broad rule matches first, later rules for the target domain won’t run.
6. Common Questions: False Blocks, Caching, and Configuration Updates
Login stopped working after I added a rule. Which rule should I remove first?
Temporarily disable the REJECT rule you just added and try logging in again to see whether functionality returns. Then check the request log from the login attempt, especially DOMAIN-SUFFIX rules covering a root domain. If you confirm that an authentication hostname must remain available, add an exact exception before the broader rule and use the same working policy as before. Don’t allow an entire platform without verifying that it’s necessary.
The log shows REJECT. Why is the content still visible on the page?
First, confirm that the log entry is for a request made by this page, not another background connection. Then reopen the page and look for a new connection. Cached images, downloaded content, and built-in app assets won’t disappear just because a connection was rejected. Rules also don’t collapse empty spaces in a page layout.
The app requested content from a different hostname. Should I block every new hostname?
Don’t add rules in bulk just because hostnames appeared in the log. Compare each hostname with the action that triggered it and determine whether it’s related to the target feature. Test one hostname at a time. Backup endpoints may also serve legitimate content; keep unverified login, payment, and sync requests available for now.
Why did my custom REJECT rule disappear after updating a subscription?
First, distinguish a subscription update for a connection entry in Home from a configuration file update in Config; they’re not the same thing. Check whether the active file changed and whether a remote configuration update overwrote your manual edits. Keep a local test copy and a list of custom rules. After each update, compare the file contents and rule order; don’t assume the rules were preserved just because the connection entry is still there.
Whether blocking is suitable comes down to three things: whether the request follows the current rule path, whether the client has enough information to match it, and whether the target can be separated from essential functionality. If all three conditions are met, use a precise rule and keep a fallback copy. If they aren’t, accept the limits of domain-level handling rather than masking the problem with a broader rule.