---
title: "How to use VLESS, Trojan or Shadowsocks in one browser"
description: "Paste a vless://, vmess://, trojan:// or hysteria2:// link, or Shadowsocks details, into a Donut Browser profile. Only that browser uses the server."
url: "https://donutbrowser.com/docs/guides/vless-trojan-shadowsocks/"
---

# How to use VLESS, Trojan or Shadowsocks in one browser

A browser cannot speak VLESS, VMess, Trojan, Hysteria2 or Shadowsocks itself. Desktop clients for these protocols usually change the system proxy or add a TUN device, so every app on the computer uses the server. Donut Browser runs the protocol for one profile only: you paste the share link into a proxy, give the proxy to a profile, and the rest of your computer keeps its own connection. You need Donut Browser [installed](https://donutbrowser.com/docs/install) and a share link or Shadowsocks details from your provider.

## What Donut accepts

| Type | What you enter | Notes |
| --- | --- | --- |
| VLESS | A `vless://` link | Security none, TLS or REALITY. Flow `xtls-rprx-vision` only over RAW (TCP) with TLS or REALITY. |
| VMess | A `vmess://` link | The base64 JSON form and the URL form both work. |
| Trojan | A `trojan://` link | TLS by default. A flow on a Trojan link is refused. |
| Hysteria2 | A `hysteria2://` or `hy2://` link | Obfuscation: Salamander only. Port hopping is refused. |
| Shadowsocks | Host, port, cipher and password | Ciphers `aes-128-gcm`, `aes-256-gcm` and `chacha20-ietf-poly1305`. No 2022 ciphers. |

For VLESS, VMess and Trojan, the transport can be RAW (TCP), WebSocket, gRPC, HTTPUpgrade or XHTTP. mKCP, HTTP/2 and QUIC transports are not supported. REALITY works over RAW without the HTTP header, gRPC or XHTTP, and the link must have `sni` and `pbk`.

Donut ships Xray-core 26.3.27 inside the app for the four link types. On macOS they need macOS 12 or newer.

## 1. Copy the link from your provider

Copy one share link for one server. A link holds the server address, the credentials and the transport, so you do not need to fill in anything else.

Donut does not read subscription URLs, the address that returns a list of servers. Open the subscription in your client or browser, copy the individual links, and add each one as a proxy. To add many links at once, paste them one per line into **Import** on the **Proxies** tab. Each line becomes one proxy.

## 2. Add the proxy

1. Open **Network** in the sidebar (**Cmd/Ctrl+Shift+N**). Stay on the **Proxies** tab.
2. Click **New proxy** and enter a **Name**.
3. In **Type**, choose **VLESS**, **VMess**, **Trojan** or **Hysteria2**. They are in the group "First hop set by the link".
4. Paste the link into **Share link**. The field replaces host, port, username and password.
5. Click **Add Proxy**.

Donut checks the link while you type. If you pasted a link of another type, **Type** changes to match it. If Donut cannot use the link, the reason shows under the field. See [Troubleshooting](https://donutbrowser.com/docs/guides/vless-trojan-shadowsocks/#troubleshooting).

### Shadowsocks

Choose **Shadowsocks** in **Type** (group "First hop depends on the cipher") and fill in **Host**, **Port**, **Cipher** and **Password**. The password is required. You can also paste a link of the form `ss://aes-256-gcm:password@host:port` into **Host**, and the form fills in the fields.

Many providers give `ss://` links with the method and password in base64 (the part between `ss://` and `@`). Donut does not decode that part. Decode it first. This command adds the padding that such links leave out, which `base64 -d` on macOS needs:

```bash
python3 -c "import base64,sys; s=sys.argv[1]; print(base64.urlsafe_b64decode(s + '=' * (-len(s) % 4)).decode())" YWVzLTI1Ni1nY206cGFzc3dvcmQ
# aes-256-gcm:password
```

Then enter the cipher and the password in the form.

## 3. Check the proxy

Click the check button in the **Status** column. For a share link, Donut starts Xray-core for the check and connects through it. **Connection details** shows the exit IP, its location, ISP and timezone. If the check fails, the toast starts with "Proxy check failed:" and gives the reason.

The **UDP** result for share-link proxies comes from the local Xray-core process, not from your server. It does not prove that the server relays UDP. For Shadowsocks, Donut does not relay UDP at all, and the column stays unknown. Use the [WebRTC leak test](https://donutbrowser.com/tools/webrtc-leak-test) in the profile to see what sites get.

## 4. Give the proxy to a profile

Choose the proxy in **Create new profile** (the picker that reads "No proxy / VPN"), or in the **Network** section of an existing, stopped profile. When the profile launches, Donut starts one Xray-core process for that profile. It listens on `127.0.0.1` with a random username and password, and the browser reaches it through Donut's local relay. No other app on your computer uses it.

Open [What is my IP](https://donutbrowser.com/tools/what-is-my-ip) in the profile to confirm the server's exit IP.

Before a launch, Donut compares the profile's timezone and language with the exit of a share-link proxy. It does not measure Shadowsocks exits, so with Shadowsocks it is up to you to keep the two in step. See [How to match a browser's timezone and language to its proxy](https://donutbrowser.com/docs/guides/match-timezone-to-proxy).

## Add it with the API

The [local API](https://donutbrowser.com/docs/quickstart) takes the link in `vless_uri` for all four link types. The name is historical. Host and port are still required fields; Donut reads the real server from the link.

```bash
curl -sS -X POST http://127.0.0.1:10108/v1/proxies \
  -H "Authorization: Bearer $DONUT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "NL VLESS",
    "proxy_settings": {
      "proxy_type": "vless",
      "host": "nl.example.com",
      "port": 443,
      "vless_uri": "vless://<uuid>@nl.example.com:443?security=tls&type=ws&host=nl.example.com&path=%2Fws#NL"
    }
  }'
```

```python
import os, requests

link = "trojan://<password>@de.example.com:443?sni=de.example.com#DE"
response = requests.post(
    "http://127.0.0.1:10108/v1/proxies",
    headers={"Authorization": f"Bearer {os.environ['DONUT_API_KEY']}"},
    json={
        "name": "DE Trojan",
        "proxy_settings": {
            "proxy_type": "trojan",
            "host": "de.example.com",
            "port": 443,
            "vless_uri": link,
        },
    },
    timeout=10,
)
print(response.status_code, response.json())
```

For Shadowsocks, use `"proxy_type": "ss"` and put the cipher in `username` and the password in `password`. `POST /v1/proxies/import` with `"format": "txt"` takes a list of links, one per line. See [Import proxies in bulk](https://donutbrowser.com/docs/rest-api#import-proxies).

## Troubleshooting

These are the messages the form shows under **Share link**:

| Message | Cause |
| --- | --- |
| "That is not a supported share link. It must start with vless://, vmess://, trojan://, hysteria2:// or hy2://." | Another scheme, such as `ss://` in the share link field. Use the Shadowsocks type instead. |
| "This link uses a transport, or a transport mode, that Donut does not support. …" | mKCP, HTTP/2 or QUIC transport. Ask your provider for a WebSocket, gRPC, XHTTP or TCP link. |
| "This link uses a security setting Donut does not support. …" | REALITY over WebSocket or HTTPUpgrade, or another security value. |
| "This link uses a flow Donut does not support. …" | XTLS Vision outside VLESS over RAW with TLS or REALITY. |
| "This link uses an encryption setting Donut does not support." | VLESS with `encryption` other than `none`. |
| "The link is missing a valid server name (sni)." or "The link is missing the REALITY public key (pbk)." | A REALITY link without `sni` or `pbk`. |
| "This Hysteria2 link uses an obfuscation Donut does not support. Donut supports Salamander only." | Another obfuscation type. |
| "The link contains an option Donut does not support." | An unknown option, or Hysteria2 port hopping. |

Donut always checks the server's TLS certificate. `allowInsecure=1` in a link is ignored, so a server with a self-signed certificate fails the check.

For Shadowsocks, "Unsupported Shadowsocks cipher" means the cipher is not one of the three AEAD ciphers above. "VLESS, VMess, Trojan and Hysteria2 proxies require macOS 12 or newer." means the Mac is too old for the bundled Xray-core.

## Related

- [Proxies, VPNs and DNS](https://donutbrowser.com/docs/proxies): every proxy type and setting.
- [How to use a SOCKS5 proxy with a username and password](https://donutbrowser.com/docs/guides/socks5-proxy-with-password)
- [How to route one browser through WireGuard](https://donutbrowser.com/docs/guides/wireguard-one-browser)

Donut Browser is free and open source, and each of its profiles can use a different server. [Download it](https://donutbrowser.com/) for macOS, Windows or Linux.
