Sep 11, 2026 · Subscriptions · About 8 min read

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

Learn how Base64 subscriptions, native JSON configs, and share links like vmess:// differ—and how to convert between them in a client.

At a glance

First identify what you have: a subscription URL, a list of share links, or a complete core config. This guide is for anyone wondering why decoding still shows links or why JSON cannot be imported as a subscription. Starting with v2rayN subscription groups and clipboard import, it covers Base64 encoding and decoding, node exports, the limits of converting native JSON, local processing, and troubleshooting.

Three formats, three roles: subscriptions distribute nodes; JSON configures the core

Distinguish the URL you request from the content it returns. A subscription URL is usually an HTTPS address with access credentials; the client fetches node data from it. Base64 is a common format for the returned content—not a proxy protocol, and not a guarantee that every subscription uses the same encoding. Decoding the subscription URL itself usually won't reveal any nodes.

FormatTypical structureWhat it's used for
Base64 subscription contentMultiple share links, one per line, encoded togetherFetches multiple nodes through subscription updates
Share linkProtocol prefixes such as vmess:// or vless://Imports node details from the clipboard
Native JSON configFields such as inbounds, outbounds, and routingLoaded by a compatible core

A share link describes a remote connection: address, port, credentials, transport, and TLS settings. A complete JSON config can also include local listeners, DNS, routing rules, and multiple outbounds. So a node can be exported as a share link, but that doesn't mean the entire runtime config fits in one.

Decoding Base64: unwrap the outer layer, then identify the protocol

A traditional Base64 subscription has two layers: the outer layer encodes the full list of links, while each line inside still follows its own share-link format. After removing the outer layer, seeing vmess:// is expected. Don't apply the same decoding rule to every link.

The JavaScript below demonstrates local UTF-8 encoding and decoding only. Entering node produces bm9kZQ==; this is a character-encoding example, not a usable node. For real subscriptions, work only in a trusted local environment. Never submit content containing tokens to an online conversion service.

function decodeBase64Utf8(input) {
  let value = input.trim().replace(/\s+/g, "")
    .replace(/-/g, "+").replace(/_/g, "/");
  value = value.padEnd(Math.ceil(value.length / 4) * 4, "=");
  const bytes = Uint8Array.from(atob(value), char => char.charCodeAt(0));
  return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
}

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

console.log(encodeBase64Utf8("node"));       // bm9kZQ==
console.log(decodeBase64Utf8("bm9kZQ=="));   // node

Successful decoding only means the encoded content is readable. If the result is a login page, expiry notice, or other HTML, it isn't a valid node list. Re-encoding it or changing the file extension won't fix the subscription; check the URL and access permissions instead.

Importing into v2rayN: subscription URLs and clipboard links

To keep nodes updated, add a subscription group. If you only have one or more share links, import them from the clipboard. The steps below use menu names from the Chinese v2rayN interface. Button locations may vary between desktop versions, and punctuation or spacing may differ; follow the menus in your installed version.

  1. Identify what you have

    Use an HTTPS fetch URL for a subscription group; use content starting with vmess:// or vless:// to import nodes. Don't paste a complete JSON config into the subscription URL field.

  2. Add a group

    Open “Subscription Group” → “Subscription Group Settings,” add a group, enter a name and subscription URL, then save. Keep all query parameters and access tokens in the URL.

  3. Update subscriptions

    From the “Subscription Group” menu, select “Update all subscriptions (without proxy).” If a direct request fails and you have a working proxy connection, try “Update all subscriptions (through proxy)” and check the update log.

  4. Import share links

    For share links, copy the complete text, then open “Servers” → “Import batch URLs from clipboard.” Put each link on its own line. Many desktop versions also support clipboard import with Ctrl+V.

  5. Check the settings

    Open the imported node's edit window and verify the address, port, transport protocol, and TLS settings. A successful import doesn't guarantee a working connection. Check the core log for unsupported fields or handshake failures.

Android clients also use separate import paths. v2rayNG uses the Xray core, while v2flyNG uses the v2fly core. Both may read the same link list, but that doesn't mean they support every transport parameter in it. For combinations such as VLESS and REALITY, check support in the target client and core first instead of repeatedly changing the Base64 wrapper.

Share links and native JSON: what converts, and what gets lost

