GNSS Seed Data API

GET Public, no key needed JSON index, binary files Rebuilt every 10 minutes

The files from the GNSS seed data page, for programs and devices: ready-made MGA ephemeris for GPS, Galileo, BeiDou, GLONASS and QZSS, so a receiver gets its first fix from cold in seconds rather than waiting to read the orbits from the sky. They are rebuilt every 10 minutes from the live broadcast ephemeris streams.

They are plain files, so there is no key and no limit beyond a sensible schedule: the data only changes every 10 minutes. For devices without TLS, every file is also served over plain http:// at altimetercloud.com, without the www: the www address sends plain http on to https. The URLs in the index start https://www.altimetercloud.com, so a device without TLS swaps that for http://altimetercloud.com.

GEThttps://www.altimetercloud.com/api/gnss/the current index

The same file is at https://www.altimetercloud.com/ubx/index.json.

The index

It lists every file of the current build: what is in it, how many satellites of each system, and the size and URL of every file and chunk. Shortened here to one bundle and one single system:

{
  "version": 1,
  "generated": "2026-10-13T07:03:38Z",
  "format": "mga-eph",
  "ttl": 7200,
  "source": "Caster BCEP00BKG0 (BKG, live stream)",
  "chunk_size": 1000,
  "satellites": {"gps": 32, "gal": 30, "bds": 36, "glo": 23, "qzss": 5},
  "bundles": [
    {
      "name": "gnss_all",
      "systems": ["gps","gal","bds","glo","qzss"],
      "gnss": "gps,gal,bds,glo,qzss",
      "missing": [],
      "svcount": 126,
      "satellites": {"gps": 32, "gal": 30, "bds": 36, "glo": 23, "qzss": 5},
      "raw": {
        "url": "https://www.altimetercloud.com/ubx/gnss_all.bin",
        "size": 10076
      },
      "zlib": {
        "url": "https://www.altimetercloud.com/ubx/gnss_all.z",
        "size": 7412,
        "chunks": 8,
        "chunk_urls": ["https://www.altimetercloud.com/ubx/gnss_all.z.0", ...]
      },
      "lzma": {
        "url": "https://www.altimetercloud.com/ubx/gnss_all.lzma",
        "size": 6532,
        "chunks": 7,
        "chunk_urls": ["https://www.altimetercloud.com/ubx/gnss_all.lzma.0", ...]
      }
    },
    ...
  ],
  "single": [
    {
      "name": "gnss_glo",
      "systems": ["glo"],
      "gnss": "glo",
      "missing": [],
      "svcount": 23,
      "satellites": {"glo": 23},
      "raw":  {"url": "https://www.altimetercloud.com/ubx/gnss_glo.bin",  "size": 1288},
      "zlib": {"url": "https://www.altimetercloud.com/ubx/gnss_glo.z",    "size": 979},
      "lzma": {"url": "https://www.altimetercloud.com/ubx/gnss_glo.lzma", "size": 913}
    },
    ...
  ]
}
FieldMeaning
generatedWhen this build was made, UTC.
formatAlways mga-eph: every file is MGA ephemeris frames, one after another.
ttlHow long, in seconds, a device can go on using a download before it should fetch again.
sourceWhere this build's ephemeris came from: a live stream, or one of the fallback files.
chunk_sizeThe size of every chunk but the last, in bytes.
satellitesHow many satellites of each system this build has.
bundles, singleThe ready-made mixes and the one-system files, each entry as below.

Each bundle or single system

FieldMeaning
nameThe file name without its ending. The files are name.bin, name.z and name.lzma, and for a bundle the chunks name.z.0, name.z.1... and name.lzma.0...
systemsThe systems the file is made to hold: gps, gal, bds, glo, qzss.
gnssThe systems this build actually has in it, comma separated.
missingSystems the file is made to hold that this build has none of. GLONASS is only in the live streams, so a build from a fallback file has none.
svcount, satellitesThe satellites in the file, in all and by system.
raw, zlib, lzmaEach file's url and size in bytes; bundles add chunks and chunk_urls. null when a single system has no satellites in this build, and its files are taken down until a build has some.

The files

