1. The latency number in the dashboard isn’t download speed

The 120 ms shown on a Clash client’s proxy page usually comes from a kernel request sent through the selected node to a specified URL. It tells you how long that proxy path took to complete a small request—not how much data it can download per second. Manual tests, subscription health checks, and automatic url-test selection may use different test URLs and timeouts, so check the source before comparing results.

Latency is measured in milliseconds; throughput is usually measured in Mbps or MB/s. Suppose node A reports 80 ms and downloads at 2 MB/s, while node B reports 160 ms and reaches 15 MB/s. Node A may suit frequent small requests better, while node B may be better for large downloads. These figures illustrate the difference between metrics; they are not real-world test results or performance guarantees.

2. What happens during a url-test request

For example, a proxied request to https://www.gstatic.com/generate_204 follows this path: client core → proxy server or proxy chain → test site → response. This URL typically returns HTTP 204 without a large response body, so it’s suited to lightweight reachability checks—not measuring sustained throughput.

  1. Prepare the destination and connection details. Resolve the proxy server address and prepare the test host or URL. Whether DNS resolution happens locally or remotely depends on the protocol, DNS settings, and connection path.
  2. Connect to the proxy. Depending on the node’s protocol, this may involve a TCP connection, TLS, WebSocket, or a UDP-based transport handshake. The overhead varies by protocol.
  3. Establish a route to the destination. The proxy’s exit connects to the test site. An HTTPS destination also requires a TLS handshake with the site, which is separate from any TLS used by the proxy protocol.
  4. Send the request and wait for a response. The destination processes the request, the response returns over the proxy path, and the core records the test result.

Don’t treat these four steps as a fixed timing formula used by every version. Original Clash, Clash Meta (now called mihomo), and different releases may vary in request methods, connection reuse, repeated probes, and how latency is recorded. DNS caching can also affect the overhead. To explain a specific reading, note the client and core versions and check the corresponding implementation.

Why the first result can differ from later ones

The first request may trigger a DNS lookup and use a cold connection. Later tests may benefit from caches or session resumption, or be affected by changes in server load. Even when each test opens a new connection, not every state starts from scratch. If the first result is 240 ms and the next is 130 ms, that alone doesn’t mean the node suddenly got faster.

3. The test URL can change the node ranking

A URL test measures the route from a node to a specific destination. The test site’s CDN, geographic routing, and ISP peering may differ from those used by the sites you actually visit. A node might reach the test URL quickly but take a roundabout route to a code repository, video CDN, or work service—so low dashboard latency can coexist with sluggish browsing.

Condition Effect How to check
HTTP vs. HTTPS HTTPS adds a TLS exchange with the destination, which can change the ranking Use the same protocol and URL for each comparison
CDN geographic routing Different exits may reach different edge servers Verify against the domain you actually use
IPv4 vs. IPv6 Different address families can use different routes and have different reachability Check DNS results and outbound connection logs
Site rate limiting or outage Multiple nodes may slow down or time out at once Retest with another lightweight URL known to be reachable

When changing the test URL, check the response status and the health-check criteria used by your current core. Pages that require a login, keep redirecting, or show access challenges aren’t reliable probes. If expected-status is configured, an unexpected status code may count as a failure; not every failed test means the route is down.

4. How concurrency, congestion, and packet loss widen the gap

A small request can’t measure sustained bandwidth

A request with almost no response body finishes quickly. It can’t reveal how the congestion window grows during a long download, bandwidth limits, persistent packet loss, or load on a shared exit. During peak hours, a route may still complete a small request in about 100 ms but fail to stream HD video reliably.

Testing every node at once can cause interference

Batch tests open multiple connections in a short time. Nodes may share an entry point, relay link, or even an exit. Your Wi-Fi, router’s connection-handling capacity, and ISP uplink can all affect results. Uploading a large file in the background can also add significant queueing delay.

  • Pause large uploads, cloud sync, and other speed tests first.
  • Choose 2–3 candidate nodes from the batch results and retest them individually.
  • Test each candidate at least five times; record the median, highest reading, and number of failures.
  • Retest during the hours you normally use the service. Daytime results don’t reflect evening peak loads.

For example, five results of 90, 92, 95, 98, and 800 ms have a median of 95 ms, but that spike is still worth investigating. If two of five tests fail, don’t compare nodes using only the lowest of the three successful readings. Jitter and packet loss often affect browsing and real-time communications more than average latency does.

5. url-test doesn’t mean fastest downloads

url-test is a proxy group type that automatically selects an outbound based on probe results. It doesn’t download large files to compare bandwidth or know whether you’re streaming video, on a call, or updating software. select lets you choose manually; fallback checks outbounds in order for an available one. These group names don’t all mean “speed optimization.”

