V2Ray Subscription Formats: Base64 Subscriptions, Native JSON Configs & vmess:// Links

Learn how Base64 subscriptions, native JSON configs, and vmess/vless links work—and how to import and convert them in v2rayN and v2rayNG.

At a glance

First, distinguish subscription URLs and responses from single-node share links and core configs, then choose the right import method. This guide is for anyone seeing “subscription content not recognized,” trying to import JSON as a node, or moving settings between devices. Learn to identify Base64 wrappers, compare VMess and VLESS fields, and see which connection settings survive conversion—and which DNS and routing settings must be migrated separately.

1. Identify the Format: A Subscription URL Is Not a Node Config

A V2Ray subscription is not a single, fixed core config file. A “subscription link” usually means an HTTPS URL that a client fetches and parses into a list of nodes. The response may contain share links on separate lines or a Base64-encoded list of links. Opening the URL only confirms that a response was returned; it does not mean the response is usable by your client.

ItemHow to identify itWhere to use itWhat it contains
Subscription URLA service URL beginning with https://Subscription group settingsRemote update source
Base64 subscription bodyUsually decodes to multiple share links, one per lineParsed by the subscription updaterParameters for multiple nodes
VMess share linkvmess:// followed by encoded dataImport from clipboardUsually one node
VLESS share linkvless:// followed by user info and query parametersImport from clipboardUsually one node
Core JSON configIncludes fields such as inbounds and outboundsCustom config optionConnection, inbound, DNS, routing, and other settings

For example, https://subscription.example.com/list?token=demo illustrates a URL format; it is not a working subscription. Don’t enter it as a VLESS server address, and don’t paste raw JSON into a subscription URL field. A token in a subscription URL is often tied to account access. When troubleshooting, redact the entire path and query string—not just the domain.

2. Decode Base64: Separate the Subscription Wrapper from the VMess Payload

A common Base64 subscription has two layers: the outer layer encodes the complete list of links, while each vmess:// link inside may contain a Base64-encoded JSON payload. Decoding the outer layer gives you node links, not a complete core runtime config. VLESS usually uses a URI directly, so you can’t decode it the same way as a VMess payload.

Subscription response body
  ↓ Base64-decode the entire body
vmess://an encoded node JSON payload
vless://user-id@server:port?parameters#remark
  ↓ Decode only the payload after vmess://
VMess node fields: add, port, id, net, tls, and more

Check the actual response text before deciding whether to decode it. If the body already starts with vmess:// or vless://, treat it as a list of links. If it starts with an HTML tag, a login prompt, or a JSON error, the issue is likely with the subscription request, authorization, or server response. Repeated decoding won’t fix it.

  • Line breaks: Put one complete link on each line. Don’t insert a line break in the middle of a link or join multiple links on a single line.
  • Characters: Base64URL uses - and _ in place of the standard Base64 characters + and /. Some output omits the trailing = padding.
  • Text: Decode Chinese remarks as UTF-8. Displaying the raw binary output as regular text may produce garbled characters.
  • Decoding passes: Stop once you have the list of links. Don’t keep decoding just because the text contains a mix of letters and numbers.

The native JavaScript function below can be used in your browser’s developer tools on a blank local page. It demonstrates text encoding and decoding only; it makes no network requests and does not read the clipboard. Test round trips with sample text only. When handling real subscriptions, also consider browser extensions and console logs.

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

function decodeUtf8Base64(text) {
  let value = text.trim().replace(/\s+/g, "")
    .replace(/-/g, "+").replace(/_/g, "/");
  if (value.length % 4 === 1) {
    throw new Error("Invalid Base64 length; check the copied content");
  }
  value += "=".repeat((4 - value.length % 4) % 4);
  const bytes = Uint8Array.from(atob(value), ch => ch.charCodeAt(0));
  return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
}

const sample = "Subscription format example";
console.log(decodeUtf8Base64(encodeUtf8Base64(sample)) === sample);

3. Check Node Fields: VMess JSON vs. VLESS URI

A common VMess share link stores an encoded node-description JSON after vmess://. This is a client-defined sharing format, not an Xray or V2Ray core JSON config. The v field below identifies the share format; v: "2" is not a client version or a requirement to install a particular core version.

{
  "v": "2",
  "ps": "VMess-WS-TLS example",
  "add": "node.example.com",
  "port": "443",
  "id": "11111111-2222-4333-8444-555555555555",
  "aid": "0",
  "scy": "auto",
  "net": "ws",
  "type": "none",
  "host": "edge.example.com",
  "path": "/ws",
  "tls": "tls",
  "sni": "edge.example.com"
}

Encode the complete JSON text above as Base64 using UTF-8, then prepend vmess:// to create this share-link format. The example domain and user ID are for illustration only and cannot be used to connect. For a real node, the address, UUID, transport, and TLS settings must match the server. Changing only the remark won’t make it usable.

