· Subscriptions · About 12 min read

V2Ray Subscription Formats Explained: Base64, Native JSON, and vless:// Links

Compare Base64 subscriptions, native JSON configs, and VMess/VLESS share links. Learn how to import and convert them in v2rayN and v2rayNG.

At a glance

First, distinguish the subscription URL, its response, and node share links. Then compare a VLESS + WebSocket + TLS example in URI and Xray JSON form. This guide is for anyone whose subscription opens but won’t import, whose decoded Base64 still isn’t a config, or who needs to migrate nodes. You’ll learn which import option to use and which routing, DNS, and local listener settings may be lost during conversion.

How subscription URLs, Base64, and JSON differ

A subscription is usually an HTTPS URL that a client fetches to retrieve node data. The URL itself is neither Base64 nor a node config; the key is the response body returned by the server. The same URL may return different content depending on request parameters or client identifiers, so its file extension alone won’t tell you the format.

Subscription URLResponse bodyFormat detectionNode parsingCore runtime
Content typeHow to identify itWhere to use it and limitations
Subscription URLStarts with https://; may include an access tokenAdd it in subscription settings to keep future updates enabled
Base64 subscription bodyOften decodes to share links, one per lineUsually parsed by the client’s subscription updater; not a complete runtime config
Single-node share linkStarts with vless:// or, commonly, vmess://Suitable for importing a node from the clipboard; usually doesn’t include local routing
Native core JSONContains fields such as inbounds and outboundsUse the custom config option for the matching core; supported fields depend on that core

Base64 is an encoding for bytes, not encryption. Anyone with the subscription body can usually recover server addresses and identity details. JSON is just a data format: text beginning with braces might describe a node, contain an API error, or be a complete core config. Check the fields inside; valid JSON is not necessarily ready to run.

Decode and re-encode a Base64 subscription

A common Base64 subscription combines multiple share links with newline characters, then encodes the resulting UTF-8 text. If decoding reveals multiple lines beginning with vless:// or vmess://, you’ve recovered the outer subscription; there’s no need to Base64-decode each VLESS link. Some services return a plain-text list of links, in which case skip the outer decoding step.

  1. First confirm you have the response body—not a browser login page, access restriction notice, or error message with a status code.
  2. For a suspected Base64 body, remove spaces and line breaks, support the URL-safe characters - and _, then restore any missing padding.
  3. Read the decoded bytes as UTF-8, check each line’s protocol prefix, and preserve the parameters within each link.
  4. Before re-encoding, confirm that the client actually needs a Base64 list. Encoding text locally creates a static string; it does not create an HTTPS subscription service that updates automatically.

The plain JavaScript function below can be run in your local browser’s developer tools. It uses byte arrays to handle Chinese remarks, avoiding errors from using btoa directly on non-ASCII text. It only converts the input text and makes no network requests; use content you trust.

function decodeSubscription(source) {
  const compact = source.trim().replace(/\s+/g, "")
    .replace(/-/g, "+").replace(/_/g, "/");
  if (!/^[A-Za-z0-9+/]*={0,2}$/.test(compact)) {
    throw new Error("Input is not a valid Base64 character sequence");
  }
  const padded = compact + "=".repeat((4 - compact.length % 4) % 4);
  const bytes = Uint8Array.from(atob(padded), ch => ch.charCodeAt(0));
  return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
}

function encodeSubscription(linkText) {
  const bytes = new TextEncoder().encode(linkText);
  let binary = "";
  for (const byte of bytes) binary += String.fromCharCode(byte);
  return btoa(binary);
}

const sampleText = "Sample node";
console.log(decodeSubscription(encodeSubscription(sampleText)));

If the decoder throws an error, don’t keep applying layers of conversion. Check whether the response is truncated or includes quotes or HTML tags, then confirm whether it’s already a plain-text list. Even after successful decoding, the client still needs to validate each link’s protocol, required fields, and transport settings.

Field structure of vless:// and vmess:// links

VLESS share links typically use a URI structure: the user-info section contains the UUID, the host and port identify the server, query parameters describe transport and security, and the text after the hash is the node remark. The example below uses a reserved example domain and a demonstration UUID for illustrating the fields only; it doesn’t represent a connectable service.

vless://[email protected]:443?encryption=none&security=tls&type=ws&host=example.net&path=%2Fws&sni=example.net#WS-TLS-demo
443
Server-side TLS port in this example
10808
Local SOCKS port used in the config below

path=%2Fws decodes to /ws. Encode paths, remarks, and special characters in query parameters using percent encoding. Don’t encode the entire URI at once or decode the full URI before parsing it manually, or characters such as & in a path could be mistaken for parameter separators. IPv6 addresses in the host position must also be enclosed in square brackets.

VLESS share link

Identity
UUID appears before @
Transport
type=ws
Security
security=tls
Path
path=%2Fws

This example uses WebSocket and TLS; don’t add Vision flow.

Common VMess share format

Outer layer
Base64 follows vmess://
Server
add and port in the JSON
Identity
id in the JSON
Transport
net and path in the JSON

This is a common client-side sharing convention, not JSON that can be passed directly to a core for runtime use.

In common VMess share JSON, v is the share format version, not the VMess protocol version; ps is usually the remark. Its structure differs from settings.vnext in a core outbound. VMess sharing conventions also have variants, so when migrating, use the import and export features in both clients where possible rather than assuming every vmess:// link has exactly the same internal structure.

Build native Xray JSON from a VLESS link

To turn a share link into a complete JSON config, you need to add local inbounds and outbound tags that the link doesn’t contain. The config below matches the earlier VLESS example and uses the Xray config structure; it listens locally only on 127.0.0.1:10808. Before using it, replace the example values with real server parameters you’re authorized to use. The example domain does not provide proxy service.

