v2RAGE for providers
How to give your users a subscription in v2RAGE with one tap, and which links and configurations the app accepts. This page describes v2RAGE 2.4.1 for iPhone, iPad and Mac from the App Store. Items marked Next update are already done and ship in the next version of the app.
Add-subscription link
The link opens v2RAGE and offers to add your subscription:
v2rage://import?url=<subscription URL, percent-encoded>
urlis the full subscription address,https://orhttp://, percent-encoded as a whole (encodeURIComponentin JavaScript). An unencoded&from your own query splits the address, and the app receives only its beginning.- The app shows the address and asks “Add this subscription?” Nothing is downloaded until the user taps Add.
- On success the user sees “Subscription added — N servers”. If the response holds no server the app can read, the user sees “No servers found in subscription”, and nothing is added.
- The list of subscriptions is stored on the device and synced through the user's iCloud when it is available.
- Opening the link for an address that is already added replaces the earlier copy instead of adding a second one. Letter case of the scheme and host, a
#fragmentand a trailing slash do not make the address different. - Only subscription addresses are accepted. A single server key (
vless://…,hy2://…) cannot be passed inurl: put it into a subscription, or let the user paste it on the import screen.
Example
Subscription address:
https://panel.example.com/sub/abc?format=v2ray
Link:
v2rage://import?url=https%3A%2F%2Fpanel.example.com%2Fsub%2Fabc%3Fformat%3Dv2ray
Button on your page:
<a href="v2rage://import?url=https%3A%2F%2Fpanel.example.com%2Fsub%2Fabc%3Fformat%3Dv2ray">Add to v2RAGE</a>
Where to put the link
- Behind a button on an
https://page: your dashboard or a landing page. A tap in Safari opens the app. - Messenger in-app browsers often do not open custom schemes, and a QR code with a
v2rage://link may not open from the camera. In messages and QR codes, point to your https page with the button rather than to thev2rage://link itself. - Next to the button, show the plain subscription address with a copy button. The user can always paste it in the app: Settings → Import Subscription.
- If v2RAGE is not installed, the link does nothing. Add the App Store link: apps.apple.com/app/v2rage/id6761075402.
Manual import
Settings → Import Subscription accepts:
- a subscription address (
https://…); - a single server link, see Supported configurations;
- an AmneziaWG configuration: an
awg://link or the text of a.conffile; - any of the above from a QR code, with the Scan QR button.
Subscription URL
Request
The app downloads the subscription with a GET request and these headers:
| Header | Value |
|---|---|
User-Agent | v2RAGE/<version> (build <build>; iOS <system version>) |
x-hwid | Device ID for the panel: 64 hex characters. The same on every request from the device, also after the app is reinstalled; different on each device. |
x-device-os | System name as the device reports it, for example iOS or iPadOS. |
x-ver-os | System version, for example 18.5. |
x-device-model | Model identifier, for example iPhone16,1. |
x-app-version | App version, for example 2.4.1. |
The x-* headers follow the convention of Happ, Remnawave and 3x-ui 3.7+: a panel counts devices by x-hwid. If your panel counts devices, refuse requests without a valid x-hwid with the x-hwid-not-supported header, see Device limit.
Response
- Status
200, body in UTF-8. Any other status is shown to the user as an error. - Body: one server link per line, or the same list encoded in standard Base64 as one line, without spaces or line breaks, with or without
=padding. One subscription can mix protocols. - Lines the app cannot read are skipped, the rest are added.
- Not supported as a subscription body: Clash / Mihomo YAML, sing-box JSON, Xray JSON. If your panel chooses the format by
User-Agent, return the plain link list forv2RAGE/…. - A Base64 body is recognised only when it holds at least one
vless://,vmess://,hysteria2:///hy2://,hysteria://,tuic://,socks://orsocks5://link. Serve a subscription made only ofawg://,wireguard://,socks4://,socks4a://orsocks5h://links as plain text. Next updateawg://is recognised in Base64 too.
Response headers
| Header | What the app does |
|---|---|
profile-title | Subscription name in the app settings. Plain text, or base64: followed by Base64 of UTF-8 text. Without it the subscription is called “Subscription”. |
subscription-userinfo | upload=…; download=…; total=…; expire=…: traffic in bytes, expire in Unix time, seconds. The app shows the expiry date next to the subscription. |
Send these header names in lowercase, as written above. A complete response:
HTTP/1.1 200 OK
content-type: text/plain; charset=utf-8
profile-title: base64:TXkgVlBO
subscription-userinfo: upload=0; download=1073741824; total=107374182400; expire=1798761600
vless://11111111-2222-3333-4444-555555555555@nl1.example.com:443?type=tcp&security=reality&flow=xtls-rprx-vision&pbk=<public key>&sid=<short id>&sni=www.example.org&fp=chrome#NL%20Amsterdam
profile-update-interval is read but not used for scheduling. On iPhone, iPad and Mac the subscription is downloaded again when the user refreshes the server list or the subscriptions in settings. On Apple TV it is also refreshed when the server screen opens, at most once every 15 minutes.
Device limit
A panel that counts devices can refuse with these response headers. The status code does not matter: Remnawave, for example, answers 404.
| Header | The user sees |
|---|---|
x-hwid-max-devices-reached: true | “This subscription has reached its device limit. Remove an unused device in your provider's panel or ask them to raise the limit.” |
x-hwid-not-supported: true | “The subscription panel did not accept this device's ID. Ask your subscription provider to allow it.” |
Subscriptions a user adds are synced through their iCloud to their other Apple devices with v2RAGE. Each device downloads the subscription with its own x-hwid and counts as a separate device.
Supported configurations
Server links, inside a subscription or pasted one by one. Everything after # is the server name. Start the name with a flag emoji or a two-letter country code (🇳🇱 Amsterdam, NL Amsterdam) to set the server's country.
| Protocol | Link | Parameters |
|---|---|---|
| VLESS | vless://uuid@host:port?…#name |
REALITY: security=reality, pbk, sid, sni, fp (default chrome); flow=xtls-rprx-vision. Transport type: tcp (default), xhttp or splithttp (host, path, mode), grpc (serviceName). security=none without encryption. |
| VMess | vmess:// + Base64 of v2rayN JSON |
TCP transport, with or without TLS (tls, sni, fp). The old form vmess://method:uuid@host is not supported. |
| Hysteria 2 | hysteria2://auth@host:port/?…#name, also hy2:// |
sni (or peer), obfs=salamander with obfs-password, insecure=1, pinSHA256, up and down in Mbit/s. Other obfs types are not supported. One port only: port hopping (443,5000-6000) is rejected. |
| Hysteria | hysteria://host:port/?…#name |
auth, peer or sni, obfs, upmbps, downmbps, alpn, insecure. UDP only: protocol=faketcp and wechat-video are not supported. |
| TUIC | tuic://uuid:password@host:port/?…#name |
sni, congestion_control (bbr, cubic, new_reno), udp_relay_mode (native, quic), zero_rtt_handshake, alpn, allow_insecure or insecure. |
| SOCKS | socks5://[user:pass@]host:port#name, also socks://, socks5h://, socks4://, socks4a:// |
Default port 1080. No TLS. |
| AmneziaWG | awg:// + Base64 of the .conf file, also wireguard://; #name |
In a subscription, as awg:// lines. The text of a .conf file ([Interface] and [Peer] sections) can be pasted or scanned on the import screen. Amnezia's vpn:// profile format is not supported. |
Link rules
- Set
sniexplicitly for TLS keys: Hysteria 2, Hysteria, TUIC, VMess with TLS. - VLESS: write
host:port?…, without/between the port and?. Do not repeat parameters. Writesni,hostand the other values without percent-encoding; onlypathmay be encoded.
Not supported
- NaiveProxy (
naive+https://). - HTTP and HTTPS proxies.
- Clash / Mihomo YAML, sing-box JSON and Xray JSON.
- Shadowsocks and Trojan in version 2.4.1: such keys are rejected when pasted and skipped in a subscription. See below.
Next update
Already done and shipping in the next version of v2RAGE. Until it is released, these keys do not work in the App Store version.
| Protocol | What is added |
|---|---|
| Shadowsocks | ss:// in SIP002 form (Base64url user info, or plain text, which 2022 ciphers require) and the legacy all-Base64 form. Keys with plugin=, and 2022-cipher keys of the wrong length, are rejected. |
| Trojan | trojan:// with TLS or REALITY; transports tcp, ws, grpc, xhttp. Not supported: security other than tls or reality, disabling certificate verification, an unknown fp. alpn only http/1.1 with ws and h2 with grpc. |
| VLESS | TLS without REALITY (security=tls with sni); WebSocket transport (type=ws, host, path). |
| VMess | WebSocket and gRPC transports. |
For Shadowsocks and Trojan, a parameter repeated in one link makes the key rejected.