VMess + WS + TLS

Server port
443
Transport field
net: ws
Request path
/ws
HTTP Host
edge.example.com
TLS SNI
edge.example.com

Host is part of the WebSocket request, while SNI is used in the TLS handshake. They happen to match in this example, but they are not interchangeable.

VLESS + TCP + TLS

Server port
443
Transport parameters
type=tcp
Protocol parameters
encryption=none
Transport security
security=tls
TLS SNI
node.example.com

VLESS protocol encryption and TLS operate at different layers; don’t remove TLS settings on that basis.

The corresponding VLESS example combines user info, an address, query parameters, and a fragment for the remark. Percent-encode spaces and Chinese remarks. Put IPv6 addresses in square brackets. Parameter order usually doesn’t affect meaning, but don’t arbitrarily change parameter names or values.

vless://[email protected]:443?encryption=none&security=tls&sni=node.example.com&type=tcp#VLESS-TLS

4. Import into v2rayN: Create a Subscription Group, Then Update Nodes

Add remote subscriptions to a subscription group. For one or more share links, use clipboard import instead. The menu paths below refer to the commonly used Chinese v2rayN interface. The desktop and WPF versions may place options in different locations, and updates may be available from a group’s right-click menu. Use the option with the matching name in your version; don’t switch to the custom config option just because a button moved.

  1. Create a group

    Go to “Subscription Groups” → “Subscription Group Settings” and add a record. Enter a remark, paste the full HTTPS subscription URL into the address field, and save.

  2. Update the subscription

    Go back to “Subscription Groups” and select “Update All Subscriptions (No Proxy).” If your network requires an already working proxy to access the subscription, choose the corresponding option to update through the proxy.

  3. Check the nodes

    Review the update results and confirm that nodes appear in the target group. Open a node’s edit window and check its protocol, server address, port, transport, and TLS settings. Don’t rely on the remark alone.

  4. Select a server

    Right-click a node and select “Set as Active Server.” Updating a subscription fetches config; it does not switch the current connection to a new node.

  5. Test the connection

    Run the connection test provided by the client, then use a browser to visit a site you need to check. If it fails, first inspect the logs for handshake, authentication, or DNS errors instead of repeatedly converting the format.

To import static share links, copy each complete link, including its prefix, then use “Server” → “Import bulk URLs from clipboard.” The common shortcut is Ctrl+V. Put each link on its own line. If you only have a Base64 body and no remote URL, decode it locally into a list of links first; this makes errors easier to pinpoint.

  • Updates can overwrite changes: Subscription nodes are maintained remotely, so manual edits may be replaced during a later update. Save any changes you need to keep as separate entries.
  • Don’t assume the local port: Example configs often use 127.0.0.1:10808, but check the listening port in your client’s settings. You can’t infer it from the subscription node’s 443 port.
  • Use the dedicated JSON option: To load a complete core config, use the custom config option under “Server.” Its editing and export capabilities may differ from those for regular node entries.

5. Import into v2rayNG: Keep the Update Source Separate from Static Links

v2rayNG is an Android client that uses the Xray core. In commonly used versions, remote subscriptions are managed from the top-right menu, while static links can be imported using the plus button on the main screen. Both methods add nodes to the list, but only the former retains the subscription source. Copying share links exported from desktop does not carry over the desktop update schedule or group associations.

  1. Add a source

    Open the top-right “⋮” → “Subscription Group Settings,” tap “+,” enter a remark and the complete subscription URL, then save and return to the main screen.

  2. Fetch nodes

    Open “⋮” → “Update Subscription.” If your version offers options to update the current group or all groups, choose the scope that includes the target subscription and check the update message.

  3. Import static links

    For a share link, copy the complete text, then tap “+” → “Import from clipboard” on the main screen. Don’t include login instructions from the subscription webpage.

  4. Connect and verify

    Select the target node, start the connection, and approve the system VPN permission prompt. Run a real connection test, then verify access in an actual app. A TCP latency result alone doesn’t mean proxy requests are working.

Move Between Both Clients: Share the Source, Verify Settings Separately

Desktop: v2rayN
  • Save the original HTTPS URL in a subscription group.
  • Make sure the current core supports the node’s protocol.
  • Set up the system proxy, DNS, and routing rules separately.
Android: v2rayNG
  • Add the same subscription URL instead of copying only the node remark.
  • After updating, check key parameters and confirm that the nodes work.
  • Check VPN permission and per-app proxy settings separately.

Using the same source makes maintenance easier, but the returned list may vary based on the account, request conditions, or server policy. Node lists and settings are not synced automatically between the two clients.

6. Convert Formats: Identify What Can Be Preserved

