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

Learn how V2Ray subscription formats work, decode Base64 subscriptions into share links, map links to native JSON, and troubleshoot import errors. Compare v2rayN, v2rayNG, and V2Fly clients.

At a glance

A subscription URL retrieves content, Base64 encodes text, a share link describes one node, and native JSON defines a core configuration. This guide is for anyone seeing an empty subscription, an unimportable JSON file, or a need to move nodes. Identify the response format, decode it locally if needed, then check the protocol, transport, and TLS fields. Conversion changes only how data is represented; it cannot restore missing server parameters or guarantee feature parity across cores.

1. Subscription URLs, share links, and native JSON

“V2Ray subscription” isn’t a single file format. When a client requests an HTTPS URL, the response might be Base64 text, a list of share links, JSON, or even a login page. Check the response body to identify the format; don’t rely on whether the URL ends in .txt or .json.

Subscription URL recognized by the client

Recommended

Use v2rayN, v2rayNG, or v2flyNG to fetch a node list. This works only if the provider’s response format is compatible with your client. Subscription updates can preserve group organization, so you don’t need to copy nodes by hand each time.

Best for: regular updates and managing subscription groups across devices

One share link per line

Each line describes one node, usually starting with vmess:// or vless://. Useful for troubleshooting a single node; a bulk import is usually a one-time snapshot and won’t retain the original subscription’s update link.

Best for: offline transfers and checking an individual node’s fields

Native core JSON

May include inbounds, outbounds, DNS, and routing rules. It isn’t a universal node list; you’ll usually need the client’s custom configuration option and a structure compatible with the selected core.

Best for: preserving specific DNS, routing, and multiple-outbound settings

Keep the client and core distinct: v2rayN is a desktop client; v2rayNG uses the Xray core, while v2flyNG uses the V2Fly core. Importing a link only means the client recognized its text format; it doesn’t mean the current core supports every feature it declares. For REALITY or specific flow-control settings, check core compatibility instead of repeatedly encoding or decoding Base64.

2. Identify the subscription response before decoding

When inspecting a response with a trusted local tool, trim leading whitespace and check how the content begins. Subscription tokens can grant access to an account, so don’t send the full URL, response body, or QR code to an online converter. If the browser shows a CAPTCHA, login form, or error page, resolve the access issue first.

