Skip to content

Starlink

Client for Starlink's public Modified ITC ephemerides.

StarlinkClient

StarlinkClient

StarlinkClient(base_url: str = None, cache_max_age: float = None, max_retries: int = None, rate_limit: RateLimitConfig = None)

Client for Starlink's public Modified ITC ephemerides.

Requests are blocking, rate limited (1000 per minute and 30000 per hour by default), retried on transient failures, and honour BRAHE_NETWORK_MODE. The manifest is cached under $BRAHE_CACHE/starlink/MANIFEST.txt for the default base URL, or under $BRAHE_CACHE/starlink/mirrors/<label> for any other base URL so clients pointed at different mirrors never share a cache, and re-fetched with a conditional GET once it is older than cache_max_age; when the listing changes, the prior copy is kept as MANIFEST.previous.txt so the caller can ask which satellites moved. The cache directory is not coordinated across processes or across clients sharing it; run one bulk download at a time.

Parameters:

Name Type Description Default
base_url str

Custom base URL for testing or a mirror.

None
cache_max_age float

Seconds a cached manifest is served without a refresh. Default: 3600.0.

None
max_retries int

Extra attempts after the first on transient failures. Default: 3.

None
rate_limit RateLimitConfig

Custom per-minute and per-hour request caps.

None
Example
1
2
3
4
5
import brahe as bh

client = bh.StarlinkClient()
manifest = client.get_manifest()
traj = client.get_trajectory(manifest[0].norad_cat_id)

Initialize instance.

base_url property

base_url: str

Base URL without a trailing slash.

Returns:

Name Type Description
str str

The directory URL.

cache_max_age property

cache_max_age: float

Manifest cache age in seconds.

Returns:

Name Type Description
float float

Seconds.

cache_dir method descriptor

cache_dir() -> str

Directory holding the cached manifest and ephemeris files.

For the default base URL this is $BRAHE_CACHE/starlink. For any other base URL it is $BRAHE_CACHE/starlink/mirrors/<label>, where <label> is derived from the base URL's host so that clients pointed at different mirrors do not read or write each other's cached manifest and ephemeris files.

Returns:

Name Type Description
str str

The cache directory, created if missing.

Raises:

Type Description
BraheError

If the cache directory cannot be created.

cached_files method descriptor

cached_files() -> list[str]

Cached ephemeris files, sorted by name.

Returns:

Type Description
list[str]

list[str]: Files whose names are Space-Track ephemeris names.

Raises:

Type Description
BraheError

If the cache directory cannot be read.

cached_manifest method descriptor

cached_manifest() -> Any

The cached manifest, whatever its age, without touching the network.

Returns:

Type Description
Any

StarlinkManifest | None: The cached listing, or None if nothing is cached.

Raises:

Type Description
BraheError

If the cached file cannot be read or parsed.

download_all method descriptor

download_all(concurrency: int = 8) -> list[str]

Downloads every file the manifest lists that is not already cached, using up to concurrency threads that share the rate limiter.

The full manifest is about 11,100 files and about 22 GB, so a first run against the public mirror is a long transfer. Stops at the first failure and returns it. Files already cached are not re-fetched. No files are pruned; superseded files for a satellite whose file is downloaded are still evicted. Call prune_cache to remove files the manifest no longer lists.

Parameters:

Name Type Description Default
concurrency int

Worker threads, at least 1. Default: 8.

8

Returns:

Type Description
list[str]

list[str]: Cache path of one file per listed NORAD ID, in manifest order.

Raises:

Type Description
BraheError

The first failure, or concurrency == 0.

download_ephemeris method descriptor

download_ephemeris(norad_cat_id: int) -> str

Downloads a satellite's current ephemeris file into the cache.

The manifest names one file per satellite; if that file is already cached no request is made. After a download every other cached file for the same NORAD ID is deleted.

Parameters:

Name Type Description Default
norad_cat_id int

NORAD catalog number.

required

Returns:

Name Type Description
str str

Path of the cached file.

Raises:

Type Description
BraheError

If the ID is not listed, the download fails, or the body is not a valid ITC file.

get_ephemeris method descriptor

get_ephemeris(norad_cat_id: int) -> ITC

Downloads (if needed) and parses a satellite's current ephemeris.

Parameters:

Name Type Description Default
norad_cat_id int

NORAD catalog number.

required

Returns:

Name Type Description
ITC ITC

The parsed message in SI units.

Raises:

Type Description
BraheError

See download_ephemeris.

get_manifest method descriptor

get_manifest() -> StarlinkManifest

Returns the manifest, serving the cached copy while it is younger than cache_max_age and refreshing it with a conditional GET otherwise.

BRAHE_NETWORK_MODE applies as for the other clients: offline serves a cached manifest of any age, offline-strict serves only a fresh one and rejects a stale or missing one, and a refresh that fails is an error rather than a silent fall back to the stale copy.

Returns:

Name Type Description
StarlinkManifest StarlinkManifest

The current listing.

Raises:

Type Description
BraheError

If the cached copy cannot be served under the current mode and no refresh succeeds.

Example
1
2
3
4
import brahe as bh

