V2Ray Subscription Formats: Base64, Native JSON, and Share Links

Compare Base64 subscriptions, native JSON configs, and vmess:// and vless:// share links. Learn how their formats differ, which clients support them, and how to convert between them.

At a glance

A subscription URL handles updates, Base64 wraps text, a share link describes a single node, and native JSON configures the core. If you can fetch a subscription but can’t import it, or routing rules disappear after converting JSON to a link, start by identifying the input format. Then check the protocol, transport, and security fields before importing and testing in your client. Encoding changes the wrapper, not the configuration.

1. Subscription URLs, response content, and node formats

“V2Ray subscription” isn’t a file standard implemented consistently by every client. In practice, a subscription is usually an HTTPS URL that a client requests to retrieve nodes and save in a subscription group. The URL may contain an access token, but import compatibility depends on the response content and the formats the client can parse.

Input typeTypical structureWhat it containsWhere to use it
Subscription URLHTTPS URLLocation of the content and access credentialsSubscription group settings
Base64 subscriptionA single block of encoded textUsually share links, one per lineSubscription updates or an importer that supports the format
Share linkvmess://、vless://Connection parameters for one nodeImport from clipboard or QR code
Native JSONObjects such as inbounds and outboundsInbound and outbound settings, with optional DNS and routingCustom config option or the corresponding core

Some subscriptions return a plain-text list of links; others serve different formats depending on request parameters or client identifiers. A .json extension or a string of gibberish in the browser doesn’t tell you whether a client can import it. Check the actual response, not just the URL. Re-encoding a login page, expiry notice, or error JSON won’t produce valid nodes.

2. Base64 subscriptions and VMess: two layers of encoding

A typical Base64 subscription is created by joining multiple share links with line breaks, encoding the UTF-8 text as Base64, and returning it as the response body. The client first decodes the outer layer, then parses each node line by line. Don’t prepend vmess:// to a block of Base64 text—that makes the whole list look like a single VMess node.

  1. Retrieve the response body and rule out an HTML page, an access error, or empty content.
  2. If the body already contains protocol-prefixed links, one per line, treat it as a plain-text link list.
  3. If the body is Base64, decode the outer layer and check that the result contains recognizable share links.
  4. Parse the nodes line by line. For vmess:// links, decode the inner payload according to the format.

A widely used VMess share format consists of vmess:// followed by a Base64-encoded JSON object. This JSON contains share-link fields; it is not a complete V2Fly or Xray config. The example below shows the decoded object inside a VMess link. The value 2 for v marks the share format version, not the core version.

{
  "v": "2",
  "ps": "Sample node",
  "add": "example.com",
  "port": "443",
  "id": "0f3a10d2-7f3b-4b58-a3f6-9a6fcbec8431",
  "aid": "0",
  "scy": "auto",
  "net": "ws",
  "type": "none",
  "host": "example.com",
  "path": "/ws",
  "tls": "tls",
  "sni": "example.com"
}

The example domain, UUID, and path are for illustrating the structure only and won’t connect to a server. aid: "0" is commonly used with modern VMess AEAD; don’t change it to 64 based on outdated tutorials. scy controls VMess content encryption, while tls controls transport security. They are separate settings. Generators may also differ in how they handle numbers, strings, and extension fields.

3. VLESS link query parameters and transport fields

Common VLESS share links use a URI structure: the UUID goes in the user-info section, the host and port in the address, and transport, security, and path settings in query parameters. The remark follows #. The example below is a VLESS + WebSocket + TLS link; %2Fws decodes to /ws.

vless://[email protected]:443?encryption=none&security=tls&type=ws&host=example.com&path=%2Fws&sni=example.com#VLESS-WS-TLS

VMess share-link field

Server
add = example.com
Remote port
port = 443
Transport and path
net = ws、path = /ws
Content encryption
scy = auto
Transport security
tls = tls、sni = example.com

These abbreviated fields must be mapped to the core config; they can’t be used as-is as an outbound object.

VLESS query parameter

Server
example.com:443
Transport
type=ws
Request path
path=%2Fws
Protocol encryption field
encryption=none
Transport security
security=tls、sni=example.com

VLESS itself doesn’t provide content encryption; in this example, TLS secures the transport.

