Shadowrocket Blog · How it works

Why Shadowrocket cannot
"proxy only one app."

Many people want desktop-style control: "this app uses the proxy, everything else goes direct." On iOS that is basically impossible. The limit is not Shadowrocket — it is how iOS networking is designed. This article explains the restriction and the workaround Shadowrocket uses.

On iOS, VPN traffic goes through Apple's framework

iOS does not let third-party apps take over the network stack the way desktop tools can. Any app that forwards traffic (including Shadowrocket) must use Apple's Network Extension framework. The component that forwards packets is NEPacketTunnelProvider. That is why the first launch asks you to allow a "VPN configuration" — it is required by the official framework, not something Shadowrocket invented.

Two modes, pick one — they cannot mix

Per Apple's docs, NEPacketTunnelProvider supports only two routing modes, and they are mutually exclusive:

ModeHow it worksLimits
Route by destination IP
destinationIP
Whether traffic enters the tunnel depends on the destination. Shadowrocket global proxy and rule-based routing both use this modeIn this mode the system never tells the app which app sent the request. You can only match by domain or IP, not by source app
Route by source app
sourceApplication
The system decides whether to send traffic to your tunnel based on the source appOnce an app is routed into this per-app VPN mode, your app must handle all of its traffic — you cannot proxy some and send the rest direct. This mode usually also requires MDM (mobile device management), so a normal sideloaded or App Store install cannot use it

In other words, Apple never offered "split by app, then split again inside that app." That is not a missing feature in proxy apps — the system API does not expose it. Apple staff have said the same on the developer forums: in per-app VPN mode, there is no way to handle only part of an app's traffic.

The workaround Shadowrocket actually uses

Because the system never tells the app "this request came from App X," Shadowrocket matches by destination domain / IP instead. Rules such as DOMAIN-SUFFIX, IP-CIDR, and GEOIP approximate per-app routing by targeting the domains or servers an app usually uses — they do not identify the source app.

That also explains a few things you will see in real use:

Does that mean rule-based routing is useless?

No. For most cases (“local sites DIRECT, geo-restricted sites PROXY”), matching by domain and IP is accurate enough because those destinations are usually distinct. What iOS will not do is split one app so that some of its flows go PROXY and the rest DIRECT.

Note: Technical details follow Apple developer documentation (Network Extension / Packet Tunnel Provider) and official forum replies. API behavior is defined by Apple's latest docs.

Once you know the limits, setup is faster Knowing where the limits are makes it easier to write rules and to decide when to use global proxy
Download →

Further reading: Rule syntax explained · Sites will not load