A subscription URL retrieves content, Base64 encodes text, a share link describes one node, and native JSON describes the runtime configuration. This guide is for anyone dealing with failed imports, missing rules after conversion, or different results across clients. First identify the data format, then use the right import option, and finally check whether conversion preserves transport, TLS, DNS, and routing settings.
1. Subscription URLs, encoding, and node configs are different layers
“V2Ray subscription” isn’t a single, standardized file format. A client first requests the subscription URL, then parses the response body. Common responses contain multiple share links, either as plain lines or Base64-encoded as a whole. Some services return JSON instead. An HTTPS URL only describes how the content is retrieved; it doesn’t guarantee that a particular importer can read the response.
| Item | Typical characteristics | What it contains | Where to import it |
|---|---|---|---|
| Subscription URL | HTTPS address, possibly with an access token | Location of the remote content | Subscription group settings |
| Base64-encoded subscription body | Usually decodes to one link per line | A set of nodes; may not include local policies | Subscription update parser |
| Share link | vmess:// or vless:// | One node and its connection parameters | Import from clipboard |
| Native JSON | Keys such as inbounds and outbounds | Inbound, outbound, and optional DNS and routing settings | Custom configuration import |
JSON is a syntax, not a configuration type. A VMess share object with add, id, and net can pass JSON syntax checks, but it can’t run directly as a complete Xray config. Conversely, Base64-encoding a complete config doesn’t automatically turn it into a node subscription supported by a client.
2. Base64 subscriptions: decode first, then parse each line
Traditional node subscriptions often join multiple share links with newline characters, then encode the entire UTF-8 text. The client decodes the response back into text and parses each line by protocol. A VMess link may also contain another layer of Base64 within the individual link, so successfully decoding the outer subscription doesn’t mean the inner node fields are valid.
- Retrieve the response: Make sure you received subscription content, not a login page, access restriction notice, or server error page.
- Check the outer layer: If the response already starts with a share link, treat it as plain text. Don’t decode it again blindly.
- Decode the content: After decoding the outer Base64 layer, check that the result contains one link per line.
- Parse the nodes: Identify the protocol on each line, then check the server address, port, user ID, and transport parameters.
Standard Base64 commonly uses + and /, and may end with = padding. Some sources use the URL-safe variant with - and _, or omit the trailing padding. Importers vary in how tolerant they are: missing equals signs alone don’t mean a subscription is corrupted, and Base64 should not be treated as URL percent-encoding.
// Local JavaScript example: input is the retrieved text containing multiple share links.
// TextEncoder / TextDecoder preserve Chinese node names.
function encodeSubscription(text) {
const bytes = new TextEncoder().encode(text);
let binary = "";
for (const byte of bytes) {
binary += String.fromCharCode(byte);
}
return btoa(binary);
}
function decodeSubscription(encoded) {
let normalized = encoded.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);
}
This code converts text only; it doesn’t fetch subscriptions or check whether nodes can connect. If decoding fails, first check whether the content was truncated or copied along with explanatory text. Even after successful decoding, a client that supports the relevant protocol must parse the result. Calling btoa() directly on Chinese text in a browser may throw an error, so this example converts the text to UTF-8 bytes first.
3. VMess and VLESS share links: map the fields
A common vmess:// share-link format appends a Base64-encoded JSON object to the protocol prefix. The example below shows the object before encoding. It follows a common sharing convention and is not a complete core config. The domain and UUID illustrate the structure only; they aren’t usable node details.
{
"v": "2",
"ps": "Example VMess WS",
"add": "node.example.org",
"port": "443",
"id": "2d1e7e18-49f4-4ab7-8b63-c929d11c5e29",
"aid": "0",
"scy": "auto",
"net": "ws",
"type": "none",
"host": "node.example.org",
"path": "/proxy",
"tls": "tls",
"sni": "node.example.org"
}
v identifies the share-object format, not the client version. ps is the remark; add and port specify the connection target; and net, host, and path describe the transport. The aid value here is zero; don’t infer that VLESS has a parameter with the same name. Share-link implementations may omit fields, so check the node editor after importing.
VLESS share links commonly use a URI structure: the user ID comes before @, the server and port follow it, query parameters describe transport and security settings, and the remark comes after #. The example below uses the same parameters as the JSON example later in this guide.
vless://[email protected]:443?encryption=none&security=tls&type=ws&host=node.example.org&path=%2Fproxy&sni=node.example.org#Example-WS
security=tlsmeans TLS is used for transport security.encryption=noneis a VLESS parameter; the two settings don’t contradict each other.type=wsspecifies WebSocket;path=%2Fproxydecodes to/proxy.hostis the hostname in the WebSocket request header, whilesnispecifies the TLS server name. They may be the same, but shouldn’t be substituted for each other without checking.- IPv6 addresses need square brackets in URIs. Encode remarks containing spaces, non-ASCII characters, or special symbols according to URI rules.
Takeaway: convert the fields, not the protocol name
Changing vmess:// to vless:// doesn’t convert the protocol. You can create a link for another protocol only if the server provides the corresponding parameters. When representing the same node in another format, preserve its transport, security, and authentication fields.
4. Native JSON: runtime settings beyond node parameters
A native Xray config describes how the entire process runs. Inbounds define where local applications connect; outbounds define how requests reach servers; routing and DNS control traffic selection and name resolution. The minimal config below illustrates the fields and uses VLESS, WebSocket, and TLS. Its example address does not provide a working service.
{
"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": "vless",
"settings": {
"vnext": [
{
"address": "node.example.org",
"port": 443,
"users": [
{
"id": "2d1e7e18-49f4-4ab7-8b63-c929d11c5e29",
"encryption": "none"
}
]
}
]
},
"streamSettings": {
"network": "ws",
"security": "tls",
"tlsSettings": {
"serverName": "node.example.org"
},
"wsSettings": {
"path": "/proxy",
"headers": {
"Host": "node.example.org"
}
}
}
}
]
}
These ports serve different purposes. 10808 binds to the local loopback address; it’s only an example, not a setting used on every device. 443 is the remote listening port and must match the server. If another process is already listening on the same local address and port, a second config may fail to start.
- Link to JSON: Map the node parameters to an outbound, then explicitly add inbounds, DNS, and routing; share links usually don’t include these local settings.
- JSON to link: Extract parameters from an outbound that can be represented as a node. Multiple outbounds usually need to be handled separately; don’t assume they can be combined into one node.
- Preserve policies:
routing,dns, inbound listeners, and logging settings usually don’t carry over to single-node share links. - Core compatibility: Xray and V2Fly differ in supported fields and protocols. v2rayNG uses Xray, while v2flyNG uses V2Fly. The fact that both accept JSON doesn’t mean their configs are interchangeable.
5. v2rayN and v2rayNG: choose the right import option
Menu labels can vary by client version and interface language. The steps below use common menu names. Before importing, identify whether the clipboard contains a subscription URL, a single-node link, or a complete JSON config. In particular, don’t import an HTTPS subscription URL as a regular node link.
v2rayN: import subscription groups and individual nodes separately
-
Add a subscription group
In the main window, go to “Subscription Group” → “Subscription Group Settings.” Select “Add,” enter a remark and subscription URL, then save. Keep all query parameters in the URL intact.
-
Update subscriptions
Return to the “Subscription Group” menu and choose to update the current subscription or all subscriptions. If the menu offers updates through or without a proxy, choose based on what your current network can reach, then check the update log.
-
Import a single node
Copy the complete
vmess://orvless://link, then in the main window choose “Server” → “Import bulk URL from clipboard.” The common shortcut isCtrl+V. -
Check the connection settings
Open the node editor and check the address, port, UUID, transport type, path, and TLS server name. A successful import means the link was parsed; it doesn’t mean the server is reachable.
v2rayNG: subscription groups and clipboard imports
- Subscription URL: Open the top-right menu → “Subscription Group Settings” → “+”, then enter a remark and URL. After saving, return to the main screen and select “Update Subscription” from the menu.
- Share links: Copy one or more links, then on the main screen tap “+” → “Import from clipboard.” Check the number of nodes and their remarks afterward.
- Complete JSON: Use the custom config import option available in your current version; don’t substitute the regular node editor. Android works differently from a desktop setup using a local SOCKS inbound, so don’t assume that copying the desktop inbound will route app traffic.
6. Conversion options: choose what to preserve
“Successful conversion” can mean at least three things: the text decodes, the client imports it, and the connection behaves as expected. Even when the first two succeed, routing, DNS, fingerprints, or extended transport parameters may be lost. Decide what needs to move first; that usually saves more troubleshooting time than hunting for a conversion button.
Move a node with a share link
RecommendedExport using the client’s share or copy-link feature, then import the link in the target client. Check each transport and TLS setting afterward; migrate local routing and DNS separately.
Best for: moving a single node between devices or organizing a small number of connections
Use a subscription URL to maintain a node list
Add the subscription URL in the target client and let it parse and update the list. Converting the response into a static list of links only captures a snapshot; it won’t keep the remote update mechanism.
Best for: groups whose nodes change frequently and need ongoing updates
Preserve policies with native JSON
Move configs between compatible cores, checking file references, ports, system permissions, and supported fields one by one. After importing a custom config, some client UI options may not apply to it.
Best for: configs with multiple outbounds, custom DNS, or complex routing
After migration, check the logs for config parsing or listener errors, then test an actual connection with a node. On desktop, also make sure the system proxy or app-level proxy points to the correct inbound. On Android, confirm the connection service has started and grant VPN interface permission when prompted. A speed test result and browser traffic routed through the proxy are two different checks.
7. Import and conversion FAQs
Why does a subscription URL open, but updating it finds no nodes?
First check whether the response body is an HTML page, an error message, or a format the client doesn’t support. A URL opening in a browser doesn’t mean it returns a node list. Make sure the token hasn’t expired, then check the client’s update log for parsing errors.
After decoding Base64, the text still starts with vmess. Do I need to decode it again?
The outer subscription layer is already decoded. In common formats, the content after the vmess:// prefix on an individual line has another encoding layer. Parse only the payload after the protocol prefix; don’t decode the entire multiline list again. The client handles this layer during a normal import.
Why won’t the core start even though the JSON check passes?
Valid syntax doesn’t guarantee valid fields. First distinguish a VMess share object from a complete config, then check whether the core supports the protocol and fields. If the log reports a listener error, check whether a local port is already in use instead of repeatedly changing the subscription encoding.
Why did my routing rules disappear after converting to a link?
Single-node links usually carry only connection parameters. To restore traffic routing, recreate routing and DNS in the target client or migrate a compatible complete config. Missing local policies don’t mean node authentication parameters were lost.
What should I do if the import succeeds but TLS or handshake errors appear?
Open the node editor and compare the port, transport type, SNI, WebSocket Host, and path against the server details. Check that the device clock is correct. Don’t turn off certificate verification to compensate for incorrect fields. If the original link also fails, continue troubleshooting the server and network connection.