Special characters in URI parameters must be escaped correctly. For example, if a path contains &, encode it as %26; otherwise, it will be treated as a separator for the next parameter. Enclose IPv6 hosts in square brackets. Percent-encode non-ASCII remarks for better compatibility across clients. Changing the remark usually won’t affect the connection, but changing the path, SNI, or Host will affect the handshake.

4. Why native JSON can’t be used as a subscription

A native config tells the core how to run. It can include multiple inbounds and outbounds, as well as DNS, routing, and logging settings. The VMess config below illustrates the structure: a local SOCKS inbound listens on 127.0.0.1:10808, and a remote outbound connects to example.com:443. Port 10808 is an example local port, not a subscription URL port or a value used by every client.

{
  "log": {
    "loglevel": "warning"
  },
  "inbounds": [
    {
      "tag": "local-socks",
      "listen": "127.0.0.1",
      "port": 10808,
      "protocol": "socks",
      "settings": {
        "auth": "noauth",
        "udp": true
      }
    }
  ],
  "outbounds": [
    {
      "tag": "proxy",
      "protocol": "vmess",
      "settings": {
        "vnext": [
          {
            "address": "example.com",
            "port": 443,
            "users": [
              {
                "id": "0f3a10d2-7f3b-4b58-a3f6-9a6fcbec8431",
                "alterId": 0,
                "security": "auto"
              }
            ]
          }
        ]
      },
      "streamSettings": {
        "network": "ws",
        "security": "tls",
        "tlsSettings": {
          "serverName": "example.com"
        },
        "wsSettings": {
          "path": "/ws",
          "headers": {
            "Host": "example.com"
          }
        }
      }
    }
  ]
}

Here, settings.vnext holds the VMess server parameters, while streamSettings holds transport and security settings. VLESS uses a different protocol settings structure; changing protocol from vmess to vless isn’t enough. Xray and V2Fly configs share some syntax, but their extensions and fields evolve differently. Valid JSON doesn’t guarantee that the target core can run it.

Conversion limits: migrating a node vs. a complete config

Migrate nodes only
  • Extract the server, port, and UUID from the proxy outbound.
  • Preserve the WebSocket path, Host, and TLS SNI.
  • Generate a share link supported by the target client.
  • Set DNS, routing, and local listening ports in the target client.
Migrate the complete config
  • Preserve outbound tags and their routing references.
  • Check DNS, inbound listeners, and logging settings.
  • Check every field supported by the target core.
  • Use the custom config option and verify the runtime logs.

Standard node share links don’t carry full DNS and routing rules. Converting a complete config to links and importing it back is usually a lossy round trip.

5. Import support in v2rayN, v2rayNG, and v2flyNG

The client parses subscriptions and manages nodes; the core handles the actual connection. v2rayN is a desktop client that can use supported cores depending on its configuration. v2rayNG is an Android client that uses the Xray core, while v2flyNG is an Android client that uses the V2Fly core. The fact that all three can parse VMess links doesn’t mean they support every VLESS, REALITY, or full JSON config in the same way.

ClientCommon inputsHandling native configsWhat to check
v2rayNSubscription URLs and supported node share linksUse the custom config option with a compatible coreWhether both the importer and selected core support the node fields
v2rayNGSubscription URLs, clipboard links, and QR-code nodesUse the custom config feature available in your versionXray version and whether transport and security parameters are complete
v2flyNGSubscription URLs and supported node share linksUse the current version’s option for V2Fly configsDon’t pass an Xray-specific config directly to V2Fly

The steps below use common menus in the Chinese interface of v2rayN 7.x; labels may vary between minor versions. First identify whether you have a subscription URL or node text, then choose the matching import option. This works better than repeatedly trying the same button.

  1. Identify the input

    Use a subscription group for an HTTPS subscription URL. Import text starting with vmess:// or vless:// as a node link. Treat JSON containing inbounds and outbounds as a complete config.

  2. Add a subscription

    Go to “Subscription Group” → “Subscription Group Settings,” add a group, and enter a name and subscription URL. After saving, update it from “Subscription Group.” Choose to update through a proxy or directly, depending on network access.

  3. Import a single node

    Copy the full link and import it from “Servers” → “Import bulk URL from clipboard.” Put each link on its own line. In v2rayNG, use “+” → “Import from clipboard” on the main screen.

  4. Check the fields

    Open the node editor and check the server, remote port 443, UUID, transport, path, Host, and SNI. For REALITY nodes, also verify the public key, short ID, fingerprint, and Flow—not just the node name.

  5. Test the connection

    Select the node, run a test, and check the logs. If they report an unsupported protocol or field, check the core. For address, certificate, or handshake errors, check the node config. Then enable the required system proxy or TUN mode.