Share links and Base64-encoded link lists are usually just different text wrappers. Native JSON and share links are not interchangeable one-to-one: a full config may include multiple outbounds, direct and block rules, DNS, inbound listeners, and outbound selection logic. A single node link usually describes only the connection settings for one proxy outbound; it cannot replace a full config backup.

Keep the original subscription URL

Recommended

Add the same remote source to both clients. As long as the URL remains valid, each client can receive node updates maintained by the provider. Whether multiple devices are allowed depends on the provider’s account rules.

Best for: ongoing use across devices with automatic updates.

Export node share links

Use the node’s right-click menu or sharing option to export or copy its share URL. After importing it on the other client, check each parameter. The result is a static snapshot of the node; it does not include the subscription token or automatic updates.

Best for: temporarily moving a few nodes or checking an individual connection’s settings.

Keep the full core JSON config

Use the custom config option to migrate the file, then check core compatibility, local paths, listening addresses, and ports. Don’t assume a runtime config generated by a client is a portable backup that works across platforms.

Best for: configs with multiple outbounds, DNS, or complex routing.

Convert Between a Link List and a Base64 Subscription Body

  1. Collect complete share links supported by the target client, one per line. Remove quotes, numbering, and explanatory text copied from chat messages.
  2. Encode the entire text as Base64 using UTF-8 to create a common Base64 subscription body. To reverse the process, decode it once to restore the links, one per line.
  3. Before importing, check the protocol prefix on the first line, the total number of lines, and whether Chinese remarks display correctly. Successful encoding doesn’t mean every node can connect.
  4. To update through a URL, you also need a controlled HTTPS service that actually returns the subscription body. Generating Base64 text alone does not create a subscription URL.

Convert Between Native JSON and a Single-Node Link

To extract a node from JSON, locate the actual VMess or VLESS outbound under outbounds, then read the server, user authentication, and streamSettings according to the core’s config structure. Don’t assume the first outbound is the one you need: it may be a direct connection or a chain that depends on another outbound. Xray and V2Ray differ in their capabilities, and fields may vary between versions.

  • Link to JSON: Import the link in the client first, then let the client generate its runtime config. This incorporates local inbound, DNS, and routing settings instead of outputting an isolated outbound fragment.
  • JSON to link: Export only when the outbound parameters can be represented on their own. If you imported a custom config, the client may not offer a generic single-node sharing option.
  • What links can’t carry: Inbound listeners, domain-based routing, DNS policies, rule order, and chained outbound relationships usually don’t transfer through standard share links.
  • Verify after conversion: Compare the address, port, UUID, transport, path, Host, SNI, and TLS or REALITY parameters, then test the connection.

7. Troubleshoot Import Failures: Check the Response, Parsing, and Connection

First identify where the failure occurs. An update error may mean the request never succeeded. “Imported 0 nodes” may mean the text format isn’t supported. If nodes appear but can’t connect, check their connection settings and the scope of the active proxy. Treating these as the same problem leads to repeated encoding or core changes without fixing the underlying issue.

SymptomCheck firstWhat to do
Update returns 401 or 403Subscription token, authorization status, and access conditionsGet a valid URL from the provider; don’t modify the Base64 content
Response starts with HTMLLogin page, redirect page, or request-blocking pageCheck the final response and subscription endpoint; don’t treat page source as node data
Base64 decoding failsTruncated copy, character variants, or paddingConfirm the full text, normalize Base64URL, then decode as UTF-8
Update succeeds but imports 0 nodesWhether the response is a supported link listCheck protocol prefixes after decoding and confirm the server’s output format
Node appears but handshake failsTLS, SNI, system time, and transport parametersCompare the node fields one by one; don’t confuse a format issue with a connection issue
Connection works, but some apps don’tSystem proxy, VPN, and per-app rulesCheck which traffic is handled locally; don’t re-encode the subscription
Why does the node count change after a subscription update?

The server may add or remove nodes, and the client may filter unsupported or duplicate entries. Check the update log and the actual response structure, then compare supported protocols. A different count alone doesn’t mean conversion lost nodes. Don’t manually add old nodes back to an automatically maintained subscription group.

Why does the client reject JSON that parses successfully?

Valid JSON only means the syntax is correct. VMess share JSON, a JSON error response from a subscription endpoint, and a core config can all pass syntax validation but serve different purposes. Check the config structure, protocol support, and import method. Use the custom config option to validate a native core config.

Can I restore DNS and routing rules from a share-link backup alone?

Usually not. Share links mainly contain node connection settings. Before moving clients, also record DNS, system proxy, routing mode, and custom rules; back up the full config separately. After importing, test the connection with a single node before restoring routing rules, so you can distinguish node issues from rule issues.

Download v2rayN