Subscriptions ~9 min read

Clash Subscription Formats Explained: YAML Config, Base64 Links & Converting Between Them

Client won't recognize your subscription link? First learn the difference between Clash YAML, Base64 node lists, and protocol-specific formats, then see how subscription conversion works, common parameters, and privacy considerations.

The real difference between three common subscription formats

Paste a subscription link into a browser, and what comes back isn't always the same kind of content. Most troubleshooting starts from a wrong assumption — that whatever format comes back, the client "should" understand it — without first checking which of the formats it actually is. Subscription content in circulation today generally falls into three categories, each requiring completely different handling.

  • Clash YAML config: The response body itself is a complete YAML document containing fields like proxies, proxy-groups, and rules. It can be parsed and used directly by the Clash / Clash Meta / mihomo core, with no conversion step needed.
  • Base64 node list: The response body is one long Base64 string. Decoded, it becomes a set of lines starting with protocol prefixes like vmess://, ss://, or trojan://. This format is common in the V2Ray/V2RayN ecosystem. The Clash core can't read the whole response directly — it must first be decoded, then each line converted into a proxies entry.
  • Plain-text collections of protocol-specific share links: Without Base64 wrapping, node links are simply listed one per line — common with small, self-hosted panels. Handling is similar to Base64 lists, minus the decoding step.

Telling them apart is straightforward: open the subscription link in a browser or with curl and look at the first line of the response. If it's YAML key-value pairs like port:, mixed-port:, or proxies:, it's a native Clash config. If it's a long string with no line breaks, made up of letters, numbers, and trailing equals signs, it's almost certainly Base64. If every line starts with a protocol name followed by ://, it's a plain-text node list.

Tip: Many panels offer multiple subscription formats from the same source — usually distinguished only by a URL parameter or path suffix (e.g. ?clash=1 or /clash). Before manually converting an unrecognized subscription, check whether the panel's dashboard already offers a Clash-specific link — it's usually far less work.

Key fields in a Clash YAML config

A subscription the Clash core can use directly generally has this skeleton:

port: 7890
socks-port: 7891
mode: rule
log-level: info

proxies:
  - name: "hk-01"
    type: ss
    server: example.com
    port: 443
    cipher: aes-256-gcm
    password: "your-password"

proxy-groups:
  - name: "auto"
    type: url-test
    proxies:
      - hk-01
    url: "http://www.gstatic.com/generate_204"
    interval: 300

rules:
  - DOMAIN-SUFFIX,google.com,auto
  - GEOIP,CN,DIRECT
  - MATCH,auto

Here, proxies describes the connection parameters for each node, proxy-groups organizes nodes into policy groups (automatic latency testing, manual selection, load balancing, and so on), and rules determines which policy group traffic is routed to under which conditions. All three sections matter — if a subscription's YAML only includes proxies without the other two, most clients will auto-generate a default policy group and rule set, though the exact behavior varies by client. It's worth opening the config viewer after import to confirm what was generated.

If you're using the Clash Meta (mihomo) core, you may also see extended fields inside proxies such as tfo, smux, or reality-opts — newer protocol parameters that the original Clash core doesn't recognize. Importing these into the original core will either throw an error or silently skip the affected nodes, which is itself a good signal for whether you need to switch cores.

How Base64 node lists are decoded and converted

A Base64-format subscription is essentially just "a bunch of share links packed into one block of text" so the client can pull updates in one request — it's encoding, not encryption. Once decoded, common node links look roughly like this:

ss://[email protected]:443#hk-01
vmess://eyJ2IjoiMiIsInBzIjoiaGstMDIiLCJhZGQiOiJleGFtcGxlLmNvbSIsInBvcnQiOiI0NDMi...}
trojan://[email protected]:443?sni=example.com#hk-03