6. Conversion options: keep updates or export a snapshot

Converting share links to a Base64 subscription means joining the text and encoding it; converting a Base64 subscription back means decoding and splitting it into lines. This changes only the wrapper: it won’t turn VMess into VLESS or fill in missing server parameters. If the subscription provider changes the nodes, a locally exported file won’t update.

Keep the original subscription URL

Recommended

If the target client supports the subscription format, add it as a subscription group. You’ll keep receiving the provider’s maintained node list instead of copying a new file for every update. The lists may temporarily differ if the clients update at different times.

Best for: everyday use and sharing a node source between desktop and Android

Export a snapshot of share links

To move a small number of nodes, use the client’s share or export feature, then import them on the target device. Check each transport and security field after export; unfamiliar extension parameters may be lost if you export again.

Best for: moving a single node or troubleshooting how a specific link is parsed

Migrate native JSON

If you need to preserve routing, DNS, or multiple outbounds, check whether the target core supports the complete config instead of converting it to share links first. Also make sure its local ports don’t conflict with listeners already used by the client.

Best for: existing complete configs and control over core behavior

Local encoding example: handle UTF-8 bytes first

These native JavaScript functions encode and decode text locally to illustrate how standard Base64 works. They don’t make network requests, parse nodes, or generate native configs. Use a link list you’ve already confirmed is valid; don’t paste production subscription data into an unfamiliar website’s console.

function encodeList(text) {
  const bytes = new TextEncoder().encode(text);
  const binary = Array.from(bytes, byte =>
    String.fromCharCode(byte)
  ).join("");
  return btoa(binary);
}

function decodeList(encoded) {
  let normalized = encoded.trim()
    .replace(/\s+/g, "")
    .replace(/-/g, "+")
    .replace(/_/g, "/");
  normalized += "=".repeat((4 - normalized.length % 4) % 4);
  const binary = atob(normalized);
  const bytes = Uint8Array.from(binary, char =>
    char.charCodeAt(0)
  );
  return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
}

7. Common questions about format conversion and subscription imports

The subscription opens, but why does the client show zero nodes?

First, check the start of the response locally. If it’s HTML, an expiry notice, or an error object, resolve the subscription access issue. If it’s Base64, decode it and check for protocol links on separate lines. If it returns complete JSON, use a compatible custom config option or ask the provider for a format supported by your client.

Why can’t I import JSON even after encoding it?

Base64 doesn’t change the internal structure. A config object containing outbounds is still a config object after encoding; it doesn’t become a list of links. Extract the proxy outbound, map its server, user, transport, and security fields, then export a share link using a compatible tool or client.

The import succeeded, so why does the connection still fail?

A successful import only means the parser accepted the text. Open the node editor and check the remote port, UUID, WebSocket path, and SNI. Then check the logs for certificate, handshake, or unsupported-field errors. Don’t enter the local SOCKS port 10808 as the remote server port.

Where did my routing rules go after switching devices?

Standard node links usually contain only node parameters. Recreate the rules in the target client’s routing settings, or migrate a complete, compatible custom config. Check that outbound tags match their routing references; migrating only the server address and UUID won’t restore all your routing rules.

I shared my subscription URL. Will changing the remark help?

Changing a node remark won’t revoke access. Reset the subscription token or URL in the provider’s management portal, then replace the old URL in the client’s subscription group and update it. If node credentials were exposed too, the server administrator will need to rotate those credentials as well.

Check the three layers in order: verify the response content, confirm the client can parse it, then confirm the core can connect. Recording the client version, selected core, node transport, and error logs makes troubleshooting more effective than repeatedly encoding with Base64. For setup basics, read the Quick Start Guide. For protocol and security fields, see Protocol Reference.

Download v2rayN