CelesTrak is a public source for satellite Two-Line Element (TLE) data, maintained by T.S. Kelso since 1985. It provides free, frequently updated orbital element sets for thousands of satellites, making it a useful resource for satellite tracking, orbit determination, and space situational awareness.
Respectful Usage
CelesTrak is freely available for public use, but users should be respectful of the service. Avoid excessive automated requests, and design your calls to take advantage of caching to minimize repeated queries. For large-scale or commercial applications, consider setting up a single download and local caching strategy to disribute ephemeris data internally.
CelesTrak is a public data source for satellite orbital elements, maintained by Dr. T.S. Kelso since 1985. It provides free, frequently updated Two-Line Element (TLE) data for thousands of satellites, making it an essential resource for satellite tracking, orbit determination, and space situational awareness.
Two-Line Elements (TLEs) are a compact text format for encoding satellite orbital parameters compatible with the SGP4/SDP4 propagation models. For more information on TLEs, see the Two-Line Elements documentation.
To minimize load on CelesTrak's servers and improve performance, brahe implements a 6-hour cache for downloaded data:
Cache key: Satellite group name (e.g., "starlink", "stations")
Cache duration: 6 hours (default, configurable)
Cache location: System temp directory
When you request a satellite by ID or name with a group hint, brahe checks if that group was recently downloaded and uses cached data if available. This is much faster and more respectful than making individual requests.
Customizing Cache
See the Caching documentation for details on customizing cache behavior.
importbraheasbh# Initialize EOP databh.initialize_eop()# Download TLE data for the Starlink group# This fetches all Starlink satellites in one requesttles=bh.datasets.celestrak.get_tles("starlink")print(f"Downloaded {len(tles)} Starlink TLEs")# Each TLE is a tuple of (name, line1, line2)name,line1,line2=tles[0]print("\nFirst TLE:")print(f" Name: {name}")print(f" Line 1: {line1}")print(f" Line 2: {line2}")# Expected output:# Downloaded 8647 Starlink TLEs# First TLE:# Name: STARLINK-1008# Line 1: 1 44714U 19074B 25306.45157821 .00002551 00000+0 19011-3 0 9997# Line 2: 2 44714 53.0544 37.8105 0001365 79.2826 280.8316 15.06391189329573
usebraheasbh;fnmain(){bh::initialize_eop().unwrap();// Download TLE data for the Starlink group// This fetches all Starlink satellites in one requestlettles=bh::datasets::celestrak::get_tles("starlink").unwrap();println!("Downloaded {} Starlink TLEs",tles.len());// Each TLE is a tuple of (name, line1, line2)let(name,line1,line2)=&tles[0];println!("\nFirst TLE:");println!(" Name: {}",name);println!(" Line 1: {}",line1);println!(" Line 2: {}",line2);// Expected output:// Downloaded 8647 Starlink TLEs// First TLE:// Name: STARLINK-1008// Line 1: 1 44714U 19074B 25306.45157821 .00002551 00000+0 19011-3 0 9997// Line 2: 2 44714 53.0544 37.8105 0001365 79.2826 280.8316 15.06391189329573}
importbraheasbh# Initialize EOP databh.initialize_eop()# Get ISS TLE by NORAD ID# The group hint ("stations") allows brahe to check cached data firstname,line1,line2=bh.datasets.celestrak.get_tle_by_id(25544,"stations")# Parse TLE data to get epoch and orbital elementsepoch,oe=bh.keplerian_elements_from_tle(line1,line2)print("ISS TLE:")print(f" Name: {name}")print(f" Epoch: {epoch}")print(f" Inclination: {oe[2]:.2f}°")print(f" RAAN: {oe[3]:.2f}°")print(f" Eccentricity: {oe[1]:.6f}")# Expected output:# ISS TLE:# Name: ISS (ZARYA)# Epoch: 2025-11-02 10:09:34.283 UTC# Inclination: 51.63°# RAAN: 342.07°# Eccentricity: 0.000497
usebraheasbh;fnmain(){bh::initialize_eop().unwrap();// Get ISS TLE by NORAD ID// The group hint ("stations") allows brahe to check cached data firstlet(name,line1,line2)=bh::datasets::celestrak::get_tle_by_id(25544,Some("stations")).unwrap();// Parse TLE data to get epoch and orbital elementslet(epoch,oe)=bh::keplerian_elements_from_tle(&line1,&line2).unwrap();println!("ISS TLE:");println!(" Name: {}",name);println!(" Epoch: {}",epoch);println!(" Inclination: {:.2}°",oe[2]);println!(" RAAN: {:.2}°",oe[3]);println!(" Eccentricity: {:.6}",oe[1]);// Expected output:// ISS TLE:// Name: ISS (ZARYA)// Epoch: 2025-11-02 10:09:34.283 UTC// Inclination: 51.63°// RAAN: 342.07°// Eccentricity: 0.000497}
Cache-Efficient Pattern
The most efficient workflow is:
Download the group once: get_tles("stations")
Query specific satellites with the group hint: get_tle_by_id(25544, "stations")
This pattern uses cached data and avoids redundant downloads.
importbraheasbh# Initialize EOP databh.initialize_eop()# Get ISS as a propagator with 60-second step size# The group hint ("stations") uses cached data for efficiencyiss_prop=bh.datasets.celestrak.get_tle_by_id_as_propagator(25544,60.0,"stations")print(f"Created propagator: {iss_prop.get_name()}")print(f"Epoch: {iss_prop.epoch}")# Propagate forward 1 orbit period (~93 minutes for ISS)iss_prop.propagate_to(iss_prop.epoch+bh.orbital_period(iss_prop.semi_major_axis))state=iss_prop.current_state()print("\nState after 1 orbit:")print(f" Position: [{state[0]:.1f}, {state[1]:.1f}, {state[2]:.1f}] m")print(f" Velocity: [{state[3]:.1f}, {state[4]:.1f}, {state[5]:.1f}] m/s")# Expected output:# Created propagator: ISS (ZARYA)# Epoch: 2025-11-02 10:09:34.283 UTC# State after 1 orbit:# Position: [6451630.2, -2126316.1, 34427.2] m# Velocity: [2019.6, 5281.4, 6006.2] m/s
usebraheasbh;usebh::traits::SStatePropagator;usebh::utils::Identifiable;fnmain(){bh::initialize_eop().unwrap();// Get ISS as a propagator with 60-second step size// The group hint ("stations") uses cached data for efficiencyletmutiss_prop=bh::datasets::celestrak::get_tle_by_id_as_propagator(25544,Some("stations"),60.0,).unwrap();println!("Created propagator: {}",iss_prop.get_name().unwrap_or("Unknown"));println!("Epoch: {}",iss_prop.epoch);// Propagate forward 1 orbit period (~93 minutes for ISS)iss_prop.propagate_to(iss_prop.epoch+bh::orbital_period(iss_prop.semi_major_axis()));letstate=iss_prop.current_state();println!("\nState after 1 orbit:");println!(" Position: [{:.1}, {:.1}, {:.1}] m",state[0],state[1],state[2]);println!(" Velocity: [{:.1}, {:.1}, {:.1}] m/s",state[3],state[4],state[5]);// Expected output:// Created propagator: ISS (ZARYA)// Epoch: 2025-11-02 10:09:34.283 UTC// State after 1 orbit:// Position: [6451630.2, -2126316.1, 34427.2] m// Velocity: [2019.6, 5281.4, 6006.2] m/s}
importbraheasbh# Initialize EOP databh.initialize_eop()# Search by name (checks common groups automatically)iss_name,iss_line1,iss_line2=bh.datasets.celestrak.get_tle_by_name("ISS")print("Search without group hint:")print(f" Found: {iss_name}")print(f" Line 1: {iss_line1}")print(f" Line 2: {iss_line2}")# Or provide a group hint for faster lookupiss_name2,iss_line2_1,iss_line2_2=bh.datasets.celestrak.get_tle_by_name("ISS","stations")print("\nSearch with group hint:")print(f" Found: {iss_name2}")print(f" Line 1: {iss_line2_1}")print(f" Line 2: {iss_line2_2}")# Expected output:# Search without group hint:# Found: ISS (ZARYA)# Line 1: 1 25544U 98067A 25306.42331346 .00010070 00000+0 18610-3 0 9998# Line 2: 2 25544 51.6344 342.0717 0004969 8.9436 351.1640 15.49700017536601# Search with group hint:# Found: ISS (ZARYA)# Line 1: 1 25544U 98067A 25306.42331346 .00010070 00000+0 18610-3 0 9998# Line 2: 2 25544 51.6344 342.0717 0004969 8.9436 351.1640 15.49700017536601
usebraheasbh;fnmain(){bh::initialize_eop().unwrap();// Search by name (checks common groups automatically)let(iss_name,iss_line1,iss_line2)=bh::datasets::celestrak::get_tle_by_name("ISS",None).unwrap();println!("Search without group hint:");println!(" Found: {}",iss_name);println!(" Line 1: {}",&iss_line1);println!(" Line 2: {}",&iss_line2);// Or provide a group hint for faster lookuplet(iss_name2,iss_line2_1,iss_line2_2)=bh::datasets::celestrak::get_tle_by_name("ISS",Some("stations")).unwrap();println!("\nSearch with group hint:");println!(" Found: {}",iss_name2);println!(" Line 1: {}",&iss_line2_1);println!(" Line 2: {}",&iss_line2_2);// Expected output:// Search without group hint:// Found: ISS (ZARYA)// Line 1: 1 25544U 98067A 25306.42331346 .00010070 00000+0 18610-3 0 9998// Line 2: 2 25544 51.6344 342.0717 0004969 8.9436 351.1640 15.49700017536601// Search with group hint:// Found: ISS (ZARYA)// Line 1: 1 25544U 98067A 25306.42331346 .00010070 00000+0 18610-3 0 9998// Line 2: 2 25544 51.6344 342.0717 0004969 8.9436 351.1640 15.49700017536601}
Name Matching
Name searches are case-insensitive and support partial matches. If multiple satellites match, the function returns the first match.
CelesTrak organizes satellites into logical groups accessible via simple names. These groups are updated as active constellations evolve. It is best to download TLEs by group name rather than ID to minimize the number of distinct requests.