GitHub - haydenjames/cf-colo-watcher: Monitor which Cloudflare colo is serving your requests, with TTFB and cache status, in real time. · GitHub
/" data-turbo-transient="true" />
Skip to content
Search or jump to...
Search code, repositories, users, issues, pull requests...
-->
Search
Clear
Search syntax tips
Provide feedback
--><br>We read every piece of feedback, and take your input very seriously.
Include my email address so I can be contacted
Cancel
Submit feedback
Saved searches
Use saved searches to filter your results more quickly
-->
Name
Query
To see all available qualifiers, see our documentation.
Cancel
Create saved search
Sign in
/;ref_cta:Sign up;ref_loc:header logged out"}"<br>Sign up
Appearance settings
Resetting focus
You signed in with another tab or window. Reload to refresh your session.<br>You signed out in another tab or window. Reload to refresh your session.<br>You switched accounts on another tab or window. Reload to refresh your session.
Dismiss alert
{{ message }}
haydenjames
cf-colo-watcher
Public
Notifications<br>You must be signed in to change notification settings
Fork
Star
main
BranchesTags
Go to file
CodeOpen more actions menu
Folders and files<br>NameNameLast commit message<br>Last commit date<br>Latest commit
History<br>10 Commits<br>10 Commits
.gitignore
.gitignore
LICENSE
LICENSE
README.md
README.md
colowatch.png
colowatch.png
colowatch.sh
colowatch.sh
View all files
Repository files navigation
cf-colo-watcher
A small bash script that shows which Cloudflare colo (datacenter) is serving each request, along with cache status and per-phase timing.
For background on why this exists, see the post on linuxblog.io.
Why
Cloudflare routes each request through one of its edge locations (colos) based on anycast and current network conditions, so the same site can be served from different colos depending on the client's ISP and geography. This script gives you a live view of which colo is serving you, the cache status, and a full per-phase timing breakdown (one line per request), so you can see how performance varies across colos and over time.
Run it, switch VPN/connection mid-run, and watch the colo change. The timing column tells the story.
Example output
Default view (DNS / TCP / TLS handshake times in milliseconds, plus TTFB and total in seconds):
Cloudflare colo watch v1.2.0<br>URL: https://example.com<br>Interval: 5s<br>Started: Mon May 4 14:25:00 EDT 2026<br>Switch your VPN/connection mid-run to compare colos. Ctrl+C to stop.<br>Tip: pass -c or --compact for a narrower table.
TIME | COLO | HTTP | CACHE | DNS | TCP | TLS | TTFB | TOTAL | CF-RAY<br>---------+--------+------+-----------+-------+-------+-------+-----------+-----------+--------------------------<br>14:25:03 | MIA | 200 | HIT | 7 | 55 | 58 | 0.218s | 0.231s | 9f6971eeff87f51d-MIA<br>14:25:09 | MIA | 200 | HIT | 3 | 56 | 61 | 0.241s | 0.255s | 9f69729eda573043-MIA<br>14:25:14 | MIA | 200 | DYNAMIC | 2 | 55 | 59 | 0.387s | 0.402s | 9f6970ea8abbdab9-MIA<br>─── colo changed: MIA → EWR ───<br>14:25:20 | EWR | 200 | HIT | 4 | 24 | 27 | 0.176s | 0.189s | 9f6970ea8abbdab9-EWR<br>14:25:25 | EWR | 200 | DYNAMIC | 2 | 25 | 28 | 0.312s | 0.331s | 9f6970ea8abbdab9-EWR
Summary by colo and cache status:<br>COLO | CACHE | SAMPLES | P50 TTFB | P95 TTFB | MAX TTFB<br>-------+------------+---------+----------+----------+----------<br>MIA | HIT | 2 | 0.218s | 0.241s | 0.241s<br>MIA | DYNAMIC | 1 | 0.387s | 0.387s | 0.387s<br>EWR | HIT | 1 | 0.176s | 0.176s | 0.176s<br>EWR | DYNAMIC | 1 | 0.312s | 0.312s | 0.312s
Compact mode (-c / --compact) drops the DNS / TCP / TLS columns:
TIME | COLO | HTTP | CACHE | TTFB | TOTAL | CF-RAY<br>---------+--------+------+-----------+-----------+-----------+--------------------------<br>14:25:03 | MIA | 200 | HIT | 0.218s | 0.231s | 9f6971eeff87f51d-MIA
Columns:
DNS / TCP / TLS - per-phase handshake times in milliseconds (default view only)
TTFB - client-side time to first byte (cumulative: DNS + TCP + TLS + server response)
TOTAL - full request/response time
CF-RAY - Cloudflare ray ID; the suffix after the dash is the colo
TTFB is color-coded in the live output:
Green: under 500ms
Yellow: 500ms to 1s
Red: over 1s
When the colo changes between requests (e.g. you switched VPN regions), a divider line is printed so the transition is easy to spot in scrollback.
Usage
[interval] [count]">./colowatch.sh [options] url> [interval] [count]
Options:
-c, --compact - narrower table without the DNS/TCP/TLS breakdown
--csv FILE - write all samples as CSV to FILE
--json FILE - write all samples as JSON Lines to FILE
-h, --help - show help
Positional:
url - required, the URL to test
interval - optional, seconds between requests (default 5)
count - optional, stop after N requests (default 0 = run until Ctrl+C)
Examples:
./colowatch.sh https://example.com<br>./colowatch.sh -c https://example.com 3<br>./colowatch.sh --csv runs.csv https://example.com 5 50<br>./colowatch.sh --json runs.jsonl https://example.com 5...