API

The service exposes its own endpoints, the ones its app uses. They are public and available without a key, but they are not a product: they may change along with the app.

Available addresses

They all return JSON and support ETag — a repeat request carrying If-None-Match gets a 304 with no body.

Live vehicles

/api/live-vehicles returns the vehicles currently running on a line, or the vehicle with a given fleet number, or one vehicle with exactly the given key.

&source=gdynia narrows it to one city.

Gdynia. The answer holds that vehicle or none (never a vehicle whose number merely starts the same way), and &source= must not contradict the city in the key (400).

(the nastepne field, described below).

adds the vehicle's whole trip, from the first stop to the last (the trasa and poz fields, described below). It does not combine with stops (400) — whoever asks for the whole trip does not need the nearest stops separately.

Pass exactly one of line, fleet and key; a bad parameter gives 400. Fleet numbers of Gdańsk and Gdynia can overlap, so every vehicle carries a key (for Gdynia with a prefix: gdynia:3081) and always states its city in zrodlo. When the same bus appears in both city feeds (the same fleet number and the same line), only the Gdańsk record is returned, because it has the direction, the stop and the delay; lacznie counts after that merge.

The answer holds dostepny, pobrano (the GPS snapshot time in ms), lacznie (how many vehicles match) and pojazdy (at most 60, sorted by city and fleet number). A vehicle has key, zrodlo, numer, linia and, when the server can determine them, rodzaj (see "Kind of vehicle" below), kierunek, doKad (its destination), przystanek (the nearest stop on its route), miejsce (where exactly it is, see "Where the vehicle is" below), start (the scheduled start of its current trip, UTC in ISO form, for example 2026-10-01T04:31:00Z), d (the delay in seconds) and wiek (the age of the position in seconds relative to pobrano). Fields that cannot be determined are left out, never guessed — Gdynia, for one, publishes neither delays nor trip start times. With no GPS data at all the answer is dostepny: false with a reason.

Next stops and the arrival time

With ?key=…&stops=N the vehicle also has a nastepne field: up to N nearest stops ahead of the vehicle, in route order, each as {id, nazwa, eta}. The field appears only when the server knows the vehicle's direction and its position along the route, and a stop leaves the list once the vehicle has passed it. eta is an estimate in Polish time as HH:MM (minute resolution): the scheduled time of that trip at the stop plus the vehicle's current delay. It is an approximation, not a promise — the app labels it „ok." ("approx.").

eta is left out, and the stop stays in the list, when the server cannot determine it, rather than giving a guessed value: for Gdynia (no timetable and no delays in its data), for a trip that is not in the timetable, for a vehicle without a delay, for the last stop of the trip, and for a stop whose time has already passed. On Polish public holidays no stop has an eta, because the timetable knows only weekdays, Saturdays and Sundays, and a time taken from such a day would be wrong. A stops answer also depends on the timetable file, so its ETag changes with it.

The whole trip

With ?key=…&route=1 the vehicle has, instead of nastepne, two fields: trasa — all stops of the trip in route order, each as {id, nazwa, eta} — and poz, the zero-based index of the first stop that is still ahead of the vehicle. Stops with an index below poz have already been passed and never have an eta; trasa[poz] is the stop the vehicle is heading to, and when poz equals the length of trasa nothing is ahead any more. The stops ahead, trasa.slice(poz), get their eta by the same rules as in nastepne (one function in the code) and with the same exceptions (Gdynia, holidays, a trip outside the timetable, no delay, the last stop, a time that has passed), so trasa.slice(poz) always agrees with a stops=10 answer at the same moment. The fields appear only when the server knows the direction and the trip; when it does not, the vehicle has neither, and nothing is guessed. The answer then has no nastepne either. The ETag of a route answer differs from the one with stops and the one with neither, because the content differs, and it changes with the timetable file.

Where the vehicle is

When the server knows the vehicle's direction and its position along the route, the vehicle has a miejsce field in every kind of answer (line, fleet, key, with or without stops and route). It has one of two forms:

side (a bus waiting at a stop stands just before or just past it);

behind it, do the first one ahead of it (the stop it is heading for).

With ?key=…&route=1 the field also carries i, the zero-based index into trasa of the stop it is at (na), or of the stop behind it (z). It is computed from the same list and the same 25 m rule as poz, so they always agree: for z/do, i is poz - 1 and trasa[poz] is do; for na, i is below poz. Without trasa there is no i.

miejsce is left out, not guessed, when there is no direction or the vehicle is off the route, and in two more cases that have no honest wording: BEFORE the first stop (no stop is behind it, so "on the way from..." would invent one) and PAST the last stop by more than 25 m (nothing is ahead). przystanek stays as it was — the nearest stop, behind or ahead — for clients that read it. When a trip's own list of stops is known (stops or route with a timetable run), the stops are those of the trip, so a stop the trip does not serve is never named; otherwise they are the stops of the route variant.

Kind of vehicle

