# Satellite Orbital Data & Tracking Scraper (`ninhothedev/satellite-tracking-scraper`) Actor

$0.5/1K 🔥 Satellite scraper! Orbital data for Starlink, GPS, weather & 10k active satellites. No key. JSON, CSV, Excel or API in seconds. Build tracking apps & space analytics ⚡

- **URL**: https://apify.com/ninhothedev/satellite-tracking-scraper.md
- **Developed by:** [ninhothedev](https://apify.com/ninhothedev) (community)
- **Categories:** Developer tools, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.50 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Satellite Orbital Data & Tracking Scraper

Scrape **orbital elements for the entire public satellite catalogue** — Starlink, GPS, Galileo, GLONASS, BeiDou, weather satellites, the geostationary belt and all ~16,000 active objects — straight from [Celestrak](https://celestrak.org), the reference public source for TLE / GP orbital data.

**No API key. No login. No account.** Celestrak's GP endpoint is free and public; this Actor adds the batching, deduplication, throttle recovery and — most importantly — the **derived orbital physics** that the raw feed does not give you.

***

### How is this different from `iss-tracker-scraper`?

Both Actors touch satellite data, but they answer completely different questions:

| | **satellite-tracking-scraper** (this Actor) | [**iss-tracker-scraper**](https://apify.com/ninhothedev/iss-tracker-scraper) |
|---|---|---|
| Scope | **The whole catalogue** — 16,000+ objects, 25 constellations/groups | **One satellite** — the International Space Station |
| Output | **Orbital elements** (the mean orbit at an epoch) | **Live position** (latitude, longitude, altitude, velocity right now) |
| Typical row count | 23 → 16,237 per run | 1 per run |
| Answers | "What orbit is every Starlink satellite in?" | "Where is the ISS at this second?" |
| Data source | Celestrak GP / OMM | Open Notify / WhereTheISS.at |

Use **iss-tracker-scraper** if you want a live dot on a map for the ISS.
Use **this Actor** if you want the underlying orbital mechanics for thousands of satellites at once.

### Important: elements, not live positions

This Actor returns **mean orbital elements at an epoch** (the same data that lives inside a TLE), plus everything you can derive from them with two-body physics: period, semi-major axis, apogee, perigee, mean altitude, orbit class.

It does **not** return an instantaneous latitude/longitude. To turn these elements into a live position you need to propagate them with an **SGP4** library on your side — for example the Python packages [`sgp4`](https://pypi.org/project/sgp4/) or [`skyfield`](https://rhodesmill.org/skyfield/). Every field this Actor outputs (`mean_motion`, `eccentricity`, `inclination_deg`, `raan_deg`, `arg_perigee_deg`, `mean_anomaly_deg`, `bstar`, `epoch`) is exactly what an SGP4 propagator needs as input.

The `epoch_age_days` field tells you how stale an element set is — SGP4 accuracy degrades noticeably beyond a few days.

***

### Features

- **25 verified Celestrak groups** — `active`, `starlink`, `oneweb`, `gps-ops`, `galileo`, `glo-ops`, `beidou`, `weather`, `goes`, `geo`, `stations`, `iridium-NEXT`, `cubesat`, `visual`, `last-30-days`, `science`, `resource`, `planet`, `spire`, `ses`, `intelsat`, `orbcomm`, `globalstar`, `amateur`, `tle-new`.
- **Three modes** — whole groups, specific NORAD catalog numbers, or a name search.
- **Derived orbital physics** — period, semi-major axis, apogee, perigee, mean altitude, orbit class (LEO/MEO/GEO/HEO) and a strict geostationary flag, all computed from the mean elements.
- **Throttle recovery** — Celestrak refreshes each group only every 2 hours and returns HTTP 403 if you re-download too soon. This Actor automatically falls back to Celestrak's supplemental feed or a name search instead of failing your run.
- **Deduplication** by NORAD catalog number across multiple groups.
- **Fresh data** — Celestrak updates the GP catalogue continuously; epochs are typically a few hours old.

### Use cases

- **Satellite tracking apps** — feed a pass-prediction or "what's overhead" app with an always-current element catalogue.
- **Space situational awareness** — monitor altitude decay, orbit classes and congestion in the LEO shells.
- **Constellation analysis** — compare Starlink vs OneWeb vs Kuiper shell altitudes, inclinations and growth over time.
- **Education & research** — teach orbital mechanics with real numbers; build datasets for astronomy and aerospace courses.

### Input

| Field | Type | Default | Description |
|---|---|---|---|
| `mode` | select | `groups` | `groups`, `catalog` or `search` |
| `groups` | array | `["stations"]` | Celestrak group names (see the list above) |
| `noradIds` | array | – | NORAD catalog numbers, e.g. `[25544, 20580]` |
| `nameQuery` | string | – | Case-insensitive name substring, e.g. `STARLINK` |
| `maxItems` | integer | `500` | Max satellites per run (max 10,000) |

#### Example — the ISS and Tiangong

```json
{ "mode": "groups", "groups": ["stations"], "maxItems": 50 }
```

#### Example — the whole Starlink constellation

```json
{ "mode": "groups", "groups": ["starlink"], "maxItems": 10000 }
```

#### Example — specific satellites

```json
{ "mode": "catalog", "noradIds": [25544, 20580, 48274] }
```

#### Example — every NOAA satellite

```json
{ "mode": "search", "nameQuery": "NOAA", "maxItems": 500 }
```

### Output

One dataset item per satellite:

```json
{
  "norad_id": 25544,
  "object_name": "ISS (ZARYA)",
  "object_id": "1998-067A",
  "group": "stations",
  "epoch": "2026-07-28T03:39:38.218752+00:00",
  "epoch_age_days": 0.61,
  "classification": "U",
  "mean_motion": 15.49220842,
  "period_minutes": 92.95,
  "semi_major_axis_km": 6797.141,
  "apogee_km": 423.825,
  "perigee_km": 414.183,
  "mean_altitude_km": 419.004,
  "eccentricity": 0.0007093,
  "inclination_deg": 51.632,
  "raan_deg": 97.3682,
  "arg_perigee_deg": 345.612,
  "mean_anomaly_deg": 14.4666,
  "bstar": 0.00020282,
  "rev_at_epoch": 57810,
  "element_set_no": 999,
  "orbit_class": "LEO",
  "is_geostationary": false,
  "launch_year": 1998,
  "source": "celestrak",
  "scraped_at": "2026-07-28T18:11:45.045430+00:00"
}
```

#### The derived fields, explained

| Field | Formula |
|---|---|
| `period_minutes` | `1440 / MEAN_MOTION` (mean motion is revolutions per day) |
| `semi_major_axis_km` | Kepler III: `a = (mu / n^2)^(1/3)` with `mu = 398600.4418 km^3/s^2` and `n = MEAN_MOTION * 2*pi / 86400` rad/s |
| `apogee_km` | `a * (1 + e) - 6378.137` (altitude above the WGS-84 equatorial radius) |
| `perigee_km` | `a * (1 - e) - 6378.137` |
| `mean_altitude_km` | `(apogee + perigee) / 2`, identical to `a - 6378.137` |
| `orbit_class` | `HEO` if `e > 0.25`; else `LEO` if apogee < 2000 km; else `GEO` if the mean altitude is within ±500 km of 35,786 km; else `MEO` up to the GEO belt; else `HEO` |
| `is_geostationary` | period within ±10 min of one sidereal day (1436 min) **and** inclination < 1° |
| `launch_year` | first four characters of the COSPAR designator (`1998-067A` → 1998) |

**Sanity check against reality (live run, 2026-07-28):**

| Satellite | Period | Altitude | Expected |
|---|---|---|---|
| ISS (ZARYA) | 92.95 min | 419.0 km | ~93 min, ~420 km ✅ |
| Hubble (HST) | 94.05 min | 472.3 km | ~95 min, ~475 km ✅ |
| GPS BIIR-5 | 718.0 min | ~20,180 km | ~12 h, ~20,200 km ✅ |
| TDRS 3 (GEO) | 1436.0 min | ~35,785 km | 1436 min, 35,786 km ✅ |
| Molniya 2-9 | e = 0.671 | 1,276 / 32,441 km | classic Molniya HEO ✅ |

### Pricing

Roughly **$0.5 per 1,000 satellites**. A `stations` run (23 satellites) costs fractions of a cent; the full `active` catalogue at 10,000 items costs about $5. Celestrak itself is free — you only pay Apify compute.

### Notes & limits

- Celestrak refreshes each group **every 2 hours** and returns HTTP 403 (`"GP data has not updated since your last successful download"`) if the same IP requests it again inside that window. The Actor recovers automatically via the supplemental feed or a name search, so schedule runs at most every 2 hours per group.
- `noaa` and `gps` are **not** valid Celestrak group names — use `weather` and `gps-ops`.
- The `active` group holds ~16,200 objects; `maxItems` caps at 10,000 per run. Split by group for full coverage.
- Data is public and courtesy of Celestrak / the US Space Force space-track catalogue. Please respect Celestrak's terms of use.

### Related Actors

- [ISS Tracker Scraper](https://apify.com/ninhothedev/iss-tracker-scraper) — live ISS position, one satellite, real-time
- [Launch Library Scraper](https://apify.com/ninhothedev/launch-library-scraper) — upcoming and past rocket launches
- [Spaceflight News Scraper](https://apify.com/ninhothedev/spaceflight-news-scraper) — space news, articles and blogs
- [ADS-B Flights Scraper](https://apify.com/ninhothedev/adsb-flights-scraper) — live aircraft positions

***

*Keywords: satellite scraper, TLE scraper, Celestrak API, orbital elements, NORAD catalog, Starlink tracker, GPS satellites, satellite tracking API, two-line elements, SGP4, space situational awareness, geostationary satellites, LEO constellation data.*

# Actor input Schema

## `mode` (type: `string`):

How to select satellites. 'groups' = download whole Celestrak groups (constellations / categories). 'catalog' = fetch specific satellites by NORAD catalog number. 'search' = find satellites whose name contains a text query.

## `groups` (type: `array`):

Celestrak GROUP names to download (used when mode = groups). Verified working groups and their approximate sizes: active (~16200 - the full active catalogue), stations (23 - ISS, Tiangong & modules), starlink (~10900), oneweb (651), gps-ops (32), galileo (32), glo-ops (28 - GLONASS), beidou (53), weather (74), goes (6), resource (167), science (49), geo (569 - geostationary belt), iridium-NEXT (80), cubesat (85), last-30-days (~400 recent launches), visual (157 - brightest, naked-eye), planet (106), spire (74), ses (68), intelsat (126), orbcomm (14), globalstar (28), amateur (92), tle-new (~235). Note: 'noaa' and 'gps' are NOT valid Celestrak group names - use 'weather' and 'gps-ops'.

## `noradIds` (type: `array`):

NORAD catalog IDs to fetch one by one (used when mode = catalog). Examples: 25544 = ISS (ZARYA), 20580 = Hubble Space Telescope, 48274 = Tiangong (CSS).

## `nameQuery` (type: `string`):

Case-insensitive substring matched against the satellite name (used when mode = search). Example: 'STARLINK' returns ~10800 objects, 'NOAA' returns ~430, 'HST' returns the Hubble Space Telescope.

## `maxItems` (type: `integer`):

Maximum number of satellites to push to the dataset. Increase this when scraping large groups such as 'active' or 'starlink'.

## Actor input object example

```json
{
  "mode": "groups",
  "groups": [
    "stations"
  ],
  "noradIds": [
    "25544",
    "20580"
  ],
  "nameQuery": "NOAA",
  "maxItems": 500
}
```

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "groups": [
        "stations"
    ],
    "noradIds": [
        "25544",
        "20580"
    ],
    "nameQuery": "NOAA"
};

// Run the Actor and wait for it to finish
const run = await client.actor("ninhothedev/satellite-tracking-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "groups": ["stations"],
    "noradIds": [
        "25544",
        "20580",
    ],
    "nameQuery": "NOAA",
}

# Run the Actor and wait for it to finish
run = client.actor("ninhothedev/satellite-tracking-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "groups": [
    "stations"
  ],
  "noradIds": [
    "25544",
    "20580"
  ],
  "nameQuery": "NOAA"
}' |
apify call ninhothedev/satellite-tracking-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=ninhothedev/satellite-tracking-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/a0kuIix79XjC3T5P0/builds/yN2XAJi36irCIl4Cw/openapi.json
