# NASA Asteroid Close Approaches, NEO Lookup & Impact Risk (`yadroo/nasa-asteroid-approaches`) Actor

Asteroid and comet close approaches to Earth or another planet as rows: date in UTC, distance in lunar distances and km, speed, magnitude and estimated size. Plus object lookup by designation with orbit and physical data, the Sentry impact-risk table and recorded fireballs. Keyless NASA JPL data.

- **URL**: https://apify.com/yadroo/nasa-asteroid-approaches.md
- **Developed by:** [Samat Makatov](https://apify.com/yadroo) (community)
- **Categories:** Developer tools, News, Other
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.40 / 1,000 asteroid data rows

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## NASA Asteroid Close Approaches, NEO Lookup & Impact Risk

Asteroid and comet close approaches to Earth or another planet as rows: date in UTC, distance in lunar distances and
km, speed, magnitude and estimated size. Plus object lookup by designation with orbit and physical data, the Sentry
impact-risk table and recorded fireballs. Keyless NASA JPL data.

Four questions, one actor. **Which objects pass a planet, when and how close** (close-approach table). **What is known
about one object** — orbit, size, albedo, rotation, discovery (small-body database). **Which objects carry a computed
chance of hitting Earth**, with the probability, the Palermo and Torino values and the years watched (Sentry table).
**Which bright meteors actually entered the atmosphere**, where and with how much energy (fireball record). The data
comes from NASA JPL's Solar System Dynamics service, is US government public domain, and needs no key, no login, no
proxy and no browser — a run is one to four small JSON requests, sent one at a time. Made by Yadroo.

### Use cases

- **"What passes Earth this month" for a dashboard or newsletter** — `dateFrom: "now"`, `dateTo: "+30"`,
  `maxDistanceLd: 10`: every near-Earth object inside ten lunar distances in date order, with the distance already
  converted to kilometres so nothing has to be recomputed downstream.
- **A size-filtered list for an article or a press desk** — `maxAbsoluteMagnitude: 22` over the next year keeps only
  objects of roughly 140 metres and up, which is the population that news stories are actually about.
- **Two centuries of one named object for a lesson or a chart** — `designations: ["99942"]`, `body: "ALL"`: every
  recorded passage of Apophis past Earth, Venus and the Moon, including the 2029 pass at 38 000 km, inside
  geostationary orbit.
- **An object fact sheet for a catalogue or an agent tool** — `mode: "object"` returns one row per designation with
  orbit class, eccentricity, perihelion, aphelion, inclination, period, the orbit-to-orbit gap with Earth, the
  observation count behind the solution, the measured diameter and albedo where they exist, and who discovered it.
- **An impact-risk watchlist** — `mode: "riskList"`, `minImpactProbability: 0.0001`, sorted by probability: the Sentry
  entries above one in ten thousand, which the source itself publishes in no useful order.
- **A fireball map** — `mode: "fireballs"`, `onlyWithLocation: true`: signed latitude and longitude, altitude, entry
  velocity, radiated energy in joules and impact energy in kilotons, ready for a tile layer.
- **A scheduled alert** — `onlyNew: true` on any mode: a daily run writes only the approaches, Sentry entries or
  fireballs that appeared since the previous one, so the alert stays a few rows long.

### Input

Nothing is required. With no input at all the actor writes the near-Earth objects passing within ten lunar distances of
Earth over the next 60 days.

| Field | Type | Default | Allowed values / notes |
|---|---|---|---|
| `mode` | string | `approaches` | `approaches`, `object`, `riskList`, `fireballs`. See [Modes](#modes) |
| `designations` | string\[] | — | e.g. `["99942", "Bennu", "2024 YR4"]`. Required in `object` mode; in `approaches` mode it switches the run to the approach history of those objects. See [Designations](#designations) |
| `includePhysicalParams` | boolean | `true` | `object` mode: add measured diameter, rotation period, albedo, spectral type, density |
| `includeDiscovery` | boolean | `true` | `object` mode: add discovery date, site, credited discoverers and the name citation |
| `body` | string | `Earth` | 10 bodies plus `ALL`. See [Target bodies](#target-bodies) |
| `maxDistanceLd` | number | `10` | 0.001–2000 lunar distances. 1 LD = 384 400 km |
| `minDistanceLd` | number | — | 0–2000. Lower bound, for cutting one distance band out |
| `objectKind` | string | `neo` | `neo`, `nea`, `comet`, `neaAndComet`. See [Object kinds](#object-kinds) |
| `orbitClass` | string | all | 15 codes. See [Orbit classes](#orbit-classes) |
| `onlyPotentiallyHazardous` | boolean | `false` | Keep only objects the source flags as potentially hazardous |
| `minRelativeVelocityKms` | number | — | 0–100 km/s at closest approach |
| `maxRelativeVelocityKms` | number | — | 0–100 km/s |
| `maxAbsoluteMagnitude` | number | — | −10…40. Upper bound on H, so a **lower** bound on size. Applies to `approaches` and `riskList`. See [Brightness and size](#brightness-and-size) |
| `minAbsoluteMagnitude` | number | — | −10…40. Keeps the smaller objects |
| `dateFrom` | string | see notes | `2026-01-01`, `2026-01-01T12:00:00`, `now`, or days from the run start (`+30`, `-365`). UTC. See [Time window](#time-window) |
| `dateTo` | string | see notes | Same notation |
| `onlyNew` | boolean | `false` | Remember written rows between runs and write only what is new |
| `minImpactProbability` | number | — | 1e-10…1. `riskList`: cumulative chance as a fraction, `0.0001` = one in ten thousand |
| `minPalermoScale` | integer | — | −20…20. `riskList`. See [Risk scales](#risk-scales) |
| `observedWithinDays` | integer | — | 7–36500. `riskList`: keep entries whose newest observation is younger than this |
| `minImpactEnergyKt` | number | — | 0–1000. `fireballs`: total impact energy in kilotons |
| `onlyWithLocation` | boolean | `false` | `fireballs`: drop events with no published coordinates |
| `sortBy` | string | `date` | `date`, `distance`, `velocity`, `size`, `impactProbability`, `palermoScale`, `energy`, `designation`. See [Sort orders](#sort-orders) |
| `sortDescending` | boolean | `false` | Reverse the order |
| `maxItems` | integer | `50` | 1–2000 rows. The cost brake, applied after sorting |
| `fields` | string\[] | all | Keep only these output fields, in this order |

Sent to the source, so rows outside them are never fetched or paid for: `designations`, `body`, `maxDistanceLd`,
`minDistanceLd`, `objectKind`, `orbitClass`, `onlyPotentiallyHazardous`, the velocity bounds, `maxAbsoluteMagnitude`,
`minAbsoluteMagnitude` (approaches), `dateFrom`/`dateTo`, `minImpactProbability`, `minPalermoScale`,
`observedWithinDays`, `minImpactEnergyKt`, `onlyWithLocation` and `sortBy` where the endpoint supports it. Applied by
the actor: `minAbsoluteMagnitude` in `riskList`, the sorting the Sentry and database endpoints do not offer, `onlyNew`,
`maxItems` and `fields`.

`mode`, `body`, `objectKind`, `orbitClass` and `sortBy` are matched against their value lists: an obvious typo is
corrected and the correction is logged (`"marss"` → `Mars`, `"apolo"` → `APO`, `"comets"` → `comet`, `"dist"` →
`distance`, `"Uranus"` → `Urnus`). A value that matches nothing stops the run with the list of valid values — the
query is never widened behind your back.

Two things surprise people. **Distances are in lunar distances by default**, not astronomical units; every row still
carries `distanceAu` and `distanceKm`. And **naming designations in `approaches` mode changes the default window**
from the next 60 days to 1900–2100, because the point of naming an object is its whole record.

### Reference

#### Modes

- **`approaches`** (default) — one row per passage of an object near a body. With `designations` it becomes the
  approach history of those objects. Use the **Close approaches** view.
- **`object`** — one row per designation you list, with the orbit solution, the physical parameters that have been
  published and the discovery circumstances. One request per designation, in sequence. Use the **Object details** view.
- **`riskList`** — one row per entry on the Sentry impact-monitoring table: objects whose orbit is not yet known well
  enough to rule an Earth impact out. Use the **Impact risk** view.
- **`fireballs`** — one row per bright meteor recorded entering the atmosphere, with time, location, altitude,
  velocity and energy. Use the **Fireballs** view.

#### Designations

Write objects the way the source names them: a number (`99942`, `433`), a name (`Apophis`, `Bennu`, case-insensitive),
a provisional designation (`2024 YR4`, also accepted as `2024YR4`), a comet designation (`1P`, `141P`) or an SPK-id
(`20099942`). Matching is done by the source, not by us.

- A designation nobody knows yields **one row with `found: false`** and `notFoundReason`, never an empty success.
- A designation that matches several objects yields one row with `found: false` and the candidates in
  `matchedObjects`, so `1P` and `141P` never turn into a silently wrong row. `141P` alone matches five objects
  (`141P`, `141P-A`, `141P-D`, `141P-H`, `141P-I`) — ask for one of them.
- A designation that exists but has no passage inside your window is reported in the run's status message and in
  `SUMMARY`, not as a row.

#### Target bodies

`body` takes the source's own abbreviations. The `Every body` option adds the body name to each row, which is how you
see one asteroid pass Venus, Earth and the Moon in the same century.

| `body` | Body | Note |
|---|---|---|
| `Earth` | Earth | What monitoring and news want |
| `Moon` | Moon | Rarer and always inside a few LD of an Earth passage |
| `Merc` | Mercury | |
| `Venus` | Venus | |
| `Mars` | Mars | Mission planning and planetary science |
| `Juptr` | Jupiter | |
| `Satrn` | Saturn | Very few entries |
| `Urnus` | Uranus | The source spells it `Urnus`; `Uranus` and `Uran` are corrected to it |
| `Neptn` | Neptune | Very few entries |
| `Pluto` | Pluto | Very few entries |
| `ALL` | Every body the source tracks | Mixes bodies in one run |

Distances to the outer planets are large numbers of lunar distances, so raise `maxDistanceLd` for them or you will get
an empty (but successful) run.

#### Orbit classes

The dynamical family the source files an object under. Empty = every class.

| Code | Class | Meaning |
|---|---|---|
| `IEO` | Atira | Orbit entirely inside Earth's |
| `ATE` | Aten | Earth-crossing, smaller orbit than Earth's |
| `APO` | Apollo | Earth-crossing, larger orbit than Earth's |
| `AMO` | Amor | Comes close to Earth from outside without crossing |
| `MCA` | Mars-crossing asteroid | |
| `IMB` | Inner main belt | |
| `MBA` | Main belt | |
| `OMB` | Outer main belt | |
| `TJN` | Jupiter trojan | |
| `CEN` | Centaur | Between the giant planets |
| `TNO` | Trans-Neptunian object | |
| `HTC` | Halley-type comet | Long-period returning comet |
| `JFC` | Jupiter-family comet | Short-period comet |
| `PAR` | Parabolic comet | |
| `HYP` | Hyperbolic comet | Passing through once |

Most impact-risk objects are Atens and Apollos. The classes that never come near a planet (`MBA`, `IMB`, `OMB`, `TJN`,
`CEN`, `TNO`, `MCA`) hold no close-approach rows at all — they were all queried on 2026-09-30 and answered with an
empty table, which is the physics, not a bug. In a two-century window the classes with rows were `IEO`, `ATE`, `APO`,
`AMO`, `HTC` and `JFC`.

#### Object kinds

| `objectKind` | Population |
|---|---|
| `neo` | Near-Earth objects: asteroids and comets whose orbit comes within 1.3 au of the Sun. The source's own default |
| `nea` | Near-Earth asteroids only |
| `comet` | Comets only — a handful of passages per decade |
| `neaAndComet` | Near-Earth asteroids together with all comets |

`objectKind` is not applied when you list `designations`: the named objects are the filter, and adding a population
switch would silently drop an object you asked for by name.

#### Brightness and size

Absolute magnitude **H** is how bright an object would look at a standard distance. It counts *down* as objects grow, so
`maxAbsoluteMagnitude` is an upper bound on H and a lower bound on size. A diameter follows from H only once you assume
how reflective the surface is, so every row carries a **range** computed for the conventional reflectivity span 0.25
(dark end of the range gives the smaller figure) to 0.05:

`diameter_km = 1329 / sqrt(albedo) × 10^(−0.2 H)`

| H | `estimatedDiameterMinM` | `estimatedDiameterMaxM` |
|---|---|---|
| 14 | 4 213 m | 9 420 m |
| 17 | 1 058 m | 2 366 m |
| 20 | 266 m | 594 m |
| 22 | 106 m | 237 m |
| 24 | 42 m | 94 m |
| 26 | 17 m | 38 m |
| 28 | 7 m | 15 m |
| 30 | 3 m | 6 m |

The public hazard threshold of "about 140 metres" corresponds to H 22 at a middling reflectivity of 0.14, which is why
`maxAbsoluteMagnitude: 22` is the useful filter for "big enough to matter". These are estimates and are never presented
as measurements: `diameterKm` is filled only when the object was actually sized by radar, spacecraft or thermal
infrared, which is a small minority.

#### Risk scales

- **Impact probability** — the cumulative computed chance that the object strikes Earth at some point in the monitored
  span. `impactProbabilityOneIn` is the same number as "one chance in N", which is the form people read.
- **Palermo technical scale** — compares one object's hazard with the ordinary background risk from objects of the same
  size, on a base-10 log scale. −2 means a hundred times less worrying than the background; 0 would mean comparable to
  it. Rows carry the cumulative (`palermoScaleCum`) and the largest single value (`palermoScaleMax`). The source
  accepts whole numbers in `minPalermoScale`.
- **Torino scale** — the 0–10 public communication scale. Almost every Sentry entry is 0 or has no value at all;
  `torinoScaleMax` keeps a published 0 apart from a missing value (`null`).

#### Time window

`dateFrom` and `dateTo` accept a date, a date and time, the word `now`, or an offset in days from the moment the run
starts (`+30`, `-365`). Everything is resolved to an absolute UTC instant before the request goes out, so a scheduled
task keeps moving with the clock. Defaults depend on the mode:

| Mode | Empty `dateFrom` | Empty `dateTo` |
|---|---|---|
| `approaches` | now (1900-01-01 when `designations` are listed and both ends are empty) | 60 days after the start (2100-01-01 in the same case) |
| `fireballs` | one year before the end | now |
| `object` | not used | not used |
| `riskList` | not used — the table is a current snapshot; use `observedWithinDays` | not used |

#### Sort orders

The order is applied before `maxItems`, so it decides which rows you keep. Not every key fits every mode; a key that
does not apply falls back to `date` and says so in the run's status message and in `SUMMARY`, rather than failing or
reordering silently.

| `sortBy` | Ordered by | Modes |
|---|---|---|
| `date` | Approach time / discovery date / last observation / event time | all |
| `distance` | Approach distance | `approaches` |
| `velocity` | Relative velocity, entry velocity for fireballs | `approaches`, `fireballs` |
| `size` | Absolute magnitude, **biggest object first** | `approaches`, `object`, `riskList` |
| `impactProbability` | Cumulative impact probability | `riskList` |
| `palermoScale` | Cumulative Palermo value | `riskList` |
| `energy` | Total impact energy | `fireballs` |
| `designation` | Designation, as text | `approaches`, `object`, `riskList` |

`sortDescending: true` reverses whichever order you picked. Rows with no value for the key always sink to the end.

#### Units

1 lunar distance = 384 400 km (the mean Earth-Moon distance). 1 astronomical unit = 149 597 870.7 km = 389.17 LD. The
source's own default close-approach window of 0.05 au is 19.46 LD. Distances are in au, km and LD in every row;
velocities in km/s; radiated energy in joules (the source publishes it in units of 10¹⁰ J, kept as
`radiatedEnergy10e10J`); impact energy in kilotons of TNT equivalent; altitudes in km above the geoid.

### Examples

**What passes Earth in the next 30 days**

```json
{ "mode": "approaches", "body": "Earth", "dateFrom": "now", "dateTo": "+30", "maxDistanceLd": 10, "sortBy": "date", "maxItems": 25 }
```

**Only the large ones, over the next year, closest first**

```json
{ "mode": "approaches", "dateFrom": "now", "dateTo": "+365", "maxDistanceLd": 20, "maxAbsoluteMagnitude": 22, "sortBy": "distance", "maxItems": 20 }
```

**Two centuries of Apophis and Bennu, past every body**

```json
{ "mode": "approaches", "designations": ["99942", "101955"], "body": "ALL", "dateFrom": "1900-01-01", "dateTo": "2100-01-01", "maxDistanceLd": 40, "maxItems": 30 }
```

**Orbit, size and discovery of four well-studied objects**

```json
{ "mode": "object", "designations": ["99942", "101955", "433", "162173"], "includePhysicalParams": true, "includeDiscovery": true, "maxItems": 10 }
```

**Asteroids passing Mars in the next year**

```json
{ "mode": "approaches", "body": "Mars", "dateFrom": "now", "dateTo": "+365", "maxDistanceLd": 20, "sortBy": "distance", "maxItems": 20 }
```

**Impact-risk watchlist above one in ten thousand**

```json
{ "mode": "riskList", "minImpactProbability": 0.0001, "sortBy": "impactProbability", "sortDescending": true, "maxItems": 25 }
```

**The most energetic fireballs of the last five years**

```json
{ "mode": "fireballs", "dateFrom": "-1825", "dateTo": "now", "minImpactEnergyKt": 1, "onlyWithLocation": true, "sortBy": "energy", "sortDescending": true, "maxItems": 20 }
```

### Output

A real row from a cloud run (the prefill input: the Earth approaches of Apophis and Bennu within 10 LD between 1900
and 2100 — the 2029 Apophis passage inside geostationary orbit):

```json
{
  "designation": "99942",
  "fullName": "99942 Apophis (2004 MN4)",
  "objectName": "Apophis",
  "body": "Earth",
  "approachDate": "2029-04-13",
  "approachTime": "2029-04-13T21:46:00.000Z",
  "approachTimeSource": "2029-Apr-13 21:46",
  "julianDate": 2462240.407091969,
  "distanceAu": 0.00025409,
  "distanceKm": 38011.5,
  "distanceLd": 0.0989,
  "distanceMinLd": 0.0989,
  "distanceMaxLd": 0.0989,
  "relativeVelocityKms": 7.4225,
  "vInfinityKms": 5.8414,
  "timeUncertainty": "< 00:01",
  "absoluteMagnitude": 19.09,
  "diameterKm": 0.34,
  "diameterSigmaKm": 0.04,
  "estimatedDiameterMinM": 404.2,
  "estimatedDiameterMaxM": 903.7,
  "orbitId": "220",
  "matchedObjects": [],
  "notFoundReason": null,
  "found": true,
  "url": "https://ssd.jpl.nasa.gov/tools/sbdb_lookup.html#/?sstr=99942",
  "fetchedAt": "2026-09-30T19:59:13.943Z"
}
```

`approaches` — always filled: `designation`, `body`, `approachDate`, `approachTime`, `approachTimeSource`,
`julianDate`, `distanceAu`, `distanceKm`, `distanceLd`, `distanceMinLd`, `distanceMaxLd`, `relativeVelocityKms`,
`vInfinityKms`, `timeUncertainty`, `found`, `url`, `fetchedAt`.

| Field | Type | Meaning |
|---|---|---|
| `designation` | string | How the source names the object |
| `fullName` | string|null | Number, name and provisional designation together |
| `objectName` | string|null | Proper name alone; `null` for the unnamed majority |
| `body` | string | Body it passes; read from the response in `ALL` runs |
| `approachDate` / `approachTime` | string | Closest approach, ISO 8601 UTC |
| `approachTimeSource` | string | The published timestamp as printed, e.g. `2026-Oct-02 19:28` |
| `julianDate` | number | Julian date of closest approach |
| `distanceAu` / `distanceKm` / `distanceLd` | number | The same distance in three units |
| `distanceMinLd` / `distanceMaxLd` | number | Bounds of the distance uncertainty, in LD |
| `relativeVelocityKms` | number | Speed relative to the body at closest approach |
| `vInfinityKms` | number | Speed relative to the body before its gravity takes hold |
| `timeUncertainty` | string | Uncertainty of the time as published: `< 00:01`, `00:05`, `7_06:25` = days\_hours:minutes |
| `absoluteMagnitude` | number|null | H; filled for effectively every approach row in practice |
| `diameterKm` / `diameterSigmaKm` | number|null | Measured diameter and its uncertainty; `null` for most objects |
| `estimatedDiameterMinM` / `estimatedDiameterMaxM` | number|null | Size range implied by H, see [Brightness and size](#brightness-and-size) |
| `orbitId` | string | Which orbit solution the prediction came from |
| `matchedObjects` | array | Candidates when the designation was ambiguous; empty otherwise |
| `notFoundReason` | string|null | Why a `found: false` row is empty |
| `found` | boolean | `false` for a designation that could not be resolved |
| `url` | string | The object in the source's own lookup tool |
| `fetchedAt` | string | Run time, ISO 8601 UTC |

`object` — `designation`, `fullName`, `objectName`, `spkId`, `objectKindCode`, `objectKindName`, `orbitClass`,
`orbitClassCode`, `isNeo`, `isPotentiallyHazardous`, `absoluteMagnitude`, `magnitudeSlope`, `diameterKm`, `extentKm`
(triaxial extent as published text), `albedo`, `rotationPeriodHours`, `bulkDensity`, `spectralType`,
`estimatedDiameterMinM`, `estimatedDiameterMaxM`, `eccentricity`, `semiMajorAxisAu`, `perihelionAu`, `aphelionAu`,
`inclinationDeg`, `orbitalPeriodDays`, `meanAnomalyDeg`, `moidAu`, `moidLd` (smallest possible gap between the two
orbits — the number that decides hazard status), `moidJupiterAu`, `firstObservation`, `lastObservation`,
`observationsUsed`, `dataArcDays`, `orbitSolutionDate`, `conditionCode` (0 = a well-determined orbit, 9 = poor),
`discoveryDate`, `discoveredBy`, `discoverySite`, `nameCitation`, `matchedObjects`, `notFoundReason`, `found`, `url`,
`fetchedAt`.

`riskList` — `designation`, `fullName`, `objectName`, `impactProbability`, `impactProbabilityOneIn`,
`palermoScaleCum`, `palermoScaleMax`, `torinoScaleMax`, `potentialImpacts` (how many separate dates are being
watched), `impactYearRange`, `impactYearFirst`, `impactYearLast`, `diameterKm`, `estimatedDiameterM`,
`absoluteMagnitude`, `velocityKms`, `lastObservation`, `lastObservationRaw` (the published string, sometimes a day with
a decimal fraction), `sentryId`, `found`, `url`, `fetchedAt`.

`fireballs` — `eventTime` (peak brightness, UTC), `eventDate`, `latitude`, `longitude` (signed decimals),
`latitudeRaw`, `longitudeRaw` (degrees plus hemisphere letter, as published), `altitudeKm`, `velocityKms`,
`radiatedEnergyJoules`, `radiatedEnergy10e10J`, `impactEnergyKt`, `found`, `url`, `fetchedAt`.

Dataset views: **Close approaches** (`approaches`), **Object details** (`object`), **Impact risk** (`riskList`),
**Fireballs** (`fireballs`). Request the view that matches your mode.

Every run also writes a `SUMMARY` record to the key-value store: the mode, the filters in one line, how many requests
were sent, how many rows were read, matched and written, the designations that could not be resolved and why, the
designations with no passage in the window, and every corrected input value.

### Use it from code / agents

```bash
curl -X POST "https://api.apify.com/v2/acts/yadroo~nasa-asteroid-approaches/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"mode":"approaches","dateFrom":"now","dateTo":"+30","maxDistanceLd":10,"maxItems":25}'
```

```js
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('yadroo/nasa-asteroid-approaches').call({
    mode: 'riskList', minImpactProbability: 0.0001, sortBy: 'impactProbability', sortDescending: true, maxItems: 25,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
```

```python
from apify_client import ApifyClient
client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("yadroo/nasa-asteroid-approaches").call(run_input={
    "mode": "object", "designations": ["99942", "Bennu", "2024 YR4"], "maxItems": 10})
items = client.dataset(run["defaultDatasetId"]).list_items().items
```

MCP: add `https://mcp.apify.com` to Claude / Cursor / any MCP client and call the `yadroo/nasa-asteroid-approaches`
tool with the same JSON input. For a model context, cut the row down first:
`"fields": ["designation","objectName","approachTime","distanceLd","relativeVelocityKms","estimatedDiameterMaxM"]`.
`designation` (or `eventTime` for fireballs) and `found` are always kept so a row stays identifiable.

On a schedule, set `onlyNew: true`. The actor remembers what it has written in a named key-value store — one per task,
so two schedules with different filters do not blind each other — and writes only rows it has not reported before. The
first run writes everything it matches, so start it once by hand before you schedule it.

### Pricing

Pay per event: **$0.001 per run start + $0.002 per dataset row**. The start event is charged on every run, including a
run whose filters match nothing. Apify plan tiers discount both prices (Bronze −10 %, Silver −20 %, Gold and above
−30 %).

Worked examples at full price:

- One object lookup, 1 row: $0.001 + $0.002 = **$0.003**.
- The next 30 days past Earth within 10 LD, about 10 rows: $0.001 + $0.020 = **$0.021**.
- A 25-row Sentry watchlist: $0.001 + $0.050 = **$0.051**.
- The default 50 rows: $0.001 + $0.100 = **$0.101**.
- The maximum `maxItems: 2000`: $0.001 + $4.000 = **$4.001**.

`maxItems` is both the cost brake and the run-time brake. Each endpoint answers a whole filtered table in one
response, so the actor pushes the filters and the sort to the source, reads one bounded page per designation and stops
at `maxItems`. A typical run is 256 MB for well under a minute, so compute is a fraction of a cent.

### Limits & FAQ

- **One request at a time, and a named User-Agent.** The source's fair-use terms ask for no simultaneous requests, for
  an application-specific User-Agent, and for backing off rather than retrying hard. The actor sends its requests
  strictly in sequence with a short pause, identifies itself as `yadroo-nasa-asteroid-approaches`, and backs off on
  429 and 5xx with a bounded number of attempts. A run is one request in the list modes, one per designation in the
  others. `robots.txt` on the API host answers 404, so nothing is disallowed.
- **Approach timestamps are barycentric dynamical time, about a minute off UTC.** The published clock reading is
  carried through unchanged into `approachTime` and kept verbatim in `approachTimeSource`. TDB runs roughly 69 seconds
  ahead of UTC; for anything but a spacecraft that is well inside the timing uncertainty the source itself publishes
  in `timeUncertainty`, which can be days for a distant prediction.
- **Measured diameters are rare.** A published `diameterKm` exists for the objects that were sized by radar,
  spacecraft or thermal infrared. Everything else has only brightness, from which the actor computes a range — see
  [Brightness and size](#brightness-and-size). Do not treat `estimatedDiameterMaxM` as a measurement.
- **Impact probabilities are model output, and the source says so.** The published documentation warns that the
  probabilities can be off by a factor of a few to ten and the probability-weighted diameters by a factor of two. They
  answer "is this worth watching", not "how likely is this really".
- **The Sentry table shrinks as often as it grows.** An object leaves it as soon as new observations rule an impact
  out, so a designation you saw last month can be gone today. That is why the risk mode has no time window: it is a
  snapshot. Use `observedWithinDays` to keep the entries that are still under observation — many entries rest on a
  handful of measurements from years ago.
- **Fireball rows are often incomplete.** Location, altitude and velocity are published for part of the events only;
  entry velocity was missing for most recent 2026 entries. `onlyWithLocation` drops the events with no coordinates,
  which is what you want for a map. The record is updated in batches, not live, so the last few days can be thin.
- **Getting the hemisphere right matters.** The source publishes fireball coordinates as degrees plus `N`/`S` and
  `E`/`W`. The actor emits signed `latitude`/`longitude` and keeps the published pair in `latitudeRaw`/`longitudeRaw`
  so you can check it.
- **Empty is not broken.** An outer planet at 10 LD, a main-belt orbit class in the close-approach table, or a Palermo
  bound of 0 all match nothing. The run succeeds, writes no rows and says in its status message what to widen.
- **An unknown designation is an answer, not a crash.** The close-approach table rejects a designation it cannot read
  with an error and the database answers an unknown one with a "not found" message; either way the actor writes one
  row with `found: false` and the reason. An ambiguous designation returns the candidate list instead of a guess.
- **Counting the whole table.** The source's "total matches" shortcut is unavailable together with a designation, so
  for a per-object query the actor reports what it read rather than a matched total. For a window query the status
  message names the total and tells you to raise `maxItems` if it exceeds what you asked for.
- **No forecasting, no imagery, no orbital propagation.** This is the published record: predicted and past approaches,
  the orbit solution as it stands, the risk table as it stands, the fireballs that were recorded. It computes no new
  orbits and renders no positions.
- **Formats may change without notice.** The endpoints are best-effort public services and the source reserves the
  right to change the response shape. Every parser indexes columns by the field list the response itself carries, not
  by position, so a reordered or added column does not corrupt a row — but a renamed one would need a fix.
- **Licence.** NASA/JPL data is US government public domain and nothing in the source's terms forbids automated or
  commercial use. Check the source's own pages before you republish large extracts.

***

Made by **Yadroo**. Sibling actors: [nasa-eonet-events](https://apify.com/yadroo/nasa-eonet-events) ·
[open-meteo-weather](https://apify.com/yadroo/open-meteo-weather) ·
[openalex-works](https://apify.com/yadroo/openalex-works) · [arxiv-papers](https://apify.com/yadroo/arxiv-papers) ·
[osm-geocode](https://apify.com/yadroo/osm-geocode)

# Actor input Schema

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

Four different questions, four different row shapes, one per run. `approaches` answers "what passes close and when". `object` answers "what is known about this asteroid or comet" for the designations you list. `riskList` is the Sentry table of objects with a non-zero computed chance of hitting Earth in the next century or later. `fireballs` is the record of bright meteors that entered the atmosphere, with location and energy. Read the dataset view that matches the mode: Close approaches, Object details, Impact risk, Fireballs.

## `designations` (type: `array`):

Objects to look up, written the way the source names them: a number (`99942`, `433`), a name (`Apophis`, `Bennu`), a provisional designation (`2024 YR4`), a comet designation (`1P`, `141P`) or an SPK-id (`20099942`). Required in `object` mode. In `approaches` mode it narrows the run to the approach record of these objects instead of a whole time window, which is how you follow one asteroid across a century. A designation the source does not know yields one row with `found: false` and the reason in `notFoundReason`; a designation that matches several objects yields one row per candidate in `matchedObjects` with `found: false`, so an ambiguous comet id never turns into a silently wrong row. Ignored in `riskList` and `fireballs` mode.

## `includePhysicalParams` (type: `boolean`):

Add what is measured about the body itself: diameter, rotation period, geometric albedo, spectral type, bulk density and the absolute magnitude with its published reference. These come from the literature and are filled for well-studied objects only - a newly discovered object usually carries an absolute magnitude and nothing else, in which case the estimated-diameter range computed from that magnitude is all there is.

## `includeDiscovery` (type: `boolean`):

Add the discovery date, the observing site, the credited discoverers and, for named objects, the citation text that explains the name. Useful for catalogue and education work; switch it off to keep rows narrow.

## `body` (type: `string`):

Which body the object passes. Earth is what news and monitoring want; Mars matters for mission planning and Jupiter for orbital dynamics. `Every body` adds the `body` column to the result and mixes planets in one run, which is the honest way to see that a single asteroid passes Venus, Earth and Mars in the same decade. Distances to the outer planets are large numbers of lunar distances, so raise the distance limit for them.

## `maxDistanceLd` (type: `number`):

Upper bound on the approach distance in lunar distances (1 LD = 384 400 km, the average Earth-Moon distance). 1 keeps only the rare passages inside the Moon's orbit, 10 is a normal monitoring window, 20 is roughly the source's own default of 0.05 astronomical units. Every row carries the same distance in kilometres, astronomical units and lunar distances, so you never convert by hand.

## `minDistanceLd` (type: `number`):

Lower bound on the approach distance, for cutting one band out of the table - for example between 1 and 5 lunar distances. Empty = no lower bound.

## `objectKind` (type: `string`):

Near-Earth objects are the ones whose orbit comes within 1.3 astronomical units of the Sun, which is the population that produces close approaches; that is the source's own default. Choose comets to watch the few that come near a planet, or the mixed option to see near-Earth asteroids together with comets from farther out.

## `orbitClass` (type: `string`):

Keep only objects the source files under this dynamical class. Aten and Apollo are the Earth-crossing families that most impact-risk objects belong to; Amor objects come close without crossing; the comet classes separate returning comets from the ones passing through once. Empty = every class. The full code list is printed in README > Reference dictionaries.

## `onlyPotentiallyHazardous` (type: `boolean`):

Keep only objects the source flags as potentially hazardous: an orbit that comes within 0.05 astronomical units of Earth's and an absolute magnitude of 22 or brighter, which is roughly 140 metres across. It is a standing property of the orbit, not a statement about a particular passage, and it is what public hazard lists are built from. Applies to `approaches` mode; in `object` mode the flag is reported in `isPotentiallyHazardous` instead of filtering.

## `minRelativeVelocityKms` (type: `number`):

Lower bound on the speed of the object relative to the body at the moment of closest approach. Typical Earth encounters run between 3 and 30 km/s; the fast end is what makes a small object energetic.

## `maxRelativeVelocityKms` (type: `number`):

Upper bound on the same speed. Slow encounters are the ones a spacecraft could reach, which is why mission planners filter on them.

## `maxAbsoluteMagnitude` (type: `number`):

Absolute magnitude H is the brightness an object would have at a standard distance; smaller H means a bigger body, so this is an upper bound on H and a lower bound on size. 22 is about 140 metres and the threshold used for hazard lists, 24 is about 60 metres, 28 is a few metres. Applies to `approaches` and `riskList`. Because size follows from brightness only when the reflectivity is known, every row carries `estimatedDiameterMinM` and `estimatedDiameterMaxM` computed from H for the usual reflectivity range, next to the measured `diameterKm` where one exists.

## `minAbsoluteMagnitude` (type: `number`):

Lower bound on H, which keeps the smaller objects. Use it with the bound above to isolate one size band, for example H between 22 and 25 for objects of roughly 40 to 140 metres.

## `dateFrom` (type: `string`):

Window start, written as a date (`2026-01-01`), a date and time (`2026-01-01T12:00:00`), the word `now`, or an offset in days from today (`+30`, `-365`). Offsets and `now` are resolved against the UTC date of the run before the request is sent, so a scheduled task keeps moving with time: `now` to `+30` is "the next month", `-365` to `now` is "the past year". Empty in `approaches` mode = now; empty in `fireballs` mode = one year back, because the fireball record only holds past events.

## `dateTo` (type: `string`):

Window end in the same notation. Empty in `approaches` mode = 60 days after the start; empty in `fireballs` mode = now. When you list designations in `approaches` mode and leave both ends empty, the whole recorded span of those objects is used (1900 to 2100), because the point of naming an object is its full approach history rather than the next two months.

## `onlyNew` (type: `boolean`):

Remember the identity of every written row in this actor's key-value store - approach = object plus date, object = designation, risk = designation plus computation date, fireball = event time - and write only what is not there yet. Built for schedules: a daily run with `onlyNew` reports the approaches, Sentry entries and fireballs that appeared since the previous run, which is the shape an alert needs. The first run writes everything it matches, so start it once by hand before you schedule it.

## `minImpactProbability` (type: `number`):

Lower bound on the cumulative computed chance that the object hits Earth at some point in the monitored span, as a fraction: 0.0001 is one in ten thousand and keeps a couple of hundred objects, 0.01 is one in a hundred and keeps very few. Every row also carries `impactProbabilityOneIn`, the same number as "one in N", which is the form people actually read. The source is explicit that these probabilities rest on assumptions that are hard to verify and can be off by a factor of several.

## `minPalermoScale` (type: `integer`):

Lower bound on the Palermo technical scale, which compares the hazard of one object with the ordinary background risk from objects of the same size: -2 means one hundred times less worrying than the background and already restricts the table to a handful of entries, 0 would mean comparable to it. The source accepts whole numbers here. Rows carry both the cumulative and the maximum value.

## `observedWithinDays` (type: `integer`):

Keep only Sentry objects whose newest observation is younger than this. Many entries rest on a handful of measurements from years ago and are on the table precisely because nobody has looked since; a window of 365 days gives you the objects under current observation.

## `minImpactEnergyKt` (type: `number`):

Lower bound on the estimated total impact energy of a fireball, in kilotons of TNT equivalent. Most recorded events sit below 1 kt; a handful of the last twenty years reach tens of kilotons. Empty = every recorded event in the window.

## `onlyWithLocation` (type: `boolean`):

Drop events whose latitude and longitude were not published, which is what you want when the rows go on a map. We convert the source's degrees-plus-hemisphere pair into signed decimal `latitude` and `longitude`, so a southern or western event does not silently become a northern or eastern one.

## `sortBy` (type: `string`):

The order applied before the row limit, so it decides which rows you keep when the filters match more than you asked for. Not every key fits every mode: impact probability and Palermo scale belong to `riskList`, energy to `fireballs`, distance and velocity to `approaches`. A key that does not apply falls back to date and says so in the run's status message rather than failing.

## `sortDescending` (type: `boolean`):

Reverse the order above. Date ascending is the monitoring order (what comes next); descending gives the most recent past events, which is what you want for fireballs.

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

Stop after this many rows. The source returns a whole filtered table in one response, so the limit is applied after sorting: a small number keeps the run short and cheap without changing which rows are the interesting ones. A century of approaches for one object or the full Sentry table can run into the hundreds.

## `fields` (type: `array`):

Keep only these fields, in this order, e.g. \["designation", "approachTime", "distanceLd", "relativeVelocityKms"]. Empty = every field of the mode.

## Actor input object example

```json
{
  "mode": "approaches",
  "designations": [
    "99942",
    "101955"
  ],
  "includePhysicalParams": true,
  "includeDiscovery": true,
  "body": "Earth",
  "maxDistanceLd": 10,
  "objectKind": "neo",
  "onlyPotentiallyHazardous": false,
  "dateFrom": "1900-01-01",
  "dateTo": "2100-01-01",
  "onlyNew": false,
  "onlyWithLocation": false,
  "sortBy": "date",
  "sortDescending": false,
  "maxItems": 50
}
```

# Actor output Schema

## `results` (type: `string`):

No description

# 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 = {
    "designations": [
        "99942",
        "101955"
    ],
    "dateFrom": "1900-01-01",
    "dateTo": "2100-01-01"
};

// Run the Actor and wait for it to finish
const run = await client.actor("yadroo/nasa-asteroid-approaches").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 = {
    "designations": [
        "99942",
        "101955",
    ],
    "dateFrom": "1900-01-01",
    "dateTo": "2100-01-01",
}

# Run the Actor and wait for it to finish
run = client.actor("yadroo/nasa-asteroid-approaches").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{
  "designations": [
    "99942",
    "101955"
  ],
  "dateFrom": "1900-01-01",
  "dateTo": "2100-01-01"
}' |
apify call yadroo/nasa-asteroid-approaches --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,yadroo/nasa-asteroid-approaches"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/zBISpdcdsXfsbe1KG/builds/7WRmhbfArJV3ZDs3f/openapi.json