manifest = bh.StarlinkClient().get_manifest()
assert len(manifest) > 0

get_trajectory method descriptor

get_trajectory(norad_cat_id: int, covariance_variant: OrbitRelativeFrameVariant = None) -> OrbitTrajectory

Downloads (if needed) a satellite's ephemeris as an OrbitTrajectory in the file's state frame with covariance rotated from RTN using the block-diagonal (inertial) convention by default.

Parameters:

Name Type Description Default
norad_cat_id int

NORAD catalog number.

required
covariance_variant OrbitRelativeFrameVariant

INERTIAL (default, block-diagonal) or ROTATING RTN rotation.

None

Returns:

Name Type Description
OrbitTrajectory OrbitTrajectory

Six-dimensional Cartesian trajectory.

Raises:

Type Description
BraheError

See download_ephemeris.

Example
1
2
3
import brahe as bh

traj = bh.StarlinkClient().get_trajectory(100001)

get_trajectory_with_covariance_variant method descriptor

get_trajectory_with_covariance_variant(norad_cat_id: int, variant: OrbitRelativeFrameVariant) -> OrbitTrajectory

Like get_trajectory with an explicit RTN covariance convention.

Parameters:

Name Type Description Default
norad_cat_id int

NORAD catalog number.

required
variant OrbitRelativeFrameVariant

INERTIAL (block-diagonal) or ROTATING RTN rotation.

required

Returns:

Name Type Description
OrbitTrajectory OrbitTrajectory

Six-dimensional Cartesian trajectory.

Raises:

Type Description
BraheError

See download_ephemeris.

previous_manifest method descriptor

previous_manifest() -> Any

The listing that was current before the last change, for changed_since.

Returns:

Type Description
Any

StarlinkManifest | None: The previous listing, or None if the manifest has never changed on this machine.

Raises:

Type Description
BraheError

If the file cannot be read or parsed.

prune_cache method descriptor

prune_cache() -> int

Deletes cached ephemeris files the current manifest no longer lists.

Returns:

Name Type Description
int int

Number of files deleted.

Raises:

Type Description
BraheError

If the manifest cannot be obtained or a file cannot be removed.

refresh_manifest method descriptor

refresh_manifest() -> StarlinkManifest

Fetches the manifest from the server regardless of cache age.

Sends the cached ETag and Last-Modified as conditional headers; a 304 answer touches the cached file so it is fresh again. A changed listing moves the old copy to MANIFEST.previous.txt before the new one is written.

Returns:

Name Type Description
StarlinkManifest StarlinkManifest

The listing now on disk.

Raises:

Type Description
BraheError

On network failure, offline mode, or a malformed listing.

save_all method descriptor

save_all(destination: str, concurrency: int = 8, keep_cached: bool = False) -> list[str]

Runs download_all and writes every file into destination.

With keep_cached false each cached file is moved, so destination holds every ephemeris and the cache holds none and a later download_ephemeris or download_all call downloads them again; with keep_cached true each is copied and the cached copies stay.

Parameters:

Name Type Description Default
destination str

Directory, created if missing, outside the cache directory.

required
concurrency int

Worker threads, at least 1. Default: 8.

8
keep_cached bool

Copy instead of move, leaving the cached files in place. Defaults to False.

False

Returns:

Type Description
list[str]

list[str]: Paths written, in manifest order.

Raises:

Type Description
BraheError

If destination is an existing file or resolves inside the cache directory, both checked before anything is downloaded, or on download or filesystem failure.

save_ephemeris method descriptor

save_ephemeris(norad_cat_id: int, destination: str, keep_cached: bool = False) -> str

Downloads (if needed) a satellite's ephemeris and writes it to destination.

An existing directory, or a path whose last component has no extension, is treated as a directory (created if missing) and the original file name is kept; a path with an extension is the file name. With keep_cached false the cached file is moved, so destination becomes the only copy and a later download_ephemeris call downloads it again; with keep_cached true it is copied and the cached copy stays.

Parameters:

Name Type Description Default
norad_cat_id int

NORAD catalog number.

required
destination str

Directory or file path, outside the cache directory.

required
keep_cached bool

Copy instead of move, leaving the cached file in place. Defaults to False.

False

Returns:

Name Type Description
str str

Path written.

Raises:

Type Description
BraheError

If destination resolves inside the cache directory, which is checked before anything is downloaded, or on download or filesystem failure.

StarlinkManifest

StarlinkManifest

StarlinkManifest()

Starlink's manifest as a table of entries.

Example
1
2
3
4
5
6
7
import brahe as bh

client = bh.StarlinkClient()
manifest = client.get_manifest()
print(len(manifest))
for entry in manifest:
    print(entry.norad_cat_id)

Initialize instance.

last_modified property

last_modified: Any

Last-Modified reported by the server for this listing, when known.

Returns:

Type Description
Any

Epoch | None: The listing's last-modified time.

retrieved property

retrieved: Epoch

When this copy of the listing was retrieved or cached.

Returns:

Name Type Description
Epoch Epoch

The retrieval time.

changed_since method descriptor

changed_since(other: StarlinkManifest) -> list[StarlinkManifestEntry]

