Notes from the development team

When the map has no speed sign: estimating limits under Circular 31/2019

The OpenMapTiles schema has no maxspeed tag, so with free tiles close to 100% of speed limits have to be estimated. Here is where those estimates can go wrong.

Update, October 2026: estimating limits from the road class is now off by default — when no source knows the limit for sure, the sign stays blank and no alert fires. You can turn it back on in Settings → “Estimate when data is missing”. The app now also supports reading OBD-II, so the remarks below about OBD-II being out of scope are historical.

The original plan was simple: read the maxspeed tag from OpenStreetMap and show it. That plan ran into trouble at the very first step.

Public map tiles do not include maxspeed

The OpenMapTiles schema — the standard used by OpenFreeMap and most free tile providers — has no maxspeed field in its transportation layer. Even when a road is fully tagged in raw OSM, that information does not make it into the tile. This is not a gap in the data; the schema leaves it out on purpose to keep tiles small.

There is also a second, deeper problem: many Vietnamese roads in OSM do not have a maxspeed tag in the first place. So even if you build your own tiles, most roads still have nothing to read.

Estimating from the law

Circular 31/2019/TT-BGTVT sets maximum speeds by area and road type. For cars and trucks up to 3.5 t:

  • Inside a built-up area — 60 km/h on a divided road or a one-way road with two or more lanes, 50 km/h on an undivided two-way road or a single-lane one-way road.
  • Outside a built-up area — 90 km/h on a divided road, 80 km/h on an undivided two-way road.

VietnamSpeedRules implements exactly this table. But applying it requires two pieces of information the map does not state directly.

First estimate: the built-up area

On the road, a built-up area is marked by the R.420 and R.421 signs, but OSM does not record these consistently. Instead, the app estimates it from the tile's landuse layer — residential land use counts as built-up. It is an approximation, and it can be wrong at the edges of towns.

Second estimate: a cap based on road class

Taken literally, the law allows 80 km/h on any undivided road outside an urban area — even a three-metre-wide concrete village lane. The app does not go that far: it caps the limit according to the road class on the map, so small roads get a lower limit than the law allows.

This is deliberate. A warning that comes a little early may be mildly annoying; one that comes too late is no help at the very moment it matters.

Why every estimated value carries a tilde

On the limit sign, an estimated value is always labelled ~ estimated. Drivers need to be able to tell 'the map says this road is 60' apart from 'the app estimates this road is 60', because the two deserve different levels of trust. Removing the distinction would mean presenting an estimate as fact.

The long-term fix

V1.5 will build tiles with Planetiler using a custom profile that includes maxspeed. That will not fill the gaps where OSM itself has no data, but it moves every road that is already tagged from 'must be estimated' to 'can be read' — and since OBD-II is out of scope, the accuracy of the speed warning is the very core of this app.