{
  "log": {
    "loglevel": "warning"
  },
  "inbounds": [
    {
      "tag": "socks-in",
      "listen": "127.0.0.1",
      "port": 10808,
      "protocol": "socks",
      "settings": {
        "auth": "noauth",
        "udp": true
      }
    }
  ],
  "outbounds": [
    {
      "tag": "proxy",
      "protocol": "vless",
      "settings": {
        "vnext": [
          {
            "address": "example.net",
            "port": 443,
            "users": [
              {
                "id": "9f2a54d1-8bc6-4d71-a903-0be458e623fd",
                "encryption": "none"
              }
            ]
          }
        ]
      },
      "streamSettings": {
        "network": "ws",
        "security": "tls",
        "tlsSettings": {
          "serverName": "example.net"
        },
        "wsSettings": {
          "path": "/ws",
          "headers": {
            "Host": "example.net"
          }
        }
      }
    }
  ]
}

Choose the right import option in v2rayN or v2rayNG

First decide whether you need to preserve the subscription or import a single node. Decoding a subscription and importing its links one by one may create nodes, but usually loses the subscription source and automatic updates. To keep receiving server list updates, save the original subscription URL instead of just the currently exported share links.

v2rayN: handle subscriptions, clipboard links, and custom configs separately

  1. Subscription URL: Go to “Subscription Group” → “Subscription Group Settings,” add a group, and enter a remark and URL. Save it, then use the update option under “Subscription Group.” After updating, check that the nodes were added; don’t enter the URL as if it were a single-node address.
  2. Share links: Copy the complete vless:// or vmess:// text, then choose “Server” → “Import bulk URLs from clipboard.” After importing, edit the node and check the address, port, TLS, SNI, and transport path.
  3. Complete JSON: Use a custom config option such as “Server” → “Add custom config server.” Choose the matching core, then select the config file as prompted. Don’t paste an entire JSON config into the subscription URL field.

v2rayNG: create a subscription group, then update it

  1. From the main screen menu, open “Subscription group settings.” Tap the add button, enter a subscription name and address, and save. Return to the main screen and select “Update subscription.”
  2. For a single share link, copy the complete text, then tap “+” on the main screen → “Import from clipboard.” Make sure the generated config type matches the source before connecting.
  3. For native Xray JSON, use the custom config import option in the “+” menu, choosing a file or clipboard import method as supported by your version. Don’t import common VMess share JSON as a complete custom config.

Menu labels may vary slightly between releases. Look for options corresponding to “subscription group,” “clipboard link,” and “custom config.” With v2flyNG, also check that the subscription’s protocols and transports are compatible. The fact that v2rayNG recognizes an Xray node doesn’t mean another core can run the same config.

Exporting JSON back to links and what conversion loses

“Convert between formats” doesn’t mean all three formats can always make a complete round trip. A single-node link mainly describes the remote connection, while a full JSON config may include multiple inbounds and outbounds, DNS, routing, policies, and logs. Exporting JSON as a single VLESS link means choosing one outbound and extracting its connection parameters; the remaining local behavior usually can’t be represented in the link.

ConversionUsually preservedRequires extra work
Link list ↔ Base64Original link text and orderCharacter encoding, line breaks, and URL-safe variants
VLESS link → JSONAddress, identity, common transport and security parametersAdd inbounds, outbound tags, and local routing
JSON outbound → share linkSingle-node fields supported by the target clientChoose an outbound, handle extension fields, and save DNS and routing rules separately
VMess → VLESSShared address and transport details can only serve as a referenceThe server must actually provide VLESS; changing the prefix won’t switch protocols

When migrating, select a node in the source client and use its share-link export feature, then check the fields in the target client. If you only have JSON with multiple outbounds, identify the target by checking tag and protocol in outbounds; don’t mistake a direct or block outbound for a server. For extension parameters, keep a backup of the original JSON and inspect the config generated by the target client.

Subscription decoding and import FAQs

Why does the subscription open in a browser but fail to update in the client?

First check whether the response is actually a node list, rather than a login page or API error JSON. Then make sure the complete URL includes its token and query parameters. If the address isn’t accessible from your current network, you can update through a proxy if you already have a working node. Don’t rely on a node you haven’t imported yet as the only network route for updating the subscription.

Why does Base64 decode successfully but show no servers to import?

Check the protocol prefix on every line of the decoded result. Successful Base64 decoding only proves that the encoding was reversible; it doesn’t mean the content is supported by the client. If the result is JSON, determine whether it’s a share-field object or a complete config. If it’s HTML, troubleshoot the subscription request instead of encoding it again.

What if a share link imports but the connection still times out?

Open the node editor and compare the port, transport path, TLS, and SNI with the source. In this example, the remote port is 443; 10808 is only the local SOCKS listening port, and the two aren’t interchangeable. Then check the core logs to distinguish DNS resolution issues, connection timeouts, and TLS handshake errors. “Import successful” only means the parser accepted the fields.

Why did my mainland China direct-routing rules disappear after conversion?

Node share links usually don’t include the complete local routing setup. Restore routing separately in the target client. If you use a custom JSON config, check that routing.rules and the outbound tags match. If you need domainStrategy, place it at the routing level, not inside an individual rule.

For final verification, change one layer at a time: first confirm the content format, then check that all fields are present, and finally test the network and core. This separates subscription retrieval failures, link parsing failures, and node connection failures, avoiding repeated guesswork across encoding tools and proxy settings.

Download clientsv2rayN / v2rayNG