Entries whose file name differs from, or is absent in, other.

Parameters:

Name Type Description Default
other StarlinkManifest

An earlier manifest to compare against.

required

Returns:

Type Description
list[StarlinkManifestEntry]

list[StarlinkManifestEntry]: New or updated entries, in manifest order.

entries method descriptor

All entries in manifest order.

Returns:

Type Description
list[StarlinkManifestEntry]

list[StarlinkManifestEntry]: The entries.

find_by_norad_id method descriptor

find_by_norad_id(norad_cat_id: int) -> Any

Entry for a NORAD catalog number.

Parameters:

Name Type Description Default
norad_cat_id int

Catalog number.

required

Returns:

Type Description
Any

StarlinkManifestEntry | None: The entry, or None if absent.

find_by_object_name method descriptor

find_by_object_name(object_name: str) -> Any

Entry whose object name matches exactly.

Parameters:

Name Type Description Default
object_name str

Common name, case-sensitive.

required

Returns:

Type Description
Any

StarlinkManifestEntry | None: The entry, or None if absent.

is_empty method descriptor

is_empty() -> bool

Whether the manifest has no entries.

Returns:

Name Type Description
bool bool

True when empty.

parse staticmethod

parse(text: str, reference: Epoch, last_modified: Epoch = None) -> StarlinkManifest

Parses manifest text; blank lines are skipped and any other line must be a Space-Track file name.

Parameters:

Name Type Description Default
text str

Manifest contents.

required
reference Epoch

Epoch used to place start dates in a year and to validate GPS-second metadata.

required
last_modified Epoch

Server Last-Modified for the listing, if known.

None

Returns:

Name Type Description
StarlinkManifest StarlinkManifest

The parsed table.

Raises:

Type Description
BraheError

If any non-blank line is not a compliant file name.

Example
1
2
3
4
5
6
7
8
import brahe as bh

reference = bh.Epoch(2026, 9, 11, 6, 0, 0.0, 0.0, time_system=bh.UTC)
manifest = bh.StarlinkManifest.parse(
    "MEME_100001_STARLINK-38128_2540142_Operational_1473385380_UNCLASSIFIED.txt\n",
    reference,
)
assert manifest.entries()[0].norad_cat_id == 100001

to_dataframe method descriptor

to_dataframe() -> DataFrame

The manifest as a polars DataFrame.

Columns: norad_cat_id (UInt32), object_name (String), category (String), ephemeris_start (Datetime, milliseconds), ephemeris_stop (Datetime, milliseconds, null when the name carries no stop), file_name (String).

Returns:

Type Description
DataFrame

polars.DataFrame: One row per entry.

Raises:

Type Description
BraheError

If polars is not installed or the DataFrame cannot be built.

Example
1
2
3
4
5
import brahe as bh

client = bh.StarlinkClient()
df = client.get_manifest().to_dataframe()
print(df.head())

StarlinkManifestEntry

StarlinkManifestEntry

StarlinkManifestEntry()

One line of the Starlink manifest with the epochs decoded from the name.

ephemeris_start has minute resolution (the file name carries only DDDHHMM); its year comes from ephemeris_stop when Starlink's metadata field decodes as GPS seconds, otherwise from the manifest's reference epoch.

Example
1
2
3
4
5
6
7
8
9
import brahe as bh

manifest = bh.StarlinkManifest.parse(
    "MEME_100001_STARLINK-38128_2540142_Operational_1473385380_UNCLASSIFIED.txt\n",
    bh.Epoch(2026, 9, 11, 6, 0, 0.0, 0.0, time_system=bh.UTC),
)
entry = manifest.find_by_norad_id(100001)
assert entry.object_name == "STARLINK-38128"
assert entry.ephemeris_stop is not None

Initialize instance.

category property

Operational or Special.

Returns:

Name Type Description
SpaceTrackEphemerisFileCategory SpaceTrackEphemerisFileCategory

The category.

ephemeris_start property

ephemeris_start: Epoch

Ephemeris start, UTC, minute resolution.

Returns:

Name Type Description
Epoch Epoch

The start epoch.

ephemeris_stop property

ephemeris_stop: Any

Ephemeris stop decoded from the metadata field, when present.

Returns:

Type Description
Any

Epoch | None: The stop epoch, or None when the metadata field does not decode as GPS seconds.

file_name property

Parsed view of the listing's file name.

Rendering it back to a string normalises the catalog number and the category spelling, so requests, cache files and prune keys use file_name_string(), which returns the listing's exact text.

Returns:

Name Type Description
SpaceTrackEphemerisFileName SpaceTrackEphemerisFileName

The manifest line's file name, field by field.

norad_cat_id property

norad_cat_id: int

NORAD catalog number.

Returns:

Name Type Description
int int

Catalog number.

object_name property

object_name: str

Common name, for example STARLINK-38128.

Returns:

Name Type Description
str str

Object name.

file_name_string method descriptor

file_name_string() -> str

The file name exactly as listed in the manifest, which is what the mirror serves and what the cache stores.

Returns:

Name Type Description
str str

The listing's file name with extension.


See Also