The rodzaj field is one of three values: autobus (bus), tramwaj (tram) or trolejbus (trolleybus). The server reads it from the route type (route_type) in the GTFS timetable of the city the vehicle belongs to, so it is the kind of the LINE, not of the vehicle itself: in the data of 2026-10-01 the Gdańsk lines 2-12 are trams, the Gdynia lines 21-33, 710 and 723 are trolleybuses, and every other line of both cities is a bus. It is the one source that covers both cities — Gdynia does not publish a vehicle database. A side effect: a bus put on a tram line (or a diesel bus on a trolleybus line) is described as the kind of its line.

rodzaj is left out, not guessed, when the vehicle has no line number, when the timetable does not know the line, when routes with the same number have different types in the timetable, and when the topology file has not been built yet. The field depends on the same topology file as the direction and the stops, so the ETag of the answer already covers it: it changes with the file, not with every GPS snapshot.

What is in the analytics database

Historical data, the basis for the statistics. The list below is generated straight from the database schema, so it cannot drift away from it.

tablecolumns
gps_snapshotid, last_update, fetched_at, vehicles, a, both, from, that, number, two, source
gps_courseid, route_id, trip_id, scheduled_start, route_short, headsign
gps_vehiclesource, vehicle_id, vehicle_code, first_seen, last_seen
gps_positionsnapshot_id, vehicle_id, course_id, service, generated, lat, lon, speed, direction, delay, gps_quality
dep_sightingid, stop_key, dep_key, source, line, headsign, scheduled, trip_start, vehicle_code, vehicle_id, channel, first_seen, last_seen, samples, first_eta, last_eta, last_delay, last_status, gone_at, gone_reason
dep_delay_samplesighting_id, at, delay, eta, status
agg_godzinagodzina_utc, source, klasa, wersja_regul, probek, mediana, p90, srednia, ponad5min, ponad15min, przed1min, przed2min
agg_liniagodzina_utc, source, line, wersja_regul, probek, srednia, mediana, ponad5min, przed1min, przed2min, slupkow
ruch_godzinagodzina_utc, kategoria, zadan
ruch_wizytygodzina_utc, wizyt
ruch_sciezkagodzina_utc, sciezka, zadan
ruch_klientgodzina_utc, klasa, zadan, wizyt
push_subskrypcjaendpoint, p256dh, auth, utworzono, ostatnio_ok, bledy
push_alarmendpoint, alarm_id, o_ms, dodano, wyslano
ruch_dziendzien, wizyt, zadan
ruch_szkicklucz, szkic
agg_przystanekgodzina_utc, stop_key, wersja_regul, probek, srednia, ponad5min, przed1min, linii
agg_gps_godzinagodzina_utc, source, pozycji, pojazdow, predkosc_sr, predkosc_med, stojacych, jakosc_zla, bez_kursu
agg_dryfgodzina_utc, horyzont_min, wersja_regul, kursow, mediana_abs, p90_abs, mediana_znak, srednia_znak, odrzuconych, stabilnych, wczesniej60, pozniej60
agg_widmagodzina_utc, klasa, literowa, wersja_regul, znikniec
odcinekid, line, grupa_a, grupa_b, dystans_prosty
agg_odcinekgodzina_utc, odcinek_id, wersja_regul, przejazdow, czas_sum, dystans_sum, czas_med, czas_p90, predkosc_med
agg_predkosc_liniagodzina_utc, line, wersja_regul, przejazdow, odcinkow, czas_sum, dystans_sum, czas_med, predkosc_med, odrzuconych
plk_zatrzymaniepociag, stacja, plan, WITHOUT, shifts, happened, text, IT, plan_ms, nazwa_stacji, faktyczny, feature, would, an, Unlike, rows, faktyczny_ms, opoznienie_min, potwierdzone, odwolane, computing, observation, numer, rail, number, different, przewoznik, to, The, generated_at
agg_odjazd_liniagodzina_utc, source, line, wersja_odjazdow, odjazdow, przed_czasem, przed_czasem_2, przeczekal, o_czasie, spoznionych, niedopasowanych, odchylenie_med, przyjazd_odchylenie_med, odchylenie_hist
agg_odjazd_grupagodzina_utc, source, grupa, wersja_odjazdow, odjazdow, przed_czasem, przed_czasem_2, przeczekal, o_czasie, spoznionych, niedopasowanych, odchylenie_med
agg_odjazd_linia_grupagodzina_utc, source, line, headsign, grupa, wersja_odjazdow, odchylenie_hist
agg_plk_godzinagodzina_utc, przewoznik, wersja_plk, zatrzyman, opoznionych, wczas, mediana_min, p90_min, of, not, hist
agg_plk_donegodzina_utc, wersja_plk, computed_ms
agg_doneaggregate, godzina_utc, wersja, computed_ms
agg_postojsource, stop_id, wersja_regul, probek, histogram, mediana_s
agg_postoj_globalnysource, wersja_regul, probek, histogram, mediana_s

None of these tables holds information about the people using the service — they describe only vehicles, services and stops. Details: Privacy.

Where to get the source data

If you are building something of your own, go straight to the cities' APIs rather than to this service: that is where the data originates, and your requests will not depend on somebody else's layer staying available.