Starlink monitoring and hacking notes

Some collected information and what I’m doing about monitoring Starlink / Dishy’s performance. Note most of this stuff works with just Dishy, not the Starlink-supplied router.

Some facts

  • Dishy listens at on ports 22, 80, and 9200. ssh, http, and gRPC. It also uses port 9201 for a different flavor of gPRC HTTP (for Android?)
  • The mobile app works by fetching web pages and/or gRPC data from Dishy.
  • Starlink’s router does gRPC on port 9000 and is the preferred source for the mobile app. It implements the ping interface, the thing that tells you your Fortnite lag.
  • You can view the stats direct from Dishy in any browser at
    Note you have to open the browser window to max width; it’s formatting for the screen size, not window size.
  • Another Dishy URL:



  • pinginfoview: nice lightweight Windows tool for testing if the connection is down
  • Starlink gRPC tools: Python code for reading gRPC stats off Dishy
    This seems to give very complete data from Dishy, including the history of dropped packets
  • dishyworld: a working dashboard based on Prometheus and Grafana.
    Has ambitious goals of collecting data from many users.
  • starlink-cli: Go code for getting Starlink data. I think it’s the base for dishyworld?
    This seems to give less data than the Python library above, at least by default
  • Better than Nothing Web Interface: a PHP dashboard
  • Better than Nothing stats: a mockup of a planned Javascript dashboard, successor to above
  • Obstruction view. Takes the debug info from Dishy about obstructions and draws it. I know the mobile app can do this but I can’t figure out how to do it again!
My obstructions

Starlink gRPC tools

This Python library seems to give more useful output than the other command line tool I could find so I’m pursuing it.
The full list of commands:
status, obstruction_detail, alert_detail, usage, bulk_history
ping_drop, ping_run_length, ping_latency, ping_loaded_latency

Be sure to read the code / docs for detailed notes on what all the fields mean. There’s some surprisingly sophisticated analysis going on when it’s looking at data samples to, say, characterize the latency of the last 5 minutes.

Some useful examples:

$ python -v status
id:                    ut01000000-00000000-000353f7
hardware_version:      rev1_pre_production
software_version:      848e54d2-015a-49cb-a814-34d7c5fc7e1a.release
state:                 CONNECTED
uptime:                130100
snr:                   9.0
seconds_to_first_nonempty_slot: 0.0
pop_ping_drop_rate:    0.0625
downlink_throughput_bps: 9143.5830078125
uplink_throughput_bps: 4387.2421875
pop_ping_latency_ms:   29.5
Alerts bit field:      0
fraction_obstructed:   0.006759106181561947
currently_obstructed:  False
seconds_obstructed:    266.0

# Dropped pings over the last hour
$ python -v ping_drop
current counter:       130202
All samples:           43200
Valid samples:         43200
Parsed samples:        3600
Sample counter:        130202
Total ping drop:       48.06441651657224
Count of drop == 1:    26
Obstructed:            23
Obstructed ping drop:  19.7899159938097
Obstructed drop == 1:  19
Unscheduled:           0
Unscheduled ping drop: 0.0
Unscheduled drop == 1: 0

# Bandwidth used for last 5 minutes
$ python -v usage -s 300
current counter:       131151
All samples:           43200
Valid samples:         43200
Parsed samples:        300
Sample counter:        131151
Bytes downloaded:      1327843
Bytes uploaded:        813427

Some of the ping_drop statistics are confusing; this github issue has notes on what they mean. “Unscheduled drop == 1” seems to exactly correlate to the stats UI’s “No Satellites” display, and “Obstructed drop == 1” is the Obstructed count. It’s less clear to me how to reconstruct the beta downtime statistics.