What you seePossible formatWhat to do next
vmess:// or vless://Plain-text list of share linksImport one link per line; don’t decode the whole response
A long string of letters, digits, and a few symbolsPossibly a Base64-encoded listDecode it locally once, then check for protocol prefixes
{ or [Possibly JSONInspect its structure: distinguish an API response, a node object, and a full configuration
<!DOCTYPE html> or <htmlWeb page or access-block responseCheck the URL, login status, and subscription expiry

HTTP status code 200 only means the request received a successful response; it doesn’t guarantee the body contains nodes. Even valid JSON may contain only an error code and message. Identifying the content before choosing an import option is more useful than repeatedly switching proxies or changing ports.

3. Decode a Base64 subscription into share links

A common way to create a traditional subscription is to join multiple share links with line breaks, then Base64-encode the resulting UTF-8 text. Decoding reverses that process. Note the difference between standard Base64 characters + and / and the URL-safe variants - and _; the trailing = padding may also be omitted.

3 → 4
Every 3 bytes become 4 Base64 characters; padding is added when needed
443
Remote TLS port used in this example
10808
Common local proxy port examples; use the port your client actually listens on

The native JavaScript function below is for local inspection. It processes only the input string and makes no network requests. Run it in an offline HTML page you create yourself; don’t paste a real subscription into the console of an untrusted website. UTF-8 decoding matters, or node names containing non-ASCII characters may become garbled.

function base64ToText(source) {
  const normalized = source
    .replace(/\s+/g, "")
    .replace(/-/g, "+")
    .replace(/_/g, "/");

  if (!/^[A-Za-z0-9+/]*={0,2}$/.test(normalized)) {
    throw new Error("Invalid Base64 characters");
  }

  const body = normalized.replace(/=+$/, "");
  if (body.length % 4 === 1) {
    throw new Error("Invalid Base64 length; check that the input was copied in full");
  }

  const padded = body + "=".repeat((4 - body.length % 4) % 4);
  const bytes = Uint8Array.from(atob(padded), ch => ch.charCodeAt(0));
  return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
}

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

// Local check; the result should be true.
console.log(base64ToText(textToBase64("Subscription format test")) === "Subscription format test");
  1. Pass the subscription response body to base64ToText, not the HTTPS subscription URL.
  2. Split the decoded result at line breaks and remove blank lines and leading or trailing whitespace. Preserve every character within each link.
  3. Check the protocol prefix on each line. Test-import one node before processing the rest in bulk.
  4. To regenerate a traditional Base64 list, encode the newline-separated links with textToBase64(links.join("\n")). This won’t create a subscription URL that others can access.

After decoding the outer list, the content after vmess:// may still be Base64. That’s part of the individual node’s encoding, not a failed decode. Don’t keep decoding the entire result mechanically; handle each protocol separately.

4. How VMess and VLESS share links map to JSON fields

A common VMess share link consists of vmess:// followed by a Base64-encoded node JSON object. Common keys include add, port, id, net, host, path, and tls. This is a sharing format, not a complete configuration for the core; v indicates the share format version, not the core version.

VLESS share links usually put the user ID, address, and port in the URI body, with transport parameters in the query string. The example below uses a reserved example domain and a demonstration UUID to show how fields map; it won’t connect to a real node.

vless://[email protected]:443?encryption=none&security=tls&type=tcp&sni=edge.example.com#TLS-demo
Share link fieldCommon native config locationWhat to check
Address and portsettings.vnext[].address / portThe remote port isn’t the local listening port
User UUIDsettings.vnext[].users[].idPreserve it in full; don’t use the remarks as the user ID
type=tcpstreamSettings.networkUse a transport name supported by the current core
security=tlsstreamSettings.securityCheck separately against protocol authentication and transport type
snitlsSettings.serverNameMatch the server’s certificate and configuration requirements
WebSocket host / pathwsSettings.headers.Host / pathDon’t use SNI as a substitute for Host

The VLESS example above maps to the Xray outbound snippet below. It doesn’t include inbounds, DNS, or routing, so it isn’t a complete runnable configuration. When adding it to a full config, place it in the appropriate outbounds array and verify the fields against the documentation for your core version.

{
  "tag": "proxy",
  "protocol": "vless",
  "settings": {
    "vnext": [
      {
        "address": "node.example.com",
        "port": 443,
        "users": [
          {
            "id": "00000000-0000-4000-8000-000000000001",
            "encryption": "none"
          }
        ]
      }
    ]
  },
  "streamSettings": {
    "network": "tcp",
    "security": "tls",
    "tlsSettings": {
      "serverName": "edge.example.com",
      "allowInsecure": false
    }
  }
}

5. Why native JSON can’t always be converted back to a subscription without losing data

A single share link mainly describes one remote connection. Full native JSON may also include multiple outbounds, routing rules, DNS servers, traffic sniffing, and local listeners. Even if you can extract a VLESS link from one outbound, that link can’t restore the entire routing policy. So before converting JSON to a subscription, clarify whether you’re extracting nodes or preserving the whole runtime configuration.

Choose a conversion approach: move nodes or migrate the full configuration

Move nodes only
  • Find the actual proxy outbound in outbounds, not a direct or blocked outbound.
  • Extract the protocol, address, port, authentication, transport, and TLS parameters.
  • Create share links recognized by the target client and test-import them one at a time.
  • Configure DNS, system proxy, and routing rules separately in the target client.
Keep the full configuration
  • Back up the original JSON and note the core and its exact version.
  • Check file paths, listening addresses, and port conflicts.
  • Use the client’s custom configuration option; don’t import it as a regular subscription.
  • After startup, check the logs and confirm DNS and routing behave as expected.

In short: share links are convenient for exchanging nodes; native JSON preserves configuration structure. Re-encoding the outer data can’t make up for information missing between the two formats.

Likewise, Xray and V2Fly JSON configurations aren’t interchangeable just by changing the filename. Protocol extensions, transport fields, and DNS options can differ. Removing unsupported fields may make a config parse, but it can also change how the connection works. Check the server requirements before migrating.

6. Choose the right import option in v2rayN and Android clients

Menu labels change between versions. The steps below describe common menu options and what they do; if your client uses different names, look for the equivalent of subscription groups, clipboard import, or custom configuration. Don’t paste a subscription URL into a field that accepts only a single share link, or a full JSON config into a server address field.

  1. Add a long-term subscription in v2rayN: Go to “Subscription Group” → “Subscription Group Settings,” add a group, and enter the subscription URL. After saving, choose “Update subscription (without proxy)” or the equivalent update option from the subscription menu. Choose “Update subscription (through proxy)” only if your network requires a proxy.
  2. Import one-time links in v2rayN: Copy the complete list of share links, one per line. From the “Servers” menu, choose “Import batch URLs from clipboard.” Check the transport type, TLS, and SNI after import, then select the server to use.
  3. Update a subscription in v2rayNG: Open “Subscription Group Settings,” create a group, enter the URL, and save. Return to the list and choose “Update subscription.” To import nodes from the clipboard, use “Import from clipboard” in the add menu; don’t mix up the two options.
  4. Check compatibility in v2flyNG: Before using its subscription or share-link import option, confirm that the node configuration works with the V2Fly core. If a node requires an Xray-specific feature, ask the provider for a compatible configuration; encoding conversion won’t solve the issue.

7. Common subscription conversion and import problems

After decoding, I still see vmess:// followed by a long string. Is it not fully decoded?

The outer subscription list has been decoded. Split it at line breaks to get individual nodes, then decode and parse the payload after vmess:// for a specific node. Don’t send the entire list through a Base64 decoder again, and don’t treat a VMess share object as a core configuration.

The JSON opens, so why does the client show zero nodes?

Check the top-level keys first. If they include inbounds and outbounds, it may be a full core configuration that requires the custom configuration option. If it contains an error code and message, fix subscription access first. Valid JSON syntax doesn’t mean the subscription format is supported.

Import failed after copying. What should I check first?

Check whether a chat app truncated the link, whether & in the query string was replaced by the literal HTML entity, or whether full-width colons or quotation marks were introduced. Test one complete link first; once the node details look right, import the rest.

The node imported but won’t connect. Should I try a different subscription format?

Check the address, actual server port (for example, 443), UUID, transport path, SNI, and core compatibility, then review the connection logs. A local listening port such as 10808 must not be entered as the remote port. If the fields imported correctly, re-encoding usually won’t fix a connection problem.

Can I send my subscription to an online tool to convert it to JSON?

Use local tools and the client’s export feature whenever possible. Treat subscription URLs and node authentication details as sensitive. If they’ve been exposed, reset the subscription token in your provider’s account settings and replace node credentials as required, then update the saved URLs on all your devices.

The final check boils down to four steps: inspect the response body, identify the format, verify the node fields, and confirm the core runs. For TLS, outbound, and routing terminology, see the glossary. If import succeeds but you still can’t connect, use the troubleshooting guide to check logs and network settings.

Download V2Ray Clients