BundleSystems
gnss_allGPS, Galileo, BeiDou, GLONASS, QZSS
gnss_gps_gal_bds_gloGPS, Galileo, BeiDou, GLONASS
gnssglobalGPS, Galileo, BeiDou. The file our Jupiter uses; also described on its own by /ubx/currenturls.json and /ubx/currenturls.txt, as it always has been.
gnss_gps_gloGPS, GLONASS
gnss_gps_galGPS, Galileo

The single systems are gnss_gps, gnss_gal, gnss_bds, gnss_glo and gnss_qzss, as whole files only. To make a mix of your own, join their raw contents in any order.

EndingEncoding
.binRaw MGA frames.
.zA zlib stream (RFC 1950): 2-byte header, DEFLATE, Adler-32 trailer.
.lzmaLZMA-alone, as xz --format=lzma writes: 5 bytes of properties (lc 3, lp 0, pb 2, 64 KB dictionary), the 8-byte uncompressed length, then the data. The smallest.

Chunks. A bundle's .z and .lzma also come in 1000-byte pieces for devices with a small HTTP buffer. Fetch .0, .1, .2 and on, joining them, until a piece is shorter than 1000 bytes or the server answers 404, then decompress the whole in one go.

The frames

Every frame is a complete message (the two sync bytes B5 62, class, id, 2-byte length, payload, 2-byte checksum), and every payload starts with 0x01, the ephemeris type. Send them to the receiver as they are.

SystemMessageClass, idBytes a frame
GPSMGA-GPS-EPH0x13 0x0076
GalileoMGA-GAL-EPH0x13 0x0284
BeiDouMGA-BDS-EPH0x13 0x0396
QZSSMGA-QZSS-EPH0x13 0x0576
GLONASSMGA-GLO-EPH0x13 0x0656
  • Give the receiver the time first (MGA-INI-TIME-UTC), or it cannot place the orbits and turns the frames away.
  • With acknowledgements turned on, each frame is answered by MGA-ACK. That says the receiver took the message in, not that it has checked the orbit inside it.
  • GLONASS gives its orbit as a position and velocity that is good for about 15 minutes either side of its time, so it helps most from a fresh download. Satellites flagged unhealthy are left out.

Example

In Python: read the index, download everything as LZMA, and split it into frames.

import lzma, requests

idx = requests.get("https://www.altimetercloud.com/api/gnss/").json()
b = next(x for x in idx["bundles"] if x["name"] == "gnss_all")
data = lzma.decompress(requests.get(b["lzma"]["url"]).content, format=lzma.FORMAT_ALONE)

frames, i = [], 0
while i < len(data):
    n = data[i + 4] | (data[i + 5] << 8)     # the payload length
    frames.append(data[i:i + 8 + n])
    i += 8 + n
print(len(frames), "frames", idx["satellites"])

Fetching sensibly

  • A build lands every 10 minutes, so there is no point asking more often. The files are served with Last-Modified and ETag, so a request with If-Modified-Since or If-None-Match gets a short 304 when nothing has changed.
  • Each build replaces the files where they are. A download that spans a build can join pieces of two, so check the result decompresses (the LZMA header carries the length, the zlib trailer a checksum) and fetch again if it does not.
  • Cache busting. The data folders are served with caching turned off, so a request should always get the current build. To be certain nothing along the way, such as a proxy or a mobile network’s cache on plain http://, hands you an old copy, add a random number or the Unix time to each URL, as in https://www.altimetercloud.com/ubx/gnss_all.lzma?1791849600, and the same on every chunk. The server ignores it; it only makes each request look new.

Data credit

Broadcast ephemeris from the IGS Real-Time Service, by the International GNSS Service (IGS) and its contributing organizations: the merged broadcast ephemeris streams of BKG (Federal Agency for Cartography and Geodesy, Germany), CAS (Chinese Academy of Sciences) and JPL (NASA Jet Propulsion Laboratory), served on BKG's Ntrip caster, with BKG's broadcast navigation files as the fallback. If you use these files, please acknowledge the IGS and its contributing organizations too.

We place our packaging of the data in the public domain: use the files freely, commercial or otherwise. They come as they are, with no promise of availability or accuracy, so do not make them a sole safety-critical input.