TransitRadar

Why a train on the map is never exactly where the train is

There is no GPS on a British passenger train that you can read. The dots on the live map are driven by the signalling system, and once you know how that works, everything odd about them stops being odd.

A train on our live map is not being tracked. It is being described — and the difference explains almost every question people ask about it.

Berths, not coordinates

Britain's railway is divided into train describer areas: 194 of them in the data we hold. Within an area, the track is divided into berths, each roughly the section of line between one signal and the next. A signaller's screen shows a train's four-character headcode sitting in a berth. As the train passes a signal, the equipment steps the headcode from one berth into the next and publishes a message saying so.

That message is the entire basis of the map. It says, in effect, “headcode 1S23 has moved from berth A to berth B in area M1”. It contains no latitude, no longitude, no speed and no heading. Turning it into a dot means looking berth B up in a reference dataset called SMART, which gives the location code beside that berth, and then looking that code up again to get coordinates.

So the first thing to understand is that a berth is an area, not a point. The dot marks the section of line the train is somewhere within. On a dense approach to a terminus a berth might be a couple of hundred metres; out on a rural single line it can be several miles. The dot is accurate to a signal section, and no better.

Why half of all movements don't move the dot

Here is a number that surprised us when we measured it. The SMART dataset we load describes 34,194 berth steps covering 22,359 distinct berths — but those berths resolve to only 3,766 distinct locations. That is an average of very nearly six berths sharing one location code.

The consequence is unavoidable: when a train steps between two berths that share a location, the message arrives, the train genuinely moved, and the dot does not budge. Roughly half of all steps are like this. A train can report four movements in a row while appearing frozen on screen, because all four berths hang off the same location code.

This is also why the dots advance in jumps rather than gliding. A real position update is a discrete event at a signal, not a continuous stream. We smooth this by moving each dot forward between reports at the pace its timetable implies — anchored to the last real observation, so a train running twenty minutes late stays twenty minutes late rather than being quietly dragged back onto schedule.

A step is not quite the moment it names

A berth step tells you a train crossed a signal. It does not tell you the train has arrived — a train entering a platform berth is still braking towards the stop. SMART records this too: alongside the location, each step carries a berth offset, the typical number of seconds between that step and the arrival or departure it stands for. Every one of the 34,194 records we load carries one, ranging from ten minutes early to nine minutes late.

We settled which way round it works from the data rather than a specification. When the records are split by the kind of event they describe, 98% of arrivals carry a positive offset, with a median of about seventy-six seconds, while departures lean slightly negative. That is exactly what you would expect if the step comes first and the arrival follows — the seventy-six seconds is the run in from the signal to the platform.

The offset belongs to the step, not the berth. Nearly two thirds of berths are entered by steps that disagree about their offset, and about one step in seven cannot be told apart from another step with a different offset using only what the live feed carries. Those get no correction at all — not an average, and not zero, because a guessed correction is worse than none. Measured on the live map in September 2026, a little over half of the dots moved on between reports carried an offset we could trust, and nine in ten of those were shifted by more than fifty metres, typically by a few hundred.

Whole lines with no dots at all

SMART maps only about half of what the describers actually report. This is not a gap we can close: some lines simply have no berths recorded in it. The Ribble Valley line is the example we keep coming back to — Ramsgreave, Langho, Whalley and Clitheroe have no berth mappings whatsoever, so a train working that route used to freeze at the last mapped berth before it and sit there until it reappeared somewhere else entirely.

That looked exactly like a bug, and it took a while to accept that it was the data. The fix was not to try harder with SMART but to add a second kind of dot: for trains the describers cannot place, we position from the booked timetable instead, interpolating between calling points. Those dots are honest about being estimates. They are also the reason the map does not have holes in the shape of entire branch lines.

The same headcode, in two places, legitimately

A headcode is not an identity. It identifies a train to a signaller, within an area, and it is reused freely across the country. In a single sweep of the live map we found fifteen pairs of genuinely different trains sharing a headcode at the same moment — not duplicates, not errors, just different services that happen to be 1A20 in different parts of Britain.

Early on we keyed the map's animation on the headcode alone, and the result was a dot that slid hundreds of miles across the country between refreshes as it was matched to the wrong train. Identity on the map is now the describer area and the headcode together.

Knowing which dot is which is only half of it; knowing whose train it is was harder. The describer carries a headcode and nothing else, and in one Birmingham viewport we measured, most of the headcodes on screen had been run by more than one operator that day — one by ten different companies. So a dot is no longer attributed by headcode alone: every run that could be under way with that headcode is considered, and the dot is given to the one whose booked calling points come nearest to where it actually is. Where two candidates cannot be told apart, the dot is left without an operator rather than given a guess.

There is a related trap worth knowing if you ever read raw feeds: 0B00 is not a train. It is a placeholder used network-wide for stock movements with no allocated headcode, and treating it as an identifier merges hundreds of unrelated movements into one imaginary service.

What the colours are actually telling you

Each dot carries two independent signals. The fill is the operator's brand colour, so you can pick out one company's services at a glance. The ring is lateness.

Unknown lateness has its own colour and is deliberately never green. About an eighth of the trains on the map at any time are freight, which the passenger forecast feed does not cover at all, so we have no delay figure for them. Colouring those green would be stating that they are on time, which we do not know. A separate colour says “no information”, which is the truth.

A dot also fades after three minutes without a report, and is dropped entirely after fifteen. A stationary train and a train we have lost track of should never look the same.

What this means when you use the map

  • A dot that has not moved is not necessarily a stopped train. It may have stepped between berths sharing a location, or the reporting may have gone quiet — check whether it has faded.
  • Position is accurate to a signal section. Do not read a dot's exact placement as the front of the train.
  • A missing train is usually an unmapped berth, not a cancelled service. The departure board is authoritative on whether a train is running; the map is authoritative on roughly where it is.
  • Freight is on the map but has no lateness data. The ring colour tells you which trains we can speak to.

Where this comes from

The berth steps are Network Rail's TD feed; the berth-to-location mapping is SMART; the location-to-coordinates step uses CORPUS and our own station and junction database. All are listed with their licences on where the data comes from, and how it works covers the rest of the site's mechanics. If you want the same data programmatically, the API serves it.