Converting a share link to JSON means mapping fields—not just wrapping the text in braces. The client reads the link, creates a node record, and generates a runtime config for the selected core. Exporting in the other direction usually extracts connection details for one outbound; it won't automatically include the full DNS, routing, or local listener setup.

Keep the original subscription

Recommended

Save the fetch URL and update it through a subscription group to keep receiving node changes from the provider. Treat subscription tokens as access credentials.

Best for: maintaining multiple nodes and keeping them up to date

Export share links

Select a node in the list, then use the share URL export option in the right-click menu to copy it to the clipboard. The result is a snapshot of the node, not a link to the original subscription for future updates.

Best for: moving a few nodes temporarily or checking connection fields

Keep the complete JSON config

Preserve multiple outbounds, routing tags, and DNS settings, then load the config with its corresponding core. Before using it with a different core, check what each field means; changing the file extension isn't enough.

Best for: custom routing or a fixed local inbound setup

Back up the complete config before converting

If you only need to move a node connection, export a share link. To preserve DNS and routing, save the native JSON config separately and check each field against the target core's supported options. Don't use a share-link export as a substitute for a config backup.

This sample config is for illustrating structure only. It contains a SOCKS inbound listening on 127.0.0.1:10808 and a direct outbound; it has no remote proxy server and should not be imported as a proxy node. A complete JSON config may have no object that can be converted into a VMess or VLESS link.

{
  "log": {
    "loglevel": "warning"
  },
  "inbounds": [
    {
      "tag": "local-socks",
      "listen": "127.0.0.1",
      "port": 10808,
      "protocol": "socks",
      "settings": {
        "auth": "noauth",
        "udp": true
      }
    }
  ],
  "outbounds": [
    {
      "tag": "direct",
      "protocol": "freedom",
      "settings": {}
    }
  ]
}

To load a complete config, use a dedicated v2rayN entry such as “Servers” → “Add custom config server,” then select the config file and a compatible core. A custom config's listening port may conflict with an existing instance. If the log says the address is already in use, stop the conflicting instance or change the port—don't alter the node's identity details.

Re-encode a list of links as subscription content

If you've exported multiple share links, put them together as plain text, one link per line, then Base64-encode the entire UTF-8 text. This creates traditional subscription content, but not an auto-updating subscription URL. A trusted HTTPS service still needs to serve that content at the URL.

  1. Keep each link's protocol prefix, query parameters, and remarks intact. Don't remove TLS or transport fields just because they look redundant.
  2. Join the links with newline characters \n. Don't add bullets, quotation marks, JSON array brackets, or table separators.
  3. Encode the complete text once. Don't encode each full share link separately and then combine them into a list clients can't recognize.
  4. Decode it locally once and confirm that each original line is intact, then try importing it into the target client. Check the node count and key fields—not just the success message.

Extracting links in bulk from a complete JSON config also means handling multiple outbounds, tag references, and transport-field mappings. Record any fields the target share-link format can't represent separately. A conversion tool producing links only shows that it serialized some data; it doesn't prove the links behave like the original config.

Import troubleshooting: check the content first, then the core

Why do I still see vmess:// after decoding?

That means the outer subscription encoding has been removed. Copy the links, one per line, then select “Servers” → “Import batch URLs from clipboard.” To inspect VMess fields, decode only the part after the link's prefix. Don't decode the entire line with the prefix included.

Import says it succeeded, but some nodes are missing

Compare the number of non-empty decoded link lines with the number of nodes actually imported, then inspect the protocol prefix and fields in failed lines. Some entries may not have been added because they were duplicates, malformed, or used an unsupported protocol. A lower node count alone doesn't mean the subscription is corrupted.

Why won't the client accept JSON that opens correctly?

A JSON parser accepting the file only means its syntax is valid. Check for top-level inbounds and outbounds, then confirm you're using the custom-config import path and a compatible core. The add and id fields in VMess share data are not a complete runtime config.

What if a subscription update returns 403 or times out?

For a 403, check authorization, the token, or the server's access policy. For a timeout, check your network and DNS resolution. Keep every parameter in the original URL. If you have a working node, try “Update all subscriptions (through proxy).” Re-encoding an error page won't help.

Troubleshoot in order: first confirm the subscription request returned valid content, then check that share links parse, and finally inspect the runtime core and connection settings. Track “download failed,” “unsupported format,” and “connection failed” separately to avoid repeatedly converting data at the wrong layer.

Download v2rayNChoose a client for your platform