The logic for converting each entry is fixed:

  1. Split out the protocol type from the URL (ss / vmess / trojan / hysteria2, etc.).
  2. Decode the user-info segment again (often itself Base64-encoded, as in the userinfo part of ss://), to get the cipher and password.
  3. Map the server address, port, and transport-layer parameters (ws, grpc, TLS-related fields) onto the corresponding field names used in a Clash YAML proxies entry.
  4. Decode the node name (the part after #, usually URL-encoded) back into a readable string.

Doing this by hand for a single node is fine, but subscriptions typically contain dozens or hundreds of nodes — manually editing each one isn't realistic. In practice, this batch conversion almost always relies on a subscription conversion service, covered in the next section.

Two common ways to convert between formats

Turning a Base64/plain-text subscription into YAML that Clash can read generally comes down to two approaches, each with its own trade-offs.

Approach one: built-in client conversion

Some Android clients include format detection built into "New Config" or "Import Subscription": after pasting the link, the client first tries to parse it as Clash YAML, and if that fails, automatically decodes it as Base64 and converts each entry into a local config. This approach doesn't depend on a third-party service — all data is processed locally on the device, making it the cleanest option from a privacy standpoint. However, the conversion quality depends on how well the client itself supports the relevant protocol fields; newer transport-layer parameters (some hysteria2 obfuscation options, for instance) may convert incompletely or get dropped entirely.

Approach two: routing through a subscription conversion service

The other approach is to hand the original subscription link to a conversion service, which decodes and rewrites the format server-side, then gives you a generated Clash YAML link to subscribe to in your client. These services usually support customizable parameters, commonly including:

  • target: the output format — clash or clashr.
  • url: the original subscription address(es); multiple subscriptions can be merged by separating them with |.
  • config: a remote rule template address, which determines the resulting proxy-groups and rules structure; if omitted, the conversion service falls back to its own default template.
  • emoji / udp / tfo: boolean flags controlling whether flag emojis are prepended to node names, and whether UDP forwarding and TCP Fast Open flags are forced on.

The advantage of this approach is stronger conversion capability and reusable templates — useful when you need consistent naming across multiple subscription sources, or need to merge and deduplicate them. The trade-off is that the original subscription link (which contains account credentials) passes through a third-party server, creating a privacy exposure. When choosing a service, check whether it publishes a clear logging policy; the more cautious option is to self-host an open-source conversion service, so the relay step stays under your own control.

Note: Subscription links typically carry a unique user identifier (a token, or a username/password). Once routed through a third-party conversion service, that's effectively exposing your account credentials to that service. If you don't know anything about a conversion service's background, prefer built-in client conversion or a locally deployed conversion tool over handing your raw subscription to an uncontrolled third party.

Common failure cases after conversion, and how to diagnose them

A subscription importing successfully after conversion doesn't guarantee the nodes will actually connect. The following scenarios come up fairly often in practice.

Node count doesn't match

If the converted subscription has fewer nodes than the original, it's usually because the conversion service or client doesn't support a particular protocol field and silently skips the whole node, rather than throwing an error. To diagnose this, check the total node count from decoding the original Base64, then compare it against the number of proxies entries in the generated YAML. If there's genuinely a gap, check whether the missing nodes use a less common protocol (some experimental transport-layer combinations, for example) — switching conversion templates or updating to a core version that supports that protocol usually fixes it.

New nodes don't show up in policy groups

If you're using a remote rule template (specified via the config parameter), the node-filtering rules for each policy group are hard-coded to match keywords in node names. If a new node's name doesn't match the template's keyword pattern (for example, if the template only picks up nodes starting with "HK|SG|JP"), it won't automatically land in the corresponding policy group. Check the filter regex in the template, or simply drop the remote template and let the conversion service fall back to its default "all nodes in one auto-test group" policy.

TLS/SNI parameters lost after conversion

Some protocols — especially Trojan and VMess over WebSocket+TLS — are sensitive to the SNI and skip-cert-verify fields. If the conversion service fails to correctly parse the sni or allowInsecure parameter from the original share link, the resulting node will time out or fail the TLS handshake. In this case, open the generated YAML manually, compare it against the parameters in the original share link, and fill in or fix the servername and skip-cert-verify fields.

Poorly set refresh intervals causing subscriptions to expire

A converted subscription link is essentially a "live proxy request" — every time the client refreshes it, the conversion service re-fetches the original subscription and re-converts it on the spot. If the original subscription enforces a refresh-rate limit (commonly once every few hours), refreshing too often will get flagged as abnormal traffic by the original panel and rejected, which in turn causes the conversion service to return an empty node list. Set the client's subscription refresh interval to somewhere between 6 and 12 hours, and avoid manually hitting refresh repeatedly.

Practical tips for choosing formats and conversion methods

  • If your provider offers a Clash-specific subscription link directly, use it — skip all conversion steps and reduce the chance of errors.
  • If you only have a Base64/plain-text subscription, try the client's built-in conversion first, and only reach for a third-party conversion service if conversion fails or nodes are clearly missing.
  • When using a third-party conversion service, prefer open-source projects you can self-host, keeping the original subscription credentials on a server you control.
  • After conversion, run a full url-test latency check to confirm the node count and latency look right before switching to your regular rule mode.
  • Keep rule templates and node naming conventions stable where possible, to avoid policy-group matching breaking whenever a provider changes its node naming format.

Subscription format conversion might look like a small formatting problem, but underneath it involves the path node information travels through multiple parties. Understanding exactly whose server each piece of data passes through, and in what form it's exposed, is worth more of your time than just getting the link to "work."

Download Client