Routing¶
The application supports configuring traffic routing through routing profiles. The application ships with preinstalled geo files so it works right after installation. Updates happen when the profile is updated or manually.
Adding profiles¶
Routing profiles can be added via:
- Clipboard
- Deeplink links
- QR codes
- HTTP headers (
routing) - Subscription body
Link types¶
| Link format | Description |
|---|---|
incy://routing/add/{base64} |
Adds the profile; activates after geo files are downloaded successfully |
incy://routing/onadd/{base64} |
Adds and immediately activates the profile |
incy://routing/off |
Fully disables built-in routing (no payload) |
{base64}is the JSON profile encoded in base64.
incy://routing/offdisables built-in routing entirely — equivalent to turning off the routing-profiles toggle in settings: the config is generated with no routing rules. The selected profile is kept (reversible: the provider can re-enable it viaonadd).Backward compatibility: the
://routing/add/and://routing/onadd/links are also supported.
Error handling¶
The geo file download manager runs in the background:
- Downloads exceeding 3 minutes are aborted
- Error messages are shown on the main screen
- Problematic profiles are marked with a red exclamation mark in the list
- Problems disappear after files download successfully or the profile is removed
HTTP header¶
The profile is passed in the routing header in base64 format. Two formats are supported:
Format 1 — base64 directly:
Format 2 — full link (any scheme):
Format 3 — disable routing:
The value off (or the ://routing/off link) disables built-in routing entirely — the provider turns routing off straight from the subscription response, with no user action:
Subscription body¶
The routing string is placed in the subscription body alongside server configurations:
vless://uuid@server1:443?security=tls#Server1
vmess://eyJhZGQiOiAic2VydmVyMi...
incy://routing/onadd/ewogICJOYW1lIjogIlJvc2NvbVZQTiIs...
Updating existing profiles¶
- Profiles with the same
Namefield are updated, not duplicated - The
LastUpdatedfield with a Unix timestamp controls freshness — an update happens when the value is greater than that of the stored profile
Profile structure¶
Profile example¶
{
"Name": "RoscomVPN",
"GlobalProxy": "true",
"RemoteDNSType": "DoH",
"RemoteDNSDomain": "https://cloudflare-dns.com/dns-query",
"RemoteDNSIP": "1.1.1.1",
"DomesticDNSType": "DoH",
"DomesticDNSDomain": "https://dns.google/dns-query",
"DomesticDNSIP": "8.8.8.8",
"Geoipurl": "https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat",
"Geositeurl": "https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat",
"DnsHosts": {
"cloudflare-dns.com": "1.1.1.1",
"dns.google": "8.8.8.8"
},
"DirectSites": ["geosite:ru"],
"DirectIp": ["geoip:ru", "10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16", "169.254.0.0/16", "224.0.0.0/4", "255.255.255.255"],
"ProxySites": [],
"ProxyIp": [],
"BlockSites": ["geosite:category-ads-all"],
"BlockIp": [],
"DomainStrategy": "IPIfNonMatch",
"FakeDNS": "false"
}
Field descriptions¶
General settings¶
| Field | Type | Default | Description |
|---|---|---|---|
Name |
string | "Default" |
Profile name |
GlobalProxy |
string | "true" |
"true" — all traffic goes through the proxy; "false" — direct connection. Defines the behavior when there is no match in the routing rules |
LastUpdated |
string | Unix timestamp. Controls forced geo file updates on first save or when updating the profile with a newer timestamp |
DNS settings¶
The system splits DNS queries into remote (Remote, via proxy) and local (Domestic, direct connection).
Remote DNS (for proxied resources):
| Field | Type | Default | Description |
|---|---|---|---|
RemoteDNSType |
string | "DoH" |
Protocol: DoH, DoU |
RemoteDNSDomain |
string | "https://cloudflare-dns.com/dns-query" |
DNS server address (required for DoH) |
RemoteDNSIP |
string | "1.1.1.1" |
DNS server IP |
RemoteDns |
string | Alternative field for RemoteDNSIP (backward compatibility) |
Local DNS (for direct resources):
| Field | Type | Default | Description |
|---|---|---|---|
DomesticDNSType |
string | "DoU" |
Protocol: DoH, DoU |
DomesticDNSDomain |
string | "" |
DNS server address (empty by default — DomesticDNSIP over UDP is used) |
DomesticDNSIP |
string | "8.8.8.8" |
DNS server IP |
DomesticDns |
string | Alternative field for DomesticDNSIP (backward compatibility) |
Additional DNS settings:
| Field | Type | Description |
|---|---|---|
DnsHosts |
object | Manual DNS records (analogous to a hosts file). Format: {"domain": "ip"} |
FakeDNS |
string | "true" — substitutes virtual IPs instead of real ones so that Xray handles all queries according to the configuration |
VPN DNS → Internal versus FakeDNS¶
These are separate settings. In the Apple client's HEV mode, Internal
(198.18.0.2) uses mapdns: applications receive a virtual IPv4 from
240.0.0.0/4, and HEV restores its domain before handing the connection to
Xray. This can happen even with profile FakeDNS=false. These addresses
must stay inside the VPN; they are not the provider server's addresses.
Profile FakeDNS controls Xray's mechanism. RemoteDNS and DomesticDNS
select profile resolvers; they do not switch HEV mapdns on or off. Full
subscription JSON may supply its own DNS configuration.
The October 2026 fixes restore Android mapdns and capture its virtual range when LAN bypass is enabled. Desktop Internal gains an equivalent using Xray FakeDNS while retaining Xray TUN, upstream resolvers and explicit provider pools. DNS selection rules may still return real addresses for specific domains. Stored profiles are unchanged. Availability depends on the installed build.
For real IPs, select a public VPN DNS preset and disable profile FakeDNS. Generated configurations still intercept DNS in Xray, retaining the profile's Remote/Domestic DNS and routing. For full JSON, also check its own DNS and interception rules. Reconnect and restart the affected browser to exclude stale DNS cache. A virtual IP alone does not establish the cause of a JavaScript or WebSocket failure; include DNS results and logs if the problem persists.
Routing rules¶
Traffic is distributed across three categories:
| Field | Type | Description |
|---|---|---|
DirectSites |
string[] | Domains/categories for direct access (no proxy) |
DirectIp |
string[] | IP addresses and subnets for direct access |
ProxySites |
string[] | Domains/categories routed through the proxy |
ProxyIp |
string[] | IP addresses and subnets through the proxy |
BlockSites |
string[] | Blocked domains/categories (ads, trackers) |
BlockIp |
string[] | Blocked IP addresses and subnets |
Rules support geo categories (geosite:ru, geoip:ru), specific domains, and IP/CIDR subnets.
Geo files¶
| Field | Type | Description |
|---|---|---|
Geoipurl |
string | URL to download geoip.dat |
Geositeurl |
string | URL to download geosite.dat |
Routing strategy¶
The DomainStrategy field defines the rule evaluation order (default AsIs):
| Value | Description |
|---|---|
AsIs |
Domains are passed as is, without DNS resolution (default) |
IPIfNonMatch |
Domain check first; if there is no match — DNS resolution and IP rule check |
IPOnDemand |
Always resolves domains to IPs before checking the rules |
Geo files: optimized downloading¶
Geo files (geoip.dat, geosite.dat) are downloaded from the URLs specified in the profile. A hash check is used to save traffic.
Algorithm¶
{filename}.sha256(a few bytes) is downloaded from the same URL- If the hash matches the stored one and the file exists locally → the download is skipped (even on a manual update)
- Without
.sha256, an ordinary profile import can useLastUpdatedto skip unchanged data. Manual and scheduled geo refresh bypass this timestamp check. - Required files are downloaded into a staging directory. The client computes SHA-256 and verifies it against the sidecar when available. An incomplete HTTP transfer or checksum mismatch fails the update.
- Only after all required downloads succeed are the live files replaced. Network failures keep the old pair; failure to install the second file triggers rollback of the first.
- Hashes and the successful-check timestamp are saved after installation. See failure handling and retries.
Recommendation for providers¶
Place a geoip.dat.sha256 and geosite.dat.sha256 file next to the geo files. The file must contain only the hex string of the SHA-256 hash (64 characters). This lets clients skip downloading unchanged files and save traffic.
Example contents of geoip.dat.sha256:
Trimming geo files (chunk files)¶
Full geoip/geosite files weigh tens of megabytes. If a profile uses only a limited subset of geoip:/geosite: tags, the client can trim the downloaded files down to the entries actually needed.
Profile field¶
| Field | Type | Description |
|---|---|---|
useChunkFiles |
boolean | If true — the client calls the internal CutGeoData() after downloading and keeps only the tags referenced in the rules |
- By default
falseon all platforms — backward compatibility with old profiles. - Android / iOS implement trimming via the built-in Go module
incycore.CutGeoData()(protobuf parsing of geoip/geosite and discarding unneeded entries). - Desktop (Linux / Windows) still uses full files —
useChunkFilesis ignored; the xray process works with the untrimmed.dat. - After trimming, the hash is recomputed locally and saved in the profile — a re-download will not start until the source
.sha256on the server changes.
When to use¶
Enable it if:
- Few geo tags are used in
proxy/direct/block(for example, onlygeoip:ru,geoip:cn,geosite:google). - Users complain about memory when loading heavy lists.
Do not enable it if:
- The profile uses many tags — trimming gives no benefit.
- There are custom geosite files with a non-standard layout — the client may not recognize the structure.
Per-profile geo file auto-update¶
Any provider can send routing-geo-update-interval: 24 as an HTTP response header, or #routing-geo-update-interval: 24 in the subscription text (including base64-encoded text). Premium is not required. Values are integer hours from 0 to 8760; zero or an absent value disables periodic checks when there is no local override. Invalid values are ignored. A valid HTTP header takes precedence over the body. profile-update-interval continues to control subscription refresh only.
The setting is supported on iOS/tvOS (including Designed for iPad on macOS), Android/TV and Desktop. It applies to the routing profile delivered with the subscription; it does not provide geo download URLs by itself. Those URLs come from Geoipurl and Geositeurl in the profile.
Interval selection¶
The header always uses hours, even when the editor displays days:
| Editor interval | Header value |
|---|---|
| 3 days | 72 |
| 7 days | 168 |
| 15 days | 360 |
| 30 days | 720 |
| 90 days | 2160 |
Every profile editor offers disabled, 1/6/12/24 hours or 3/7/15/30/90 days, or the provider default. The local choice survives subscription updates and application restarts. A missing provider default means disabled. Initial downloads, manual refresh and changed-profile handling remain independent of this schedule.
Failed downloads and retries¶
Scheduled checks refresh files at their existing URLs even when the profile's LastUpdated is unchanged. Matching .sha256 sidecars avoid unnecessary downloads. Successful checks are recorded even when the contents are unchanged.
GeoIP and GeoSite are first downloaded into a staging directory. HTTP completeness, non-empty content and the published .sha256 checksum are checked before replacing either live file. A network interruption or checksum mismatch keeps both previous files and does not advance the successful-check timestamp. If installing the second file fails, the first is rolled back.
Automatic failures back off for at least 30 minutes, then 1, 2, 4 and at most 6 hours while the app is running. Success resets the delay. Backoff is per session: restarting the app allows a fresh attempt. Manual refresh remains available immediately. On iOS, each file download also has up to three attempts with short delays.
A failed attempt does not restart the configured 3/7/15/30/90-day interval: it uses the shorter retry delay. Automatic retries require geo auto-update to be enabled. If it is disabled, use manual refresh. Until a successful update, existing geo rules continue to use the downloaded files. On a first download there is no previous copy to restore.
Checks run while the application is running and after launch. Background suspension or sleep can delay them. A new geo directory takes effect on the next connection; refresh does not forcibly disconnect VPN.
Profiles from different providers¶
Imported profiles are shown as Profile [GoVPN], using the provider's profile-title or the subscription name as fallback. They are bound by local subscription ID, so identical names in different subscriptions remain isolated. Renaming the provider updates the existing profile label. Legacy unbound profiles are retained to protect manually configured rules.