When reviewing an existing url-test group, start with the fields below. This example explains what the fields mean; it isn’t a complete subscription and shouldn’t replace your entire configuration file. Supported fields depend on your core version.

type: url-test
url: https://www.gstatic.com/generate_204
interval: 300
tolerance: 50
lazy: true
  • interval: 300: Run checks every 300 seconds. This doesn’t mean every page request triggers a new test.
  • tolerance: 50: Set the switching tolerance in milliseconds to avoid frequent switches over small differences. It’s not a timeout limit and won’t increase bandwidth.
  • lazy: true: Skip scheduled checks while the group is unused. How the core determines whether a group is active depends on its current implementation, so the dashboard may show an older result.

A subscription’s proxy-providers may also have its own health-check. Health checks for a proxy collection and tests for a proxy group don’t map one-to-one, and manual client tests may use different settings again. When troubleshooting, check the probe URL, result timestamp, and configuration source so you don’t mistake an old result for the current state. Subscription updates may overwrite local changes; use the client’s supported override mechanism for persistent customizations.

6. Verify nodes with real requests, not just dashboard readings

Set the outbound mode to Rule, pin a candidate node on the proxy page, then check the connection log to confirm which rule, proxy group, and final outbound handled the request. The system proxy only affects apps that honor it; terminal tools may not use it. TUN mode captures traffic from more apps, but doesn’t increase the route’s bandwidth.

Run a repeatable test through the mixed port

The command below is for macOS Terminal and assumes the client’s mixed port is 7890. Check the port in the client’s settings first; use the actual value if it differs. -x explicitly sets the local HTTP proxy instead of relying on the terminal to follow the system proxy. --noproxy "" prevents an existing proxy bypass list from sending the request directly by mistake.

curl --noproxy "" -x http://127.0.0.1:7890 \
  --connect-timeout 10 --max-time 20 \
  -sS -o /dev/null \
  -w 'status=%{http_code}\nconnect=%{time_connect}s\ntls=%{time_appconnect}s\nfirst_byte=%{time_starttransfer}s\ntotal=%{time_total}s\n' \
  https://www.gstatic.com/generate_204

Here, time_connect mainly reflects the TCP connection to the local proxy; time_appconnect is the cumulative time to complete the relevant secure handshake; and time_starttransfer is the cumulative time until the first byte arrives. These aren’t separate, non-overlapping phases, nor do they map directly to the core’s probe reading in the dashboard. This test makes the request conditions repeatable; it doesn’t show that two implementations should report the same number.

Test real services and sustained throughput

  1. Open the sites you actually use and visit several pages in a row. Check that the initial page, sign-in, and resource loading all work as expected.
  2. Download the same file from a fixed source you’re authorized to access and that permits testing. Keep the number of concurrent downloads consistent and check the stable speed over 30–60 seconds.
  3. Record the time, network conditions, node, failures, and sustained speed. Switch nodes and repeat; don’t run multiple download tests at once.

Keep the units in mind: 8 Mbps is about 1 MB/s, and protocol overhead reduces the throughput an app actually gets. Don’t compare Mbps on a speed test with MB/s in a browser’s download window by their raw numbers.

7. Low latency but sites won’t load? Check these in order

  1. Check that the result is current. Retest one node manually and note the test URL and time. Rule out cached results and scheduled checks that haven’t run.
  2. Confirm the request uses that node. Check the matched rule and final outbound on the connection page. Some domains may match DIRECT or use a different proxy group.
  3. Check how traffic enters the client. Make sure the system proxy is enabled and the app isn’t using its own proxy. With TUN mode, also check permissions, routes, and interference from other VPNs.
  4. Check the destination and DNS. A reachable probe doesn’t guarantee that a service domain is reachable. Look in the logs for resolution failures, connection timeouts, and TLS errors. Don’t change every DNS setting at once when something breaks.
  5. Distinguish TCP from UDP. A successful HTTPS request doesn’t prove UDP forwarding works. Games, voice calls, and QUIC need separate checks for protocol support and the actual route.
Does a timeout in the dashboard mean the node is unusable?

Not necessarily. A timeout could mean the proxy connection failed, but it could also be caused by the test site, DNS resolution, rate limiting, or a deadline that’s too short. First try another lightweight URL known to be reachable, then test the service you actually need. If multiple independent destinations fail, use the logs to narrow down the node or local network.

Will setting the test interval to 10 seconds make automatic selection more accurate?

More frequent doesn’t mean more accurate. Probing many nodes every 10 seconds adds connections and traffic, and can make selection chase short-lived fluctuations. Start with an interval such as 300 seconds and a sensible tolerance; manually retest candidate nodes when the network misbehaves. This usually makes results easier to interpret.