SeekSat MCP
Same engine, two faces: the web app shows satellite pages and pass lists for people; this MCP server exposes the same SGP4 + visibility-physics engine to AI agents.
Connect
Endpoint (Streamable HTTP, no sign-in):
https://seeksat.com/api/mcpClaude Code
claude mcp add --transport http seeksat https://seeksat.com/api/mcpAdd --scope user to have it in every project. Or in a project's .mcp.json (a remote server needs "type": "http"):
{
"mcpServers": {
"seeksat": {
"type": "http",
"url": "https://seeksat.com/api/mcp"
}
}
}Claude Desktop and claude.ai
Settings > Connectors > Add custom connector, name it SeekSat, and paste https://seeksat.com/api/mcp. No sign-in is needed.
Where custom connectors are not available, bridge it in claude_desktop_config.json with mcp-remote (needs Node.js):
{
"mcpServers": {
"seeksat": {
"command": "npx",
"args": [
"-y",
"mcp-remote",
"https://seeksat.com/api/mcp"
]
}
}
}Cursor
In ~/.cursor/mcp.json (or .cursor/mcp.json in a project):
{
"mcpServers": {
"seeksat": {
"url": "https://seeksat.com/api/mcp"
}
}
}Access and limits
Free and open: no sign-up and no key needed, and every satellite is free. The server also reads an optional API key (Authorization: Bearer <key>, or X-API-Key: <key>) so keyed access can be added later without an API change.
To send a key from Claude Code:
claude mcp add --transport http seeksat https://seeksat.com/api/mcp --header "Authorization: Bearer YOUR_KEY"From Cursor:
{
"mcpServers": {
"seeksat": {
"url": "https://seeksat.com/api/mcp",
"headers": {
"Authorization": "Bearer YOUR_KEY"
}
}
}
}Up to 120 requests per 60 seconds per IP address (a firewall rule on the endpoint). Past that, requests are refused with HTTP 429 until the minute is up.
Errors
- A tool that cannot answer (an unknown satellite, a place it cannot geocode, a time it cannot read) returns a normal tool result with isError: true and the text "Error: <message>", saying what to fix.
- Inputs of the wrong type or out of range are refused before the tool runs. That is also a tool result with isError: true (not a JSON-RPC error), whose text starts "MCP error -32602: Input validation error" and names the field and its limit.
- A parameter a tool does not take is refused the same way, with a message listing the ones it does take. Old parameter names still work on every tool that takes the parameter: minElevationDeg and minElev for minElevation; passTime for time.
Tools
| Tool | What it does |
|---|---|
list_satellites | The popular satellites (ISS, Tiangong, Hubble and a few more) with each one's orbit data freshness. |
find_passes | Every upcoming pass of one satellite over a place, in time order: times (UTC and local), height, direction, brightness, rating, and when it can be seen by eye. |
get_position | Where a satellite is now or at a given time: the point below it, altitude, and whether it is sunlit. |
next_visible_pass | One call for "when can I next see it from here?", optionally with its sky chart. |
get_pass_weather | Cloud-cover forecast and viewing probability for a place and time, or available:false with the reason. |
get_pass_chart | A rendered polar sky chart (PNG) of a pass, the next one or the one at a given time: where to look, with the moon, planets and stars in place. |
search_satellites | Find any satellite in the catalog (about 17,000) by name, alias or NORAD number. |
get_radio_pass | Known frequencies, Doppler swing, when to tune where and where to point, for one pass (or 24 hours for a satellite that never sets). |
best_pass | The best upcoming pass over a place, for one satellite or from a scan: visual mode scans the popular satellites plus CelesTrak's visual group (the brightest objects) with the cloud forecast folded in; radio mode scans every satellite with known downlinks, optionally by band or mode. |
whats_up_now | What is in the sky over a place right now, from the whole catalog: brightest in a dark sky, or radio satellites highest first. |
identify_satellite | "What was that moving light?" The satellites that were sunlit near where and when it was seen, best match first. |
What results include
- Satellite results include url, the satellite's page on seeksat.com, to link to. Pass rows add passUrl, which opens that exact pass from that place.
- Times are UTC ISO 8601. Results with a place add resolvedLocation.timeZone (IANA) and, next to every time, the same moment on the observer's clock with its offset: rise and riseLocal, peak and peakLocal, and so on.
- Time inputs: ISO 8601 with Z or an offset, e.g. "2026-11-14T21:00:00-06:00"; a time with no offset, e.g. "2026-11-14T21:00", is read in the observer's time zone, and the result echoes how it was read (interpretedAs). A local time the clocks skip at a daylight-saving change is moved forward, with a note.
- Pass rows say when the satellite can really be seen: visibleFrom and visibleUntil (null if never on that pass), and leavesShadow or entersShadow when it appears or fades mid-sky. sunlit is only the state at the peak. Azimuths come with compass words (direction) and peakRangeKm is the distance at the peak.
- Pass rows carry rating, the rating seeksat.com shows: { word, bars (1-5), level, reason, and in visual mode headroomMag, how far it outshines the faintest stars you can see }, from brightness against the sky (skyType) and the cloud forecast in visual mode, and from peak height in radio mode. captureProbability (quality is its old name) is the chance a camera captures the pass, a different number that leaves brightness out.
- Magnitudes are measured for most of the bright satellites (Mike McCants' Quicksat magnitudes), and a Starlink still in its launch train gets a typical train brightness. For any other satellite the magnitude is a cautious estimate from an assumed small size, marked peakMagnitudeEstimated or magnitudeEstimated, and a visual pass rated on it stops at Fair, as on the site.
- elementAge grades the orbital elements behind a result as the site does: fresh, old (over 7 days) or stale (over 14), with a warning when not fresh. Whole-sky tools and best_pass scans leave stale objects out and count them (skippedStaleElements). A tool for one satellite refuses to work out any time more than 30 days from the elements' epoch, whether now, a time asked about, the end of a search window, or the pass it answers with.
- An empty pass list comes with a note saying why. get_pass_weather answers available:false with a reason when it has no forecast for the time.
- Every tool only reads (readOnlyHint). Tools that take a place name are open-world: they geocode it with OpenStreetMap. get_pass_weather, and in visual mode best_pass, find_passes, next_visible_pass and get_pass_chart, fetch a cloud forecast.
Tool parameters
list_satellites: Popular satellites
List the popular satellites (ISS, Tiangong, Hubble and a few others) with each one's orbit data freshness. This is not the full list: every other tool also accepts any NORAD catalog number, e.g. 25544.
No parameters.
find_passes: Find passes
List every upcoming pass of one satellite over a location in the next windowHours (default 48, up to 240), in time order. Each pass has rise/peak/set times (UTC, plus riseLocal etc. on the observer's clock), peak elevation, azimuths with compass words (direction), the range at the peak (peakRangeKm), duration, brightness (magnitude, lower is brighter; peakMagnitudeEstimated means no measured magnitude is known for it, so it is a cautious guess; most of the bright satellites have a measured one, and a Starlink still flying in its launch train uses a typical train brightness, a rule of thumb rather than a measurement), and when it can be seen by eye: visibleFrom/visibleUntil (null if never on that pass) plus leavesShadow/entersShadow when it appears or fades mid-sky. rating is the rating seeksat.com shows for the pass: { word (Poor, Fair, Good, Great, Excellent), bars (1-5), level (low, ok, good), reason }. In visual mode it is how much brighter than the faintest visible star the pass gets for skyType (headroomMag), stepped down for a cloudy forecast up to 4 days ahead, and no higher than Fair when the brightness is estimated; in radio mode it is the peak height, a bar lower for each 6 dB of extra path loss when the satellite is more than 2,000 km away at the peak (8,000 km costs two bars), and no higher than Fair when SatNOGS stations tried at least 3 times in 30 days and heard nothing (the result then carries the satellite's reception and receptionSource). captureProbability (0-1) is the chance a camera captures the pass: sky darkness, height, clear-sky odds and length, with brightness playing no part; quality is its old name, the same number. Rise and set are when it crosses minElevation, not the horizon. In visual mode rise and set are the part of the pass that can be seen, so they can start or end mid-sky, and peak, peakElevationDeg and direction.peak are the highest point of that part (the whole pass may climb higher). passUrl opens that pass on seeksat.com, from that place, to hand to the user. In visual mode it fetches the cloud forecast for the place, as best_pass does (`weather` says whether one was used). This is the tool for comparing passes or finding the best or brightest one over a span of days, not just the next. An empty list comes with a note saying why (it never rises high enough from that latitude, the sky never gets dark, and so on). Feed a pass's peak time to get_pass_chart (to draw it) or get_pass_weather (to check clouds). To rank passes across many satellites at once, use best_pass.
| Parameter | Type | Details |
|---|---|---|
satellite (required) | string or whole number | NORAD catalog number (as a number or a string) or a name, e.g. 25544, "25544" or "iss". |
lat | number, -90 to 90 | observer latitude in decimal degrees, north positive (-90 to 90). Give it with lon, or give location instead. |
lon | number, -180 to 180 | observer longitude in decimal degrees, east positive and west negative (-180 to 180). |
location | string | where the observer is, when lat and lon are not given (they win when both are): a Maidenhead grid square (EN52, EN52ve, EN52ve12), coordinates in any common form ("41.88, -87.63", "41.88N 87.63W", "41°52'48"N 87°37'48"W", a Google Maps link or geo: URI), all read locally, or a place name (city, address, landmark) looked up with OpenStreetMap. Prefer lat and lon, or a grid square, when you have them: a place name is a network lookup. |
windowHours | number, above 0, up to 240 | how far ahead to look, in hours, up to 240 (10 days). Default 48. |
minElevation | number, 0 to 90 | lowest elevation that counts: a pass must climb above it, and rise and set are when it crosses it, in degrees above the horizon (0 to 90). Default 10. |
mode | "visual" | "radio" | "visual" (default): naked-eye passes, sunlit while the sky is dark; "radio": every line-of-sight pass, day or night. |
skyType | "city" | "suburban" | "rural" | "dark" | how dark the observer's sky is, for the visual rating as on seeksat.com: "city" (stars to magnitude 3.5), "suburban" (stars to magnitude 4.5), "rural" (stars to magnitude 5.5), "dark" (stars to magnitude 6.5). Default "suburban". |
get_position: Satellite position
Where a satellite is now, or at a given time: the point on Earth straight below it (latDeg, lonDeg, not where it is in your sky), its altitude, and whether it is sunlit, with url (its page on seeksat.com). A location is optional: it only sets the time zone for local times and for reading a time with no offset (UTC without one). A time more than 30 days from the orbital elements' epoch is refused.
| Parameter | Type | Details |
|---|---|---|
satellite (required) | string or whole number | NORAD catalog number (as a number or a string) or a name, e.g. 25544, "25544" or "iss". |
time | string | when. Default: now. ISO 8601 with Z or an offset, e.g. "2026-11-14T21:00:00-06:00"; a time with no offset, e.g. "2026-11-14T21:00", is read in the observer's time zone, and the result echoes how it was read (interpretedAs). A local time the clocks skip at a daylight-saving change is moved forward, with a note. |
lat | number, -90 to 90 | observer latitude in decimal degrees, north positive (-90 to 90). Give it with lon, or give location instead. |
lon | number, -180 to 180 | observer longitude in decimal degrees, east positive and west negative (-180 to 180). |
location | string | where the observer is, when lat and lon are not given (they win when both are): a Maidenhead grid square (EN52, EN52ve, EN52ve12), coordinates in any common form ("41.88, -87.63", "41.88N 87.63W", "41°52'48"N 87°37'48"W", a Google Maps link or geo: URI), all read locally, or a place name (city, address, landmark) looked up with OpenStreetMap. Prefer lat and lon, or a grid square, when you have them: a place name is a network lookup. Optional here. |
next_visible_pass: Next visible pass
Convenience shortcut: the next pass of one satellite from a location (looks windowHours ahead, default 72). Use this only when the user wants "the next pass". Set chart:true to also render that pass's sky chart in this same call. To compare upcoming passes, or find the best one over several days, use find_passes (one satellite) or best_pass (many) instead. When there is no pass, a note says why.
| Parameter | Type | Details |
|---|---|---|
satellite (required) | string or whole number | NORAD catalog number (as a number or a string) or a name, e.g. 25544, "25544" or "iss". |
lat | number, -90 to 90 | observer latitude in decimal degrees, north positive (-90 to 90). Give it with lon, or give location instead. |
lon | number, -180 to 180 | observer longitude in decimal degrees, east positive and west negative (-180 to 180). |
location | string | where the observer is, when lat and lon are not given (they win when both are): a Maidenhead grid square (EN52, EN52ve, EN52ve12), coordinates in any common form ("41.88, -87.63", "41.88N 87.63W", "41°52'48"N 87°37'48"W", a Google Maps link or geo: URI), all read locally, or a place name (city, address, landmark) looked up with OpenStreetMap. Prefer lat and lon, or a grid square, when you have them: a place name is a network lookup. |
mode | "visual" | "radio" | "visual" (default): naked-eye passes, sunlit while the sky is dark; "radio": every line-of-sight pass, day or night. |
windowHours | number, above 0, up to 240 | how far ahead to look, in hours, up to 240 (10 days). Default 72. |
minElevation | number, 0 to 90 | lowest elevation that counts: a pass must climb above it, and rise and set are when it crosses it, in degrees above the horizon (0 to 90). Default 10. |
skyType | "city" | "suburban" | "rural" | "dark" | how dark the observer's sky is, for the visual rating as on seeksat.com: "city" (stars to magnitude 3.5), "suburban" (stars to magnitude 4.5), "rural" (stars to magnitude 5.5), "dark" (stars to magnitude 6.5). Default "suburban". |
chart | boolean | true to also render that pass's polar sky chart (PNG) and return it in this same result. Default false. |
get_pass_weather: Pass weather
Cloud-cover forecast (Open-Meteo and MET Norway) and the chance of a clear view for a location at one time, such as a pass's peak. The forecast reaches about 7 to 16 days ahead. viewingProbability is the clear-sky chance (0-1), blended toward 0.5 the further ahead the time is, since forecasts lose skill. When there is no forecast for that time (in the past, beyond the forecast, a time it cannot read, or the forecast could not be fetched) the result is available:false with a reason, never a stand-in number.
| Parameter | Type | Details |
|---|---|---|
lat | number, -90 to 90 | observer latitude in decimal degrees, north positive (-90 to 90). Give it with lon, or give location instead. |
lon | number, -180 to 180 | observer longitude in decimal degrees, east positive and west negative (-180 to 180). |
location | string | where the observer is, when lat and lon are not given (they win when both are): a Maidenhead grid square (EN52, EN52ve, EN52ve12), coordinates in any common form ("41.88, -87.63", "41.88N 87.63W", "41°52'48"N 87°37'48"W", a Google Maps link or geo: URI), all read locally, or a place name (city, address, landmark) looked up with OpenStreetMap. Prefer lat and lon, or a grid square, when you have them: a place name is a network lookup. |
time (required) | string | the time to check, e.g. a pass's peak. ISO 8601 with Z or an offset, e.g. "2026-11-14T21:00:00-06:00"; a time with no offset, e.g. "2026-11-14T21:00", is read in the observer's time zone, and the result echoes how it was read (interpretedAs). A local time the clocks skip at a daylight-saving change is moved forward, with a note. |
get_pass_chart: Pass sky chart
Render a polar sky chart (PNG) of a satellite's pass over a location: where to look, with the moon, planets and stars in their real positions. Returns JSON (the charted pass as a full pass row, the same as find_passes gives, and a one-line summary) and the image. A geostationary satellite has no passes: the result gives `stationary` (where to point) instead. By default it charts the next pass; give `time` (the rise or peak of a pass from find_passes or best_pass) to chart that pass instead. Use the same minElevation as the pass came from. A time more than 30 days from the orbital elements' epoch is refused.
| Parameter | Type | Details |
|---|---|---|
satellite (required) | string or whole number | NORAD catalog number (as a number or a string) or a name, e.g. 25544, "25544" or "iss". |
lat | number, -90 to 90 | observer latitude in decimal degrees, north positive (-90 to 90). Give it with lon, or give location instead. |
lon | number, -180 to 180 | observer longitude in decimal degrees, east positive and west negative (-180 to 180). |
location | string | where the observer is, when lat and lon are not given (they win when both are): a Maidenhead grid square (EN52, EN52ve, EN52ve12), coordinates in any common form ("41.88, -87.63", "41.88N 87.63W", "41°52'48"N 87°37'48"W", a Google Maps link or geo: URI), all read locally, or a place name (city, address, landmark) looked up with OpenStreetMap. Prefer lat and lon, or a grid square, when you have them: a place name is a network lookup. |
time | string | charts the pass around this time (a pass's rise or peak from find_passes or best_pass). Default: the next pass from now. ISO 8601 with Z or an offset, e.g. "2026-11-14T21:00:00-06:00"; a time with no offset, e.g. "2026-11-14T21:00", is read in the observer's time zone, and the result echoes how it was read (interpretedAs). A local time the clocks skip at a daylight-saving change is moved forward, with a note. |
mode | "visual" | "radio" | "visual" (default): naked-eye passes, sunlit while the sky is dark; "radio": every line-of-sight pass, day or night. |
minElevation | number, 0 to 90 | lowest elevation that counts: a pass must climb above it, and rise and set are when it crosses it, in degrees above the horizon (0 to 90). Default 10. |
skyType | "city" | "suburban" | "rural" | "dark" | how dark the observer's sky is, for the visual rating as on seeksat.com: "city" (stars to magnitude 3.5), "suburban" (stars to magnitude 4.5), "rural" (stars to magnitude 5.5), "dark" (stars to magnitude 6.5). Default "suburban". |
windowHours | number, above 0, up to 240 | how far ahead to look, in hours, up to 240 (10 days). Default 72. Only used to find the next pass when no time is given. |
search_satellites: Search satellites
Search the full satellite catalog (about 17,000 objects) by name, alias or NORAD number, best match first. Use it to turn a name like "SDO" or "NOAA 19" into a NORAD number for the other tools; names outside the popular list only resolve directly on an exact whole-name match. To find satellites by downlink kind, search with mode "radio" and the kind as the query (query "sstv").
| Parameter | Type | Details |
|---|---|---|
query (required) | string | a name, part of one, or a NORAD number, e.g. "sdo", "noaa 19", "25544". With mode "radio", a downlink kind as the whole query (e.g. "sstv", "aprs", "cw") lists satellites that have one. |
limit | whole number, 1 to 20 | how many results to return, 1 to 20. Default 10. |
mode | "visual" | "radio" | "visual" (default): best name match first; "radio": satellites with known radio downlinks first among equally good matches. To list satellites with a kind of downlink, set mode "radio" and put the kind in query (e.g. query "sstv"); mode itself takes only "visual" or "radio". |
get_radio_pass: Radio pass details
Radio details for one pass of a satellite over a location: its known downlink (and uplink) frequencies, the Doppler swing, when to tune to what frequency (at 10 and 30 degrees up and closest approach), and a table (at most 40 evenly spaced rows) of time, azimuth, elevation, range and receive frequency for pointing an antenna and tuning a radio. Uses the next pass above minElevation, or the one peaking nearest `time` (past or future, within 30 days of the orbital elements' epoch). A satellite that never sets here (geosynchronous) gets the next 24 hours instead. Give frequencyMHz to use a frequency other than the default downlink; the default is the most recently heard downlink when SatNOGS heard one, else the catalog's. Downlinks carry reception from SatNOGS Network observations when known: { state (heard, silent: stations tried and heard nothing, or unknown: no observations, never a sign it is dead), heardLast48h, heardLast7d, heardLast30d, failedLast30d, lastHeard }, listed most recently heard first; receptionSource names the source (CC BY-SA 4.0). Predictions from published elements: the transmitter's own frequency offset is unknown, so the curve's shape is what to compare.
| Parameter | Type | Details |
|---|---|---|
satellite (required) | string or whole number | NORAD catalog number (as a number or a string) or a name, e.g. 25544, "25544" or "iss". e.g. "so-50" or 27607. |
lat | number, -90 to 90 | observer latitude in decimal degrees, north positive (-90 to 90). Give it with lon, or give location instead. |
lon | number, -180 to 180 | observer longitude in decimal degrees, east positive and west negative (-180 to 180). |
location | string | where the observer is, when lat and lon are not given (they win when both are): a Maidenhead grid square (EN52, EN52ve, EN52ve12), coordinates in any common form ("41.88, -87.63", "41.88N 87.63W", "41°52'48"N 87°37'48"W", a Google Maps link or geo: URI), all read locally, or a place name (city, address, landmark) looked up with OpenStreetMap. Prefer lat and lon, or a grid square, when you have them: a place name is a network lookup. |
frequencyMHz | number, above 0, up to 300000 | the downlink to compute Doppler for, in MHz. Default: the satellite's default known downlink. |
time | string | a time near the wanted pass's peak (e.g. from find_passes), past or future. Default: the next pass. ISO 8601 with Z or an offset, e.g. "2026-11-14T21:00:00-06:00"; a time with no offset, e.g. "2026-11-14T21:00", is read in the observer's time zone, and the result echoes how it was read (interpretedAs). A local time the clocks skip at a daylight-saving change is moved forward, with a note. |
minElevation | number, 0 to 90 | lowest elevation that counts: a pass must climb above it, and rise and set are when it crosses it, in degrees above the horizon (0 to 90). Default 10. |
windowHours | number, above 0, up to 240 | how far ahead to look, in hours, up to 240 (10 days). Default 48. How far past the start to look for a pass. |
best_pass: Best pass
Find the best upcoming pass(es) over a location, ranked by the rating seeksat.com shows ("what's the best pass tonight?"). Give `satellite` to rank that one satellite's passes. Omit it to scan: in visual mode (default) the popular satellites plus every satellite in CelesTrak's visual group (the brightest objects in the sky, about 160, many of them spent rocket bodies), over 72 hours by default (168 at most); in radio mode every satellite with known downlinks (about a thousand), optionally only those with a downlink in `bands` or of a kind in `modes`, over 24 hours by default (72 at most). A scan reports satellitesScanned, leaves out satellites whose orbital elements are more than 14 days old at the start (skippedStaleElements) and any pass more than 14 days from its satellite's elements, counts what else it skipped, and radio passes list the satellite's downlinks. Returns `best` (the top pass) plus a `passes` array of the top-ranked options, each tagged with its satellite. Each pass has rise/peak/set times (UTC, plus riseLocal etc. on the observer's clock), peak elevation, azimuths with compass words (direction), the range at the peak (peakRangeKm), duration, brightness (magnitude, lower is brighter; peakMagnitudeEstimated means no measured magnitude is known for it, so it is a cautious guess; most of the bright satellites have a measured one, and a Starlink still flying in its launch train uses a typical train brightness, a rule of thumb rather than a measurement), and when it can be seen by eye: visibleFrom/visibleUntil (null if never on that pass) plus leavesShadow/entersShadow when it appears or fades mid-sky. rating is the rating seeksat.com shows for the pass: { word (Poor, Fair, Good, Great, Excellent), bars (1-5), level (low, ok, good), reason }. In visual mode it is how much brighter than the faintest visible star the pass gets for skyType (headroomMag), stepped down for a cloudy forecast up to 4 days ahead, and no higher than Fair when the brightness is estimated; in radio mode it is the peak height, a bar lower for each 6 dB of extra path loss when the satellite is more than 2,000 km away at the peak (8,000 km costs two bars), and no higher than Fair when SatNOGS stations tried at least 3 times in 30 days and heard nothing (the result then carries the satellite's reception and receptionSource). captureProbability (0-1) is the chance a camera captures the pass: sky darkness, height, clear-sky odds and length, with brightness playing no part; quality is its old name, the same number. Rise and set are when it crosses minElevation, not the horizon. In visual mode rise and set are the part of the pass that can be seen, so they can start or end mid-sky, and peak, peakElevationDeg and direction.peak are the highest point of that part (the whole pass may climb higher). passUrl opens that pass on seeksat.com, from that place, to hand to the user. Visual passes rank by rating bars, then a known brightness before an estimated one, then headroomMag, then captureProbability; the cloud forecast for the location is folded in where it reaches (cloudCoverPct at the peak; `weather` says whether a forecast was used). Radio scans rank satellites with a downlink a hobby receiver can tune (30 MHz to 1 GHz) ahead of the rest unless `bands` is given, then by rating bars, then how recently SatNOGS stations heard the satellite (last 48 hours, 7 days, 30 days, unknown, probably silent), then peak elevation, then captureProbability. A probably silent satellite (SatNOGS stations tried at least 3 times in 30 days and heard nothing) rates no higher than Fair; unknown is never held down. Radio rows carry the satellite's reception (its best downlink's). Downlinks carry reception from SatNOGS Network observations when known: { state (heard, silent: stations tried and heard nothing, or unknown: no observations, never a sign it is dead), heardLast48h, heardLast7d, heardLast30d, failedLast30d, lastHeard }, listed most recently heard first; receptionSource names the source (CC BY-SA 4.0). An empty result comes with a note saying why. Set chart:true to also render the winning pass's sky chart in this same call.
| Parameter | Type | Details |
|---|---|---|
satellite | string or whole number | NORAD catalog number (as a number or a string) or a name, e.g. 25544, "25544" or "iss". Omit to scan: visual mode scans the popular satellites plus CelesTrak's visual group, radio mode every satellite with known downlinks. |
lat | number, -90 to 90 | observer latitude in decimal degrees, north positive (-90 to 90). Give it with lon, or give location instead. |
lon | number, -180 to 180 | observer longitude in decimal degrees, east positive and west negative (-180 to 180). |
location | string | where the observer is, when lat and lon are not given (they win when both are): a Maidenhead grid square (EN52, EN52ve, EN52ve12), coordinates in any common form ("41.88, -87.63", "41.88N 87.63W", "41°52'48"N 87°37'48"W", a Google Maps link or geo: URI), all read locally, or a place name (city, address, landmark) looked up with OpenStreetMap. Prefer lat and lon, or a grid square, when you have them: a place name is a network lookup. |
windowHours | number, above 0, up to 240 | how far ahead to look, in hours, up to 240 (10 days). Default 72. With no satellite named, a visual scan stops at 168, and a radio scan defaults to 24 and stops at 72. |
minElevation | number, 0 to 90 | lowest elevation that counts: a pass must climb above it, and rise and set are when it crosses it, in degrees above the horizon (0 to 90). Default 10. |
limit | whole number, 1 to 20 | how many ranked passes to return, 1 to 20. Default 3. |
mode | "visual" | "radio" | "visual" (default): naked-eye passes, sunlit while the sky is dark; "radio": every line-of-sight pass, day or night. |
skyType | "city" | "suburban" | "rural" | "dark" | how dark the observer's sky is, for the visual rating as on seeksat.com: "city" (stars to magnitude 3.5), "suburban" (stars to magnitude 4.5), "rural" (stars to magnitude 5.5), "dark" (stars to magnitude 6.5). Default "suburban". |
bands | array of "hf" | "wx" | "2m" | "70cm" | "l" | "s" | "other" | radio scan only: keep satellites with a downlink in these bands: hf (3-30 MHz), wx (137 MHz weather), 2m (144-148 MHz), 70cm (420-450 MHz), l (1-2 GHz), s (2-4 GHz), other. Default: any band. |
modes | array of "fm" | "ssb" | "usb" | "lsb" | "cw" | "sstv" | "aprs" | "afsk" | "bpsk" | "gmsk" | "fsk" | "lrpt" | "apt" | "repeater" | "transponder" | "beacon" | "digipeater" | "voice" | "telemetry" | radio scan only: keep satellites with a downlink of one of these kinds, matched on its mode or label, e.g. ["fm", "apt", "sstv"]. Default: any. |
chart | boolean | true to also render the winning pass's polar sky chart (PNG) and return it in this same result. Default false. |
whats_up_now: Satellites up now
What is in the sky over a location right now, from every satellite in the catalog (about 17,000, active satellites plus CelesTrak's visual group; most debris is not in it). mode "visual" (default) lists sunlit satellites above minElevation while the sky is dark there (Sun more than about 6 degrees down), brightest first; magnitudes are measured for most of the bright satellites (McCants' observations) and estimated for the rest (magnitudeEstimated). mode "radio" lists satellites with known downlinks above minElevation, those with a downlink a hobby receiver can tune (30 MHz to 1 GHz) first, then the more recently heard by SatNOGS stations, then highest first, with their downlinks and reception. Each has azimuth with a compass word, elevation, range, sunlit, magnitude and a url to its page. Satellites whose orbital elements are more than 14 days from now are left out and counted (skippedStaleElements). For upcoming passes rather than this moment, use best_pass or find_passes.
| Parameter | Type | Details |
|---|---|---|
lat | number, -90 to 90 | observer latitude in decimal degrees, north positive (-90 to 90). Give it with lon, or give location instead. |
lon | number, -180 to 180 | observer longitude in decimal degrees, east positive and west negative (-180 to 180). |
location | string | where the observer is, when lat and lon are not given (they win when both are): a Maidenhead grid square (EN52, EN52ve, EN52ve12), coordinates in any common form ("41.88, -87.63", "41.88N 87.63W", "41°52'48"N 87°37'48"W", a Google Maps link or geo: URI), all read locally, or a place name (city, address, landmark) looked up with OpenStreetMap. Prefer lat and lon, or a grid square, when you have them: a place name is a network lookup. |
mode | "visual" | "radio" | "visual" (default): sunlit satellites in a dark sky, brightest first; "radio": satellites with known downlinks, highest first, day or night. |
minElevation | number, 0 to 90 | lowest elevation to list, in degrees above the horizon (0 to 90). Default 10. |
limit | whole number, 1 to 50 | how many satellites to return, 1 to 50. Default 10. |
identify_satellite: Identify a satellite
"What was that moving light?" Given where and when a light was seen, lists the satellites that were sunlit, above the horizon and within `tolerance` degrees of that spot, best match first, from every satellite in the catalog (active satellites plus CelesTrak's visual group). Needs the Sun at least about 3 degrees below the horizon. Say where it was with azimuth (degrees from north) or direction (a compass word such as "NE"), plus elevation (degrees above the horizon); add travel (the compass direction it was moving towards) to rank by direction of travel too. Each candidate has its azimuth, elevation, angular error, direction of travel, magnitude (estimated where none is measured, see magnitudeEstimated), name and a url to its page. Satellites whose orbital elements are more than 14 days from the sighting time are left out and counted (skippedStaleElements).
| Parameter | Type | Details |
|---|---|---|
lat | number, -90 to 90 | observer latitude in decimal degrees, north positive (-90 to 90). Give it with lon, or give location instead. |
lon | number, -180 to 180 | observer longitude in decimal degrees, east positive and west negative (-180 to 180). |
location | string | where the observer is, when lat and lon are not given (they win when both are): a Maidenhead grid square (EN52, EN52ve, EN52ve12), coordinates in any common form ("41.88, -87.63", "41.88N 87.63W", "41°52'48"N 87°37'48"W", a Google Maps link or geo: URI), all read locally, or a place name (city, address, landmark) looked up with OpenStreetMap. Prefer lat and lon, or a grid square, when you have them: a place name is a network lookup. |
time | string | time of the sighting. Default: now. ISO 8601 with Z or an offset, e.g. "2026-11-14T21:00:00-06:00"; a time with no offset, e.g. "2026-11-14T21:00", is read in the observer's time zone, and the result echoes how it was read (interpretedAs). A local time the clocks skip at a daylight-saving change is moved forward, with a note. |
azimuth | number, 0 to 360 | where it was, in degrees from north (90 = east), 0 to 360. Give this or direction. |
direction | string | where it was, as a compass word: N, NNE, NE, ... or "north-east". |
elevation (required) | number, 0 to 90 | how high it was, in degrees above the horizon (0 to 90, 90 = straight up). Required. |
travel | string | the compass direction it was moving towards, e.g. "NE". Optional, but it sharpens the match. |
tolerance | number, 1 to 45 | how far off the reported spot a match may be, in degrees, 1 to 45. Default 10. |
limit | whole number, 1 to 10 | how many candidates to return, 1 to 10. Default 5. |
Design decisions
- Deterministic core. Pass geometry, magnitude, visibility and the observer's time zone are worked out on the server with no outside calls. Only three things reach other services: geocoding a place name (OpenStreetMap), the cloud forecast (Open-Meteo and MET Norway, for
get_pass_weatherand visualbest_pass), and fetching a satellite missing from the catalog snapshot (CelesTrak). - Cron-cached, epoch-guarded TLEs. A 4-hour cron mirrors the CelesTrak catalog into Vercel Blob; requests read from that snapshot, with a rate-limited CelesTrak lookup only for satellites not in it. A flaky source returning an older element set can't clobber good data, and an upstream outage just means serving the last-known-good TLE, still SGP4-valid for days.
- Whole-catalog questions stay fast.
whats_up_nowandidentify_satellitetake one orbit step per satellite at one moment. Thebest_passscans sweep their candidates for rough passes (elevation only, skipping time a satellite cannot rise; for visual passes also sunlight and a dark sky), cache that per area and hour, and run the full engine only on the best candidates. - Measured brightness where known. Magnitudes use Mike McCants' Quicksat intrinsic magnitudes (mmccants.org) for most of the bright satellites, measured by satellite observers; a Starlink still flying in its launch train gets a typical train brightness. Anything else is assumed small and faint, flagged
peakMagnitudeEstimated/magnitudeEstimated, and rated no higher than Fair. - Engine reuse. Every pass number comes from the same unit-tested
lib/pass-finder/*modules that drive the web app, so the two faces can't drift.