App Management¶
Parameters for controlling app behavior via subscription HTTP headers and lines in the response body.
Delivery Methods¶
All parameters can be delivered in two ways:
1. HTTP header:
2. Line in the subscription body (a # comment):
#profile-title: Мой VPN
#support-url: https://t.me/support
#profile-update-interval: 6
#announce: Текст объявления
vless://...
Priority: HTTP headers take precedence. Body lines are used as a fallback when the corresponding header is absent. This is especially useful when serving subscriptions via static files (nginx), where custom HTTP headers cannot be set.
Standard Parameters¶
Subscription Name¶
The subscription profile name. Maximum 25 characters. Can be passed as text or base64 (UTF-8).
Header:
In the subscription body:
Base64 with a description (the first line is the name, the rest is the description):
Alternative headers (fallback when profile-title is absent):
- subscription-name — alternative subscription name
- content-disposition — file name from the header (extensions .txt, .yaml, .yml are stripped automatically)
Subscription Description¶
A separate header for the description if it is not included in profile-title:
Supports base64: profile-description: base64:...
Subscription Update Interval¶
The automatic subscription update interval in hours. The value must be a multiple of one hour.
Header:
In the subscription body:
Subscription Status¶
Information about the balance, the amount of traffic used, and the subscription expiration date. Fields are separated by semicolons.
| Field | Description |
|---|---|
upload |
Outgoing traffic (bytes) |
download |
Incoming traffic (bytes) |
total |
Traffic limit (bytes) |
expire |
Expiration date (Unix timestamp, seconds) |
If
expire> 32,000,000,000, the value is interpreted as milliseconds and converted to seconds.
Support Link¶
A button to open the support page. If the link points to Telegram, the Telegram icon is shown.
Header:
In the subscription body:
Website Link¶
A button to open the subscription website.
Header:
In the subscription body:
Alternative header: homepage
Announcement¶
A text announcement (up to 200 characters). Can be passed as text or base64.
Header:
Base64:
Announcement URL (a link, not text):
In the subscription body:
#announce: Плановое обслуживание 15 марта
#announce-url: https://example.com/news
vless://uuid@server:443#Server
Parameter Summary Table¶
| Header | Alternatives | Format | Body (#) |
Description |
|---|---|---|---|---|
profile-title |
subscription-name, content-disposition |
text / base64:... |
✅ | Subscription name |
profile-description |
— | text / base64:... |
— | Subscription description |
profile-update-interval |
— | number (hours) | ✅ | Update interval |
subscription-userinfo |
— | key=value;... |
— | Traffic statistics |
sort-order |
— | none / ping / name |
— | Server sort order (per-subscription on iOS/Android; global on Desktop) |
support-url |
— | URL | ✅ | Support link |
support-email |
— | ✅ | Support email — shows an "Email" button in the subscription card (fallback contact). Without this header the button is hidden | |
profile-web-page-url |
homepage |
URL | ✅ | Website link |
announce |
— | text / base64:... |
✅ | Announcement text |
announce-url |
— | URL | ✅ | Announcement link |
autorouting |
— | URL | ✅ | Auto-updated routing profile |
routing |
— | base64 / link / off |
✅ | Routing profile; the value off disables built-in routing |
premium-url |
— | URL | — | "Premium" link (in the subscription card, see below) |
banner-text |
— | text / base64:... |
— | Banner text (overrides the panel, see below) |
banner-button-text |
— | text / base64:... |
— | Banner button text |
banner-button-url |
— | URL | — | Banner button link |
banner-bg-color |
— | hex (#RRGGBB) |
— | Banner background color |
banner-button-color |
— | hex (#RRGGBB) |
— | Banner button color |
hide-url |
— | 1 / 0 / true / false |
✅ | Hide the subscription URL from Share/Copy/QR/backup (see below) |
hide-check |
— | 1 / 0 / true / false |
✅¹ | Hide the Home "Check" button (see below) |
per-app-proxy-enable |
— | 1 / 0 |
— | Enable per-app mode (Android only) |
per-app-proxy-mode |
— | bypass / proxy |
— | Per-app mode |
per-app-proxy-list |
— | CSV / URL | — | List of package names |
fragmentation-enable |
— | 1 / 0 |
— | TCP fragmentation |
fragmentation-length |
— | min-max |
— | Fragment length range |
fragmentation-interval |
— | min-max |
— | Range of delay between fragments |
fragmentation-packets |
— | tlshello / 1-3 / all |
— | Which packets to apply to |
noises-enable |
— | 1 / 0 |
— | Send noise packets before the handshake |
noises-type |
— | rand / str / hex |
— | Noise content type |
noises-packet |
— | string | — | Noise payload (format depends on type) |
noises-delay |
— | min-max ms |
— | Range of delay between noise packets |
server-address-resolve-enable |
— | 1 / 0 |
— | Pre-resolve the server address via DoH |
server-address-resolve-dns-domain |
— | URL | — | DoH server URL |
server-address-resolve-dns-ip |
— | IP | — | DoH server IP (bootstrap) |
no-limit-enabled |
— | 1 / 0 |
— | (iOS) Enable the memory-tight Network Extension mode — keeps the background process under the iOS 50 MB cap so xhttp transports aren't killed by the system (the VPN doesn't drop). Enable-only (never overrides the user's manual choice) |
All headers are case-insensitive (
profile-title=Profile-Title).Body parameters are used as a fallback — HTTP headers always take precedence.
All headers with values support the
base64:prefix for passing UTF-8 data without Latin-1 / non-ASCII issues (applies toannounce,profile-title,profile-description,subscription-name,per-app-proxy-list,banner-text,banner-button-text).Android and Desktop additionally accept gzip chains in values (
base64:gzip:,gzip:base64:,gzip:) — handy for longper-app-proxy-list. iOS supportsbase64:only (no gzip).¹
hide-checkworks as an HTTP header and via the subscription body (#hide-check:), just likehide-url, but the#hide-check:body marker is read only by Android and iOS — Desktop applieshide-checkvia the header and Premium config only.⚠️ Cyrillic in the banner. HTTP headers cannot carry non-ASCII directly. To use non-Latin text in the banner or its button, base64-encode it:
banner-text: base64:<base64(UTF-8)>andbanner-button-text: base64:<base64(UTF-8)>.
Routing¶
Routing Profile¶
A static profile in base64. See routing.md for details.
The value off (or the ://routing/off link) fully disables built-in routing:
Auto-Updated Routing Profile¶
A URL source of the routing profile with periodic updates. See autorouting.md for details.
Routing Source Priority¶
If a routing profile is specified in several places, the first one found by priority is used:
| Priority | Source |
|---|---|
| 1 (highest) | autorouting header |
| 2 | Body — a line with a URL (://autorouting/onadd/, ://autorouting/add/) |
| 3 | routing header |
| 4 (lowest) | Body — a line with base64 (://routing/onadd/, ://routing/add/, ://routing/) |
Important: only
://autorouting/setssourceURLand enables auto-update.://routing/onadd/{url}lines in the subscription body import the profile once, without binding it to a source.
Server Description¶
An additional caption displayed under the server name (maximum 30 characters). It is appended after title using the ? separator:
Per-App Proxy (subscription control — Android only)¶
The Android VpnService allows routing only selected apps through the VPN, or conversely excluding them from the tunnel. The provider can force this mode from the subscription via three headers (Android only). Desktop has the feature too, but it is user-controlled — see the subsection below.
per-app-proxy-enable: 1
per-app-proxy-mode: bypass
per-app-proxy-list: com.android.chrome,org.telegram.messenger
Parameters¶
| Header | Value | Description |
|---|---|---|
per-app-proxy-enable |
1 / 0 |
Enable per-app mode |
per-app-proxy-mode |
bypass | proxy |
bypass — the listed apps bypass the VPN. proxy — only they go through the VPN |
per-app-proxy-list |
CSV or URL | List of package names separated by commas, newlines, or a URL to a text file |
List Format¶
Inline (CSV or line-based):
Base64 (for long lists):
Remote URL:
The file at the URL is plain text with package names, one per line or comma-separated. The client downloads it when applying the subscription and on every update.
Behavior¶
- If none of the three fields is set, the user's settings in the app are not overridden.
- If
per-app-proxy-enableis set to0, per-app mode is disabled even if the user enabled it locally. - These headers are read on Android only (the list uses package names).
Per-app on Desktop (Windows / macOS / Linux)¶
The desktop client also supports per-app split-tunnel, but not via these headers — it is a user setting in the app (the "Split-tunneling" screen). A provider cannot set it from the subscription; the user builds the list by executable names/paths, not package names.
Under the hood Desktop does not touch the system firewall — the rule is written straight into xray routing via the process field (socket-PID lookup, no sniffing). It works for both regular and full-config subscriptions. Windows, macOS and Linux are all supported (the xray core resolves the originating process: GetExtendedTcpTable on Windows, /proc on Linux, libproc on macOS).
TUN mode only
Per-app on Desktop works only when TUN mode is on (xray owns the TUN device itself and can see the originating process). In System Proxy / Proxy Only modes the process cannot be resolved and per-app is not applied.
TCP Fragmentation¶
Overrides the user's global fragmentation settings for this subscription.
fragmentation-enable: 1
fragmentation-packets: tlshello
fragmentation-length: 10-30
fragmentation-interval: 10-30
| Header | Value | Description |
|---|---|---|
fragmentation-enable |
1 / 0 |
Enable fragmentation |
fragmentation-packets |
tlshello | 1-3 | 1 | all |
Which TCP packets to apply fragmentation to |
fragmentation-length |
min-max |
Fragment length range in bytes |
fragmentation-interval |
min-max |
Range of delay between fragments in ms |
The same parameters are available through the Premium API as fragmentEnabled / fragmentPackets / fragmentLength / fragmentInterval — for a Premium subscription, HTTP headers are ignored in favor of API values.
Noise Packets (noises)¶
Sending random UDP packets before the VPN handshake for obfuscation. Primarily relevant for WireGuard and Hysteria2 on networks with deep packet inspection.
| Header | Value | Description |
|---|---|---|
noises-enable |
1 / 0 |
Enable noise |
noises-type |
rand | str | hex |
Payload format |
noises-packet |
string | Noise packet content; for rand — a length range min-max |
noises-delay |
min-max ms |
Range of delay between noise packets |
Resolving the Server Address via DoH¶
Bootstrap resolution of the server domain via DNS-over-HTTPS before the tunnel is established. Useful when the provider's DNS spoofs the VPN server address.
server-address-resolve-enable: 1
server-address-resolve-dns-domain: https://common.dot.dns.yandex.net/dns-query
server-address-resolve-dns-ip: 77.88.8.8
| Header | Value | Description |
|---|---|---|
server-address-resolve-enable |
1 / 0 |
Enable DoH resolution |
server-address-resolve-dns-domain |
URL | DoH endpoint (usually /dns-query) |
server-address-resolve-dns-ip |
IP | The DoH server IP for bootstrap — used before its domain is resolved |
The same fields are passed through the Premium API as serverAddressResolveEnable / serverAddressResolveDnsDomain / serverAddressResolveDnsIp.
"Premium" Link¶
An additional button in the subscription card — it leads to the provider's purchase page or account dashboard.
| Header | Value | Description |
|---|---|---|
premium-url |
URL | URL of the "Premium" button in the subscription card |
If not set, the button is hidden.
Provider Banner¶
The banner is a prominent strip in the subscription card on the home screen (text + an optional button). It is configured in the premium panel, but the text and button can be overridden via subscription headers — convenient for dynamic announcements without opening the panel.
Display Conditions¶
The banner is shown when the provider is premium (an active premium subscription) and at least one of:
- a
banner-textheader arrived in the subscription response (a dynamic banner — e.g. via Remnawave Response Rules, without opening the INCY premium panel); or - the banner is enabled in the premium panel (
bannerEnabled).
So the banner-text header alone turns the banner on (as long as the provider is premium) — you don't have to open the panel and set bannerEnabled. If banner-text is absent, the banner falls back to the old path (panel bannerEnabled + panel text).
Only premium providers may push a banner via headers: for non-premium subscriptions the
banner-*headers are ignored.
Priority: Header → Panel¶
Each field is resolved as header ?? panel: if the corresponding banner-* header came in the subscription response, it is used; otherwise the value from the panel is used.
banner-text: base64:0JDQutGG0LjRjyEg0KHQutC40LTQutCwIDUw0Js=
banner-button-text: Подробнее
banner-button-url: https://example.com/promo
banner-bg-color: #E53E3E
banner-button-color: #38A169
| Header | Format | Overrides (panel) |
|---|---|---|
banner-text |
text / base64:... |
bannerText |
banner-button-text |
text / base64:... |
bannerButtonText |
banner-button-url |
URL | bannerButtonUrl |
banner-bg-color |
hex #RRGGBB |
bannerBgColor |
banner-button-color |
hex #RRGGBB |
bannerButtonColor |
Both the text (
banner-text) and the button text (banner-button-text) supportbase64:— for Cyrillic/UTF-8 this is required (see the warning above).The button URL is resolved as
premium-url→banner-button-url→ panel: thepremium-urlheader has the highest priority (historically).If the banner text is empty after resolution, the banner is not shown.
Supported on iOS, Android, and Desktop.
Hiding the Subscription URL from the User¶
The hide-url parameter prevents the subscription URL from "leaking" off the device: when enabled, the app does not show or allow exporting the URL via Share, Copy URL, QR code, or backups. The subscription name, servers, and all the rest of the UX work as usual — only the URL itself is hidden.
Header:
In the subscription body:
Premium API (JSON):
Accepted Values¶
| What is sent | Behavior |
|---|---|
1, true, yes (case-insensitive) |
URL is hidden |
0, false, no, empty string |
URL is visible (default) |
| Any other value in the header | Ignored, URL is visible |
Source Priority¶
- The
hide-urlHTTP header has the highest priority - The
#hide-url:line in the subscription body is used as a fallback when the header is absent - The
hide_urlfield in the Premium API JSON is an independent source applied in parallel
If at least one source says "hide", the URL is hidden. To unhide it, disable it in all sources (or refresh the subscription with the updated value).
What Is Blocked¶
- The Share button in the subscription card
- The Copy URL button
- Displaying the subscription QR code
- Including the subscription in a backup (even a password-encrypted one)
- The export button in the subscription's server editor
What Is NOT Blocked¶
- Viewing and editing the server settings within the subscription (on devices with an admin HWID — see admin-hwids.md)
- Connecting to servers, ping, traffic stats, refreshing the subscription
- Backups of individual servers (if they were imported manually, outside this subscription)
Rules for Premium Providers¶
| Premium | Admin HWID | hide-url |
Sees URL | URL in backup |
|---|---|---|---|---|
| no | — | no | yes | yes |
| no | — | yes | no | no |
| yes | yes | no | yes | yes |
| yes | yes | yes | yes | no (admin sees it, but cannot export via backup) |
| yes | no | — | no | no |
Without hide-url, regular (non-premium) subscriptions are always exported and copied — hide-url is the only way to forbid this for non-premium.
Hiding the "Check" Button¶
The hide-check parameter removes the "Check" button (connectivity check while the VPN is active) from the Home screen. It behaves exactly like hide-url: tri-state (set to "hide" / set to "show" / absent → fallback). The button is shown by default.
Useful for providers whose server answers the check request in a non-standard way (or blocks it), so the button would mislead the user.
Header:
In the subscription body (Android and iOS only — Desktop ignores the body marker):
JSON subscription body:
Premium API (JSON):
Accepted Values¶
| Sent value | Behavior |
|---|---|
1, true, yes (case-insensitive) |
"Check" button hidden |
0, false, no, empty string |
Button shown (default) |
| Header absent | Falls back to body / Premium config, otherwise shown |
Source Priority¶
hide-checkHTTP header — highest priority#hide-check:marker in the subscription body — fallback (Android/iOS)settings.hideCheckin the Premium API — independent source
Platforms¶
Android, iOS and Desktop — all three hide the button. The only difference is the "subscription body" source: Desktop does not read the #hide-check: marker (use the header or Premium config).
Settings the Subscription Cannot Set via HTTP Headers¶
These parameters are stored in the provider's Premium API configuration and are applied by the client only if the subscription domain belongs to a Premium provider. They cannot be enabled "via a subscription without an account in the panel" — this is by design.
| Group | What is configured | Link |
|---|---|---|
| Lite Mode | Simplified interface, links to bot/channel/support + preset icons | premium-api.md § Lite Mode |
| Subscription banner | Text + colors + button in the subscription card | premium-api.md § Баннер подписки |
| Custom theme | Flat colors and gradients for the account / background | premium-api.md § Кастомная тема |
| Force settings | forceConnectionStyle: classic round button vs compact toggle |
premium-api.md § Принудительные настройки |
| Ping and sorting | defaultPingProtocol, defaultSortOrder, pingOnUpdate |
premium-api.md § Ping и сортировка |
| Domain fronting | resolveAddress / hostHeader (the SNI ↔ Host pairing for obfuscation) |
premium-api.md § Domain fronting и фрагментация |
| Admin access by HWID | adminHwids + push auto-approve |
admin-hwids.md |
| Push notifications | Moderation, targeting, cancellation | provider-notifications.md |
Fragmentation, noise, and DoH resolution are available through both channels: subscription HTTP headers (see above) or the Premium API. For a Premium subscription, API values take precedence over headers.