Skip to main content
EN

Home / Blog / Config Basics

How latency testing actually works, and what interval, tolerance and lazy should be

Config Basics2026-07-051259 words3 min read
How latency testing actually works, and what interval, tolerance and lazy should be

Where does the millisecond figure next to each node come from? Why is it so far off what ping reports? And why does the automatic group keep switching?

This explains the whole business of latency testing.

It is not a ping — it is a complete HTTP request

The steps Clash goes through:

What one latency test involvesOpen a TCP connectionto the node's serverComplete the encrypted handshakeTLS or protocol handshakeRequest the target URL through the nodegstatic.comReceive the 204 responserecord the total elapsed time
So it measures "the round trip to a target site through this node", not the network distance to the node

That is fundamentally different from ping:

pingClash latency test
ProtocolICMPTCP + TLS + HTTP
Path measuredyou → nodeyou → node → target site → back
Includes handshakeNoYes
ReflectsNetwork distanceReal usage experience

So Clash showing 180 ms while ping says 60 ms is entirely normal — the difference is handshake cost plus the leg from the node to the target site.

unified-delay: making protocols comparable

Handshake cost varies a lot between protocols. Trojan (TLS) inherently costs one extra round trip compared with Shadowsocks (no TLS), and Hysteria2 on QUIC is different again.

Comparing raw totals is unfair to some protocols. Turn on:

unified-delay: true

The core measures the handshake twice, subtracts the protocol's inherent cost, and keeps only the comparable part.

The three parameters that matter

- name: "♻️ Auto"
  type: url-test
  proxies: [...]
  url: "http://www.gstatic.com/generate_204"
  interval: 300
  tolerance: 50
  lazy: true
  timeout: 5000
  max-failed-times: 5

interval: how often to test

ValueEffectSuits
60Very responsive switchingWildly variable node quality; but constantly bothers every node
300The balance pointThe everyday recommendation
600–900Very quietStable nodes you would rather leave alone
1800+Essentially staticA dead node goes unnoticed for half an hour

tolerance: the most important and most overlooked

Tolerance in milliseconds. It means: a new node has to be this much faster before switching is worth it.

What tolerance doestolerance 0 (default)switches when 1 ms fastetwo similar nodes flip back and forthconnections keep getting rebuilttolerance 50only switches when 50 mssettles on one nodethe recommended value
"It cuts out for a moment now and then" is usually an unset tolerance

Suggested values:

  • Node latencies mostly under 100 ms → tolerance: 30
  • Mostly 100–300 ms → tolerance: 50
  • Wildly variable → tolerance: 100

lazy: skip testing while idle

lazy: true

With this on, the group skips testing when no traffic is currently going through it.

Benefits: saves power, saves data, avoids pointless connections. Particularly noticeable on laptops and phones.

Cost: when you come back to the group, the first choice may be based on stale data until one test round completes.

Turn it on for everyday use.

timeout and max-failed-times

timeout: 5000            # timeout for one test, in milliseconds
max-failed-times: 5      # consecutive failures before the node is judged dead

Too short a timeout misjudges slow nodes as unusable; too long makes each round drag. 5000 ms is a reasonable value.

Choosing a test URL

The default http://www.gstatic.com/generate_204 has two properties: it returns an empty 204 (almost no data transferred) and it is deployed on a global CDN.

Alternatives:

URLCharacter
http://www.gstatic.com/generate_204Default, lightweight
http://cp.cloudflare.com/generate_204Cloudflare, broad coverage
http://connectivitycheck.gstatic.com/generate_204Same Google family
https://www.youtube.com/generate_204Tests YouTube reachability directly
http://connectivitycheck.platform.hicloud.com/generate_204Reachable where the others are not

Low latency ≠ high speed

This is the point that most needs clearing up.

Latency and bandwidth are different thingsLatencyhow long one round trip affects: how fast pages open, how a game feelsthis is what url-test measuresBandwidthhow much data fits throuaffects: download speed, video qualityurl-test cannot see this at all
A node at 30 ms but only 5 Mbps will still stutter on 4K video

url-test measures latency only. Whether a node can carry heavy traffic can only be found by actually downloading something.

If your main use is video and large files, do not rely entirely on the automatic group — measure a few nodes yourself and pin the winner with a select group.

A useful arrangement: tiered testing

proxy-groups:
  # main group: low tolerance, tested often, chasing responsiveness
  - name: "⚡ Responsive"
    type: url-test
    include-all: true
    filter: "(?i)HK|Hong|JP|Japan"
    url: "http://www.gstatic.com/generate_204"
    interval: 300
    tolerance: 30
    lazy: true

  # heavy traffic: high tolerance, few switches, no interrupted downloads
  - name: "📦 Bulk transfer"
    type: fallback
    include-all: true
    filter: "(?i)IPLC|dedicated|premium"
    interval: 600

  # insurance: anything that works
  - name: "🛡 Backstop"
    type: fallback
    include-all: true
    interval: 900

Why bulk transfer uses fallback rather than url-test: while downloading or watching video, the worst thing is switching nodes mid-stream — the connection breaks and progress is lost. fallback only changes when the current node genuinely dies, which is far steadier.

Testing by hand, properly

The lightning icon in the interface runs one round for the current group. Some caveats:

Things to know about manual testingDuring a test every node is contacted at once, so network use spikes brieflyThe result reflects that single moment; node quality varies by time of dayResults measured at peak evening hours are the most informativeA timeout does not mean the node is broken — the test URL may simply be unreachable over that lineTesting the same node three times and taking the median beats a single measurement

Triggering a test through the API

Useful when scripting:

# test one node
curl "http://127.0.0.1:9090/proxies/HK-01/delay?timeout=5000&url=http%3A%2F%2Fwww.gstatic.com%2Fgenerate_204" \
  -H "Authorization: Bearer your-secret"

# test an entire group
curl "http://127.0.0.1:9090/group/%E2%99%BB%EF%B8%8F%20Auto/delay?timeout=5000&url=..." \
  -H "Authorization: Bearer your-secret"

Group names containing spaces or emoji need URL encoding.

In short

  • It measures a full round trip to a target site through the node, which is not the same as ping
  • Always set tolerance; 50 is a good starting point, and without it the group flip-flops
  • Use 300 for interval; anything much shorter can trip a provider's risk controls
  • Leave lazy on to save power and data
  • Enable unified-delay so nodes on different protocols are comparable
  • Latency says nothing about bandwidth — use fallback rather than url-test for heavy transfers

Related: the five proxy-group types and node naming and automatic grouping.


Related docs