# subconverter: converting and merging proxy subscriptions on your own machine

> subconverter is a C++ service that rewrites subscription links between Clash, Surge, Quantumult X, V2Ray and other formats, and merges several subscriptions into one. It fits engineers who want a self-hosted conversion endpoint, not people looking for a graphical client.

**tindy2013/subconverter** — Utility to convert between various subscription format

- Repository: https://github.com/tindy2013/subconverter
- Stars: 17,079 · Forks: 3,847
- Language: C++
- License: GPL-3.0
- Published: 2026-09-21 · Updated: 2026-09-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/tindy2013-subconverter

## The subscription format problem subconverter exists to solve

Proxy subscription providers hand out links in whatever format their panel emits. One gives you a Clash YAML, another a base64 blob of vmess and ss URIs, a third a Surge list. If you use more than one provider, or switch clients, you end up maintaining several profiles by hand and re-checking them whenever a provider changes its output.

subconverter sits between the provider and your client. You give it a target format and one or more source URLs, and it returns a subscription in the format you asked for. The README describes it as a "Utility to convert between various proxy subscription formats", and the support table makes the scope concrete: Clash, ClashR, Quantumult, Quantumult X, Loon, SS (SIP002), SS Android, SSD, SSR, Surfboard, Surge 2, 3 and 4, and V2Ray can each act as a source and as a target. Telegram-style HTTP and Socks 5 links are accepted as a source only, which is a deliberate asymmetry: those links carry a server, port, user and password, and the README notes you can append `&remark=` to give the node a name.

The audience is narrow and specific. It is for people who run their own endpoint and want a stable URL to paste into a client, not for someone who wants a GUI to click through. The project ships no web interface in the repository; the top-level entries are build files, `base/`, `include/` and `src/`. If you want a UI, that is something the community builds around it, not something subconverter provides.

## How the /sub endpoint converts and merges subscriptions

The whole service is reached through one HTTP endpoint on port 25500. The README gives the shape as `http://127.0.0.1:25500/sub?target=%TARGET%&url=%URL%&config=%CONFIG%`. Three arguments matter. `target` is mandatory and takes a name from the Target Name column of the support table, such as `clash`, `quanx`, `surge&ver=4` or `v2ray`. `url` is mandatory and is the subscription to convert; it accepts a URL or a file path, and it must be URL-encoded before it goes into the query string. `config` is optional and points at an external configuration file, also URL-encoded, which is how you override the default groups and rulesets.

Merging is done inside the `url` argument rather than through a second parameter. The README instructs you to join two or more subscriptions with a pipe character before encoding. So two provider links become one string separated by `|`, and the encoded result is what you pass as `url`. The service fetches each source, parses the nodes, and emits a single document in the requested target format. That is the data flow: HTTP request in, outbound fetch of each source, format-specific parse, format-specific render, HTTP response out.

The `config` argument is where the design gets opinionated. Default groups and rulesets are applied when you pass nothing, which the README calls "Quick Usage". Passing a config URL replaces that behaviour with your own proxy groups and rule sets, and the README points at a third-party repository, `lzdnico/subconverteriniexample`, for examples rather than documenting the config schema itself. That is a real gap: the English README tells you the argument exists and then hands you off.

## Installing subconverter and making a first conversion request

The repository does not document a package manager install in the English README. It links a separate `README-docker.md` for container use, and the presence of `CMakeLists.txt`, `cmake/` and `src/` means a source build is the other path. If you want the container route, read that Docker README before picking a tag, because the main README does not restate its commands.

For the request itself, the README's own worked example is the thing to copy. It merges two subscriptions and asks for Clash, with the pipe separating the sources and the whole string URL-encoded before it becomes the `url` parameter. Substitute your own provider links and paste the result into a client:

```txt
http://127.0.0.1:25500/sub?target=clash&url=https%3A%2F%2Fdler.cloud%2Fsubscribe%2FABCDE%3Fclash%3Dvmess%7Chttps%3A%2F%2Frich.cloud%2Fsubscribe%2FABCDE%3Fclash%3Dvmess
```

What you should see is a Clash-format subscription body containing the nodes from both sources. The README says that once you subscribe this link in Clash, you are done. If you want the output pushed somewhere instead of fetched, the Auto Upload section covers Gist: put a personal access token in `gistconf.ini` in the root directory and add `&upload=true` to the link. The README shows the file contents as a `[common]` section with a `token` key, and notes the token line is commented out until you uncomment it:

```ini
[common]
;uncomment the following line and enter your token to enable upload function
token = xxxxxxxxxxxxxxxxxxxxxxxx(Your Personal Access Token)
```

## Where subconverter is the wrong tool

The endpoint has no authentication in the interface the README documents. Anyone who can reach port 25500 can ask it to fetch a URL and return a rendered subscription, and if `upload=true` is set with a token in `gistconf.ini`, the service will write to your Gist. Binding it to a public interface without a reverse proxy in front is a decision you should make deliberately, and the README does not discuss access control.

The second limitation is documentation depth. Advanced usage is not in the English README at all; it says to refer to the Chinese document. If you need to understand how a custom `config` file shapes proxy groups, the English page will not get you there. The `config` examples live in a separate repository maintained by someone else, which means the schema you depend on is not versioned alongside subconverter itself.

The third is format drift. The support table is a snapshot of what the project handles, and the most recent release listed is v0.9.0 from 2024-04-08. Newer client formats or provider quirks will not appear in that table until a release adds them. If your provider changes its output and subconverter has not caught up, the conversion fails at parse time and you are debugging someone else's format parser.

Finally, the merge model is all-or-nothing per request. You join sources with `|` and get one document. There is no documented per-source filtering or ordering step in the README, so if you want to drop some nodes from one provider and keep the rest, that work belongs in the `config` file, which again is documented in Chinese.

## subconverter alternatives and how they differ

The search data around this project is full of names that are not alternatives in the same sense: Clash, mihomo, sing-box and Surge are clients, and subconverter is not a client. It does not connect to anything. It rewrites text. Comparing it to a proxy client is a category error, and it is worth being blunt about that because the related searches suggest people conflate them.

The real alternative is doing the conversion yourself. A short script that fetches a base64 subscription, decodes it, parses the URIs and emits a Clash YAML does the same job for one format pair. The difference in approach is scope and maintenance: subconverter carries parsers and renderers for a dozen formats and applies default groups and rulesets, while your script handles exactly the two formats you wrote it for and breaks when a third appears. If you only ever convert one provider's output into one client's format, a script is less machinery. If you juggle several providers and several clients, the matrix in the support table is the reason to run a service.

A second alternative is asking the provider to emit the format you want. Many panels offer a Clash link and a Surge link side by side, which removes the conversion step entirely. That works until you need to merge two providers into one profile, which is the case subconverter was built for and the one a provider-side format switch cannot solve.

## Maintenance, releases and the GPL-3.0 licence

The repository is not archived, and the last push was on 2026-07-09. That is recent activity on the repository, but the release list tells a different story about versioned output: v0.9.0 landed on 2024-04-08, after v0.8.1 on 2023-10-12 and v0.8.0 on 2023-10-09. So commits continue while tagged releases are sparse. If you deploy from a release binary, you are running code from April 2024. If you build from `master`, you get whatever has landed since, with no version number attached to it. That is the upgrade cost in practice: either track tags and wait, or build from source and own the diff.

The licence is GPL-3.0, and the repository carries a `LICENSE` file at the top level. The practical implication for a self-hosted deployment is that running it on your own server is the ordinary case the licence permits. The implication people miss is distribution: if you ship a modified subconverter inside a product, GPL-3.0's copyleft terms attach to that distribution. That is not legal advice, and if your plan involves redistributing a modified build, read the `LICENSE` file and talk to someone qualified rather than trusting a summary.

One more maintenance note: the Docker path has its own README, `README-docker.md`, separate from the main one. When you upgrade, check both, because image tags and the main README's build instructions are maintained as different documents.

## Conclusion

Adopt subconverter if you already run a server or Docker host and need one URL that turns several provider subscriptions into a single Clash, Surge or Quantumult X profile. Skip it if you want a desktop client with a graphical editor, or if you cannot expose port 25500 on a trusted network. Before deploying, verify that your provider links point at hosts the converter can reach, and read the Chinese README before writing a custom config, because the advanced options are not documented in English.

## FAQ

### What can I use instead of subconverter?

The honest answer from the documentation is a script of your own that parses one source format and renders one target format, or asking your provider for a link in the format you need. subconverter earns its place when you merge several subscriptions or need many format pairs, which a single-purpose script does not cover.

### How do I merge two subscriptions with subconverter?

Join the subscription URLs with a pipe character, URL-encode the combined string, and pass it as the url argument to the /sub endpoint. The README's example merges two Clash subscriptions this way and returns one Clash profile.

### Does subconverter have a web interface?

The repository does not ship one. The top-level entries are build files, base/, include/ and src/, and the documented access path is the /sub endpoint on port 25500. Any UI you see is built by someone else around that endpoint.

### What port does subconverter listen on?

The README's access interface uses 127.0.0.1:25500, so the default is port 25500. The interface section does not describe authentication, which is worth accounting for before you expose it beyond localhost.

### Can subconverter upload the result to a Gist automatically?

Yes. Put a personal access token under the token key in gistconf.ini in the root directory, then add upload=true to the subscription link. The README notes the token line in that file is commented out until you uncomment it.

### Which subscription formats can subconverter read and write?

Clash, ClashR, Quantumult, Quantumult X, Loon, SS (SIP002), SS Android, SSD, SSR, Surfboard, Surge 2, 3 and 4, and V2Ray each work as both source and target. Telegram-style HTTP and Socks 5 links work only as a source, and Shadowrocket users are told to pick ss, ssr or v2ray as the target.

## Sources

- [Issues](https://github.com/tindy2013/subconverter/issues)
- [License: GPL-3.0](https://github.com/tindy2013/subconverter/blob/master/LICENSE)
- [README](https://github.com/tindy2013/subconverter/blob/master/README.md)
- [Releases](https://github.com/tindy2013/subconverter/releases)
- [tindy2013/subconverter on GitHub](https://github.com/tindy2013/subconverter)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/tindy2013-subconverter
