Shadowrocket Custom Rules: Match Order and the FINAL Fallback

Shadowrocket rules are checked from top to bottom, stopping at the first match. Learn what PROXY, DIRECT, and REJECT do, and why FINAL belongs last.

In this article

This guide is for users who already have a provider and a working connection and are ready to edit a Shadowrocket config. First, make sure Global Routing is set to Config. Then arrange rules with specific exceptions first, broader matches later, and FINAL last. A minimal config, conflict example, and verification steps help distinguish a rule that didn’t match from a connection that failed after matching.

1. Check Config: When Rules Control Routing

Custom rules don’t turn a connection on or provide the server details it needs. Before you begin, get a subscription or connection details from your provider and confirm that the selected connection works. This guide uses the Home, Config, and Settings screen names on iPhone and iPad. On other platforms, check the equivalent routing and config settings.

Check Global Routing on Home. When it’s set to Config, the rules in the active config are the main place to investigate routing. Proxy and Direct are global routing modes; don’t confuse them with the PROXY and DIRECT actions at the end of individual rules. Scene settings depend on the active scene, so Scene isn’t another name for Config.

Request enters the tunnel Destination details are read Rules are checked from top to bottom The matching rule’s action is applied Connection is allowed or rejected

This flow describes requests routed by the config; it doesn’t mean every system request follows exactly the same path. To verify a rule, start with a specific destination domain and a new connection. A VPN indicator in the status bar alone doesn’t prove that the rule is working.

2. Rule Syntax: Read Match Conditions and Actions Separately

A typical rule has three parts: type, match value, and action, separated by English commas. The type specifies what to check, the match value defines the scope, and the action determines what happens on a match. FINAL has no match value, so it usually takes just two fields. Don’t use Chinese commas or append explanatory text to an action name.

3 fields
Typical conditional rule: type, match value, action
2 fields
Fallback rule: FINAL, action
3 actions
This guide covers PROXY, DIRECT, and REJECT
Rule typeExampleWhat it checks
DOMAINDOMAIN,login.example.com,PROXYMatches login.example.com exactly; subdomains aren’t included automatically.
DOMAIN-SUFFIXDOMAIN-SUFFIX,example.com,DIRECTMatches example.com and its subdomains, such as www.example.com.
IP-CIDRIP-CIDR,192.168.50.0/24,DIRECTChecks whether the destination IPv4 address falls within the specified network; /24 is not a port number.
GEOIPGEOIP,CN,DIRECTClassifies the destination IP using its region in the local GeoIP database.
FINALFINAL,PROXYHandles requests that didn’t match any preceding rules.

For domain rules, the match value doesn’t include https://, a path, query parameters, or a port. For example, if the URL is https://login.example.com:443/account, the DOMAIN value is still login.example.com. IP-CIDR uses an address and prefix length, not a URL. GEOIP checks an IP classification, not the webpage language, domain suffix, or service operator’s location.

3. What PROXY, DIRECT, and REJECT Do

The action appears at the end of a rule. A match selects an action, but doesn’t guarantee that the destination is reachable: PROXY still depends on the selected connection and remote network, DIRECT depends on the local network, and REJECT intentionally blocks the connection. The two config examples below illustrate individual rules; they aren’t complete configs to import together.

Set domain-based exceptions

DOMAIN
login.example.com,PROXY
DOMAIN-SUFFIX
ads.example.com,REJECT
DOMAIN-SUFFIX
example.com,DIRECT

Put exact matches and blocked subdomains before rules covering the entire domain, so broader conditions don’t take precedence.

Set address-based scope

IP-CIDR
192.168.50.0/24,DIRECT
GEOIP
CN,DIRECT
FINAL
PROXY

Keep this rule only if the address range really needs a direct connection; FINAL handles the rest.

If a domain handles both login and other content, a broad REJECT rule may block login too. Identify the destination that needs handling and narrow the match scope. Don’t assume a rule is correct just because part of a page disappeared, or blame every failure on the proxy connection.

4. Match Order: More Specific Rules Don’t Automatically Take Priority

Rules are checked from the first line down. The first match determines the action for that request, and later rules aren’t considered. DOMAIN is more specific than DOMAIN-SUFFIX, but specificity doesn’t override line order. Likewise, REJECT has no special priority over a DIRECT rule that appears earlier.

[Rule]
DOMAIN-SUFFIX,example.com,DIRECT
DOMAIN,login.example.com,PROXY
FINAL,PROXY

With this order, a request to login.example.com matches the first line because it’s a subdomain of example.com. The second line is more specific, but it never gets a chance to run. To route the login domain through PROXY and other subdomains through DIRECT, swap the first two lines:

[Rule]
DOMAIN,login.example.com,PROXY
DOMAIN-SUFFIX,example.com,DIRECT
FINAL,PROXY

Takeaway: Put exceptions before the broader rules that cover them

When adding a rule, first check whether a rule above it already covers the same destination. If it does, change the order or narrow the earlier rule instead of repeatedly adding the same one.

Putting specific rules first is a practical way to organize them, but the actual rule is that the first match wins. For example, if a particular IP must use PROXY, place its rule before a GEOIP rule that could route it directly. Don’t assume domain rules always outrank address rules or that one action is inherently stronger than another.

5. Why FINAL Must Be Last

FINAL doesn’t check a specific domain or address; it catches requests that didn’t match earlier rules. If placed in the middle of the list, it effectively ends rule evaluation there. Even valid DOMAIN, IP-CIDR, or GEOIP rules below it can’t handle requests already caught by FINAL.

[Rule]
DOMAIN,login.example.com,PROXY
DOMAIN-SUFFIX,ads.example.com,REJECT
DOMAIN-SUFFIX,example.com,DIRECT
IP-CIDR,192.168.50.0/24,DIRECT
GEOIP,CN,DIRECT
FINAL,PROXY

This minimal example illustrates rule order; it isn’t a default for every network. example.com and its subdomains are for demonstration only. Replace the local network range with one you actually need to reach. If your config already contains [Rule], organize rules within that existing section instead of pasting in another section with the same name.

  1. login.example.com matches PROXY on the first line and isn’t checked against the domain suffix rule below.
  2. ads.example.com matches REJECT on the second line; its subdomains are covered by that suffix too.
  3. www.example.com matches DIRECT on the third line, provided the request includes a destination domain that can be matched.
  4. The destination address 192.168.50.10 is in the example /24 network and is handled by the fourth line if no earlier rule matches.
  5. Other requests are checked against GEOIP; if none matches, they use the PROXY action specified by FINAL.

Choose the action for FINAL deliberately. FINAL,PROXY sends unmatched requests through the proxy; FINAL,DIRECT connects them directly. Neither is universally right regardless of network needs. Keep one clearly defined FINAL rule and make it the last active rule.

IP-based rules may involve domain resolution, and their results can depend on the destination IP, DNS response, and GeoIP data. A connection made directly to an IP address may not have a domain available for DOMAIN matching. So accessing a domain and connecting directly to its IP aren’t equivalent tests.

6. Save and Verify: Check That Rules Are Active Before Troubleshooting Failures

Before editing, save a copy of the current working config. During testing, change just one destination or one rule position at a time, and keep notes on the results before and after. Avoid changing DNS, routing mode, and the rule list together; otherwise, it’s hard to tell which change made a difference.

  1. Make sure you’re editing the active file: Open Config, check which config is in use, and open its editor. Keep remote configs distinct from local copies.
  2. Check the rule section: Edit within [Rule], keep the English commas, check action names for typos, and move FINAL to the end.
  3. Save and apply: Save your changes and confirm the config is still the one in use. Go back to Home and check that Global Routing is set to Config.
  4. Start a new connection: Reconnect after saving, then reopen the test page or app. Don’t use the behavior of an existing long-lived connection to judge a new rule.
  5. Check the logs: Find the test destination in the request or connection logs and review the matching rule, action, and destination details if available. First confirm whether the expected rule matched, then investigate connection errors.
  6. Narrow down the issue: If a PROXY match still times out, check the selected connection and your provider’s status. If a REJECT match fails, that’s the expected result of the action.

Updating a subscription and updating a config file are different things. A connection subscription usually refreshes connection details provided by your provider; it doesn’t necessarily rewrite the current [Rule] section. Updating a remote config may replace the file’s contents. Put custom rules you need to keep in a config you can maintain, and check them again after updates.

Don’t use a single successful page load as proof that routing is correct. A page may connect to its main domain, image domains, and API domains, each matching a different rule. Check the relevant requests individually. Don’t share subscription links containing credentials or your complete config while troubleshooting.

7. Common Reasons Rules Don’t Work

Why can I still open a destination after adding REJECT?

First, check whether a DIRECT, PROXY, or FINAL rule above it already covers the destination. Then confirm Global Routing is set to Config and that you edited the active file. Reconnect and check the actual request domain; an API domain used by the page may differ from the one in the address bar.

Can I add rules after FINAL?

Text can appear after FINAL in the file, but FINAL has already caught requests that didn’t match earlier rules. Later ordinary rules won’t get a chance to handle those requests. Move any rules you need above FINAL and remove redundant FINAL rules to avoid confusion when maintaining the config.

Why isn’t routing by domain working with On Demand enabled?

Settings → On Demand controls automatic connection conditions; it doesn’t change the Global Routing mode. Go to Home and check that Config is selected, then go to Config and verify which file is in use. Don’t use the automatic connection toggle as a substitute for routing settings.

Why do the rules I just added look unchanged after a successful subscription update?

First, determine whether you updated a connection subscription or a remote config. A successful subscription update doesn’t prove that rules were updated; a remote config update may overwrite local changes. Open the active config and inspect the actual [Rule] section, then test with a new connection to a specific destination.

Why did the same domain use DIRECT yesterday but match a different rule today?

Compare the match logs, actual destination IP, and active config. A change in DNS response can affect IP-CIDR or GEOIP matching, and a remote config update may change rule order. For consistent domain-based routing, put the relevant DOMAIN or DOMAIN-SUFFIX rule before related address rules.

Get Shadowrocket and continue setup

The iPhone and iPad app is a one-time $2.99 purchase on the App Store. The Mac (Apple silicon and Intel), Windows, Android, and Linux versions are free. For iPhone and iPad system requirements, see the App Store listing. Visit the download page to choose your platform, then follow the guide to add your existing config and subscription.

Buying the app is separate from paying for a connection plan. Get the subscription needed for a connection from your provider. This site covers getting the app and configuring it; it doesn’t provide, sell, or recommend nodes or subscriptions.

Download Shadowrocket for all platforms