Open, federated, self-hostable live-conditions data commons — the dynamic layer that complements OpenStreetMap's static map: road incidents, roadworks, closures, hazards, and congestion today; transit occupancy, place busyness, and a crowd-sourced reporting layer later.
OpenConditions aggregates public road-condition feeds into one canonical model, stores them in PostGIS, and re-emits them in the standard wire formats the wider ecosystem already speaks. Its reference consumer is OpenMapX — the hungry first-party consumer every prior project in this space lacked — but the data and the libraries are designed to be reused anywhere.
Road domain, v0.1:
- Live feeds: NDW (NL), Die Autobahn (DE), Fintraffic / Digitraffic (FI), DriveBC (CA), WZDx (US) and
511NY (US-NY, with its winter road conditions and message signs, granted under NYSDOT's access agreement),
spanning DATEX II, Open511, WZDx GeoJSON and Castle Rock CARS — plus government point-sensor traffic flow (speed,
volume, occupancy, level of service) from 24 flow feeds, among them Fintraffic (FI), WebTRIS (GB),
NYC DOT (US-NY), NDW (NL), OHGO (US-OH, keyed) and Trafikverket (SE, keyed), as measurement sites and
their readings. Congestion is computed from a self-derived free-flow baseline (85th
percentile), with native reference speeds where a feed ships one and OSM
maxspeedas a day-one proxy. See docs/speed-coverage.md. - Emitters: a paged record API, GeoJSON, JSON-LD, TraFF, DATEX II, Valhalla exclusions, and an SSE stream — all public, rate-limited, and bbox-filterable.
- Graph binding: road situations, and effects with a location of their own, are bound to the directed
OSM segment spine (
way_id:f|bspans with confidence); see docs/graph-binding.md. - Fuel domain: station fuel prices from Tankerkönig (DE), E-Control (AT), Prix Carburants (FR), MITECO (ES) and OpenStreetMap, as features with per-grade price components; the Tankerkönig, E-Control and OpenStreetMap feeds are fetched on demand for the area a read asks about.
- Parking domain: car parks, garages and lorry parks with their spaces by kind, live occupancy and tariffs from 23 feeds in 13 countries, among them MobiData BW (DE, with Toll Collect's lorry parks Germany-wide), Mobidrom NRW (DE), RDW and NDW (NL), SBB and Basel (CH), HDB (SG) and OpenStreetMap, read on demand. A publisher's plain GeoJSON, JSON or CSV table is mapped in the catalogue with no code; see feeds/README.md.
- Charging domain: charging sites with their charge points (EVSEs), connectors, live charge-point status and tariffs from 24 feeds (a 25th, Poland's EIPA, waits for its registration): access points and registers covering 21 countries (OCPI from NDW, MobiData BW and Via Lietuva; OICP from BFE; DATEX II from DGT and NAP Slovenija; the Bundesnetzagentur register, the French IRVE base, AFDC for the US and Canada, NOBIL for Norway and Sweden, and more), Open Charge Map and OpenStreetMap, the last two read on demand.
- Cameras domain: traffic, weather and landscape cameras with their views and each view's latest still
from 21 feeds: Digitraffic (FI), Trafikverket (SE), Statens vegvesen (NO), Vegagerðin (IS), DGT (ES),
Ontario 511 (CA), the Transport Department (HK), Live Traffic NSW (AU), TDX (TW), TfL (GB), Caltrans, the
National Park Service, ODOT TripCheck, 511NY and five IBI 511 states (US), and Windy and OpenStreetMap, the last two
read on demand. Each feed whose records carry proxyable stills declares the hosts they come from, which
GET /sourcesserves for a consumer's image proxy (osm-camerasandus-nps-camerasdeclare none), and an OpenStreetMap webcam links with the publisher's camera it stands beside. - Hazards domain: weather and civil-protection warnings as CAP alerts in every language they carry, from
the NWS (US), ECCC (CA), DWD (DE) and MeteoAlarm (38 more European countries); wildfire perimeters and incidents from NIFC (US) and burnt areas from EFFIS (EU); satellite
fire pixels from NASA FIRMS (VIIRS and MODIS, worldwide) and EUMETSAT (Sentinel-3 SLSTR, worldwide, with a
free account the operator logs in once), one
fire.frpreading each, swept 72 hours after detection and counted in cells byGET /observations/grid; NOAA HMS smoke (North America); USGS earthquakes, read by time window; and NASA EONET and GDACS natural events: 12 keyless feeds and one with a login. - Weather domain: road weather stations with their current air and road-surface measurements from Fintraffic
Digitraffic (FI): temperature, dew point, humidity, visibility, wind, precipitation, and per surface sensor the
surface state, temperatures, freezing point, water film, salt, friction, snow and ice, each sensor its own
channel and series; each station's maintenance state as its
device.status. - Vehicles domain: where Finland's state road maintenance vehicles are and what they do, from
Digitraffic's maintenance tracking each minute: anonymous
vehicle.positionreadings (the publisher names no vehicle) with the bearing, the plough and spreader the tasks imply, the task codes and a trail of the last ten minutes, one per vehicle: each stands until the vehicle moves on, or ten minutes from its report. - Border domain: land border crossings and the wait in each inspection queue, from CBP (every U.S. port on the Canadian and Mexican borders, by lane type and programme) and CBSA (the Canada-bound waits at the 30 busiest crossings). Neither publishes coordinates: a vendored table places each port at its crossing's Wikidata item (CC0), so the two agencies' features of one crossing share a place.
- OpenMapX integration: ships as an installable extension (the ingest and contributions services, serving the roads, fuel, parking, charging, cameras, hazards, weather, vehicles and border domains); OpenMapX reads all but weather, vehicles and border through its built-in OpenConditions integration.
- TMC location tables: publishers that send Alert-C location codes instead of coordinates are placed against the published national table (Germany's LCL 22.0, CC BY 4.0), behind a strict table-version guard. Dutch VILD 6.13.A adds a separate coarse point fallback, excluded from routing and XML exports. See docs/tmc-location-tables.md and the Polish/Dutch location research.
- OpenLR resolver: built and tested, but dormant — no open feed currently carries OpenLR (the open feeds use coordinates or Alert-C/TMC). It activates when an OpenLR-bearing source is configured.
Road events are stored as model situations, each with its effects and revisions (model, storage); flow feeds write measurement sites as model features and their speeds, volumes and levels of service as model observations (the latest reading per series, a partitioned history and hourly rollups). Three layers:
packages/ reusable libraries (Apache-2.0 unless noted)
model/ kernel types, taxonomy registry, validation, JSON Schema and docs generation
model-registry/ the assembled production registry and its published JSON Schemas
model-*/ one registry module per domain: roads, parking, fuel, charging, hazards, border,
facilities, maritime, vehicles, weather
core/ canonical model, severity, freshness, read helpers, DB schema/migrations (./server)
ingest-framework/ feed descriptors, credentials, guarded fetch, catalogue resolvers, licences, domain plugins
roads/ road parsers (DATEX II / Open511 / WZDx and more), the roads domain, TMC location tables
bind/ event → segment resolver + evaluation corpus
parking/ fuel/ charging/ cameras/ hazards/ weather/ vehicles/ border/
each domain's parsers and its ingest domain
datex2/ DATEX II decoding shared by the domains (XML, publications, value decoders)
ocpi/ OCPI wire types, decoders and dialects
openlr/ OpenLR binary decode + resolver client
publishers/ outbound emitters (GeoJSON, JSON-LD, TraFF, DATEX II, SSE, Valhalla)
storage/ the source catalogue and the record writer (AGPL-3.0)
contrib-core/ the signed, portable crowd report and sub-claim format
federation/ instance identity: Ed25519 keys, the actor document, the pinned peers registry
probe-spike/ non-production feasibility spike for private probe submission (AGPL-3.0)
services/ deployable services (AGPL-3.0)
ingest/ Fastify: fetch → parse → write records, bind + public record API and routing outputs; ships
the OpenMapX service.json so `repos add` can install it
contributions-api/ crowd report intake and evidence-state recompute
federation/ the instance actor document and peer discovery
openlr-resolver/ Python/FastAPI OpenLR → geometry map-matcher (dormant)
The ingest service owns and migrates the conditions schema itself, idempotently, on boot.
Requires Node 24+ and pnpm 11+ (and a reachable PostGIS).
pnpm install
pnpm build
DATABASE_URL=postgres://postgres:postgres@localhost:5432/openconditions \
pnpm --filter @openconditions/ingest devThe service applies its migrations, starts polling the enabled feeds, and serves on :4100.
Road situations, measurement sites and facilities (features), tariffs (offers) and readings
(observations) are served as model records (model). Collections take the same
filters (bbox=west,south,east,north, kind, type, domain, source, origin, at; situations
also minSeverity, horizonDays, subtype, a time window from/to that includes ended ones, and
simplify for lighter geometry; readings property and since) and are paged by a keyset cursor: follow
next (JSON) or the Link: rel="next" header (DATEX II) until there is none.
TraFF is a complete bounded feed, with no page controls or continuation header. canonical=1 serves the
canonical view: one feature per cluster of features several sources describe, and the fused reading of
a property several sources or the crowd report. Everything is rate-limited; GET /openapi.json
describes it all, and storage says what each route reads.
| Endpoint | Content |
|---|---|
GET /situations |
Situations as JSON records {records, next} |
GET /situations.geojson, .jsonld |
The same as GeoJSON, or GeoJSON-LD (SOSA/Schema.org @context) |
GET /situations/{id} |
One situation with its evidence and graph binding |
GET /features |
Features as JSON records; components with expand=components, the canonical view with canonical=1 |
GET /features.geojson, .jsonld |
The same as GeoJSON, or GeoJSON-LD |
GET /features/{id} |
One feature with its components and its canonical cluster (a canonical id serves the cluster) |
GET /offers, /offers/{id} |
Tariffs as JSON records, or one |
GET /observations/latest |
The reading in effect of every series, paged by series |
GET /observations/grid |
Current numeric readings of one property since an instant, counted, summed and maximised per cell |
GET /observations |
One series (subject, property, qualifiers, from, to): raw readings, or hourly/daily rollups beyond the raw retention |
GET /history/{class}/{id} |
A record's revisions and what changed |
GET /traff.xml |
Complete TraFF 0.8 feed (up to 20,000 candidate situations / 32 MiB; narrow filters on 413) |
GET /datex2/situations.xml |
DATEX II v3 SituationPublication, one record per effect (status) |
GET /stream |
Server-Sent Events: live situations, then each change and removal |
GET /valhalla/exclusions.json |
Valhalla exclude_locations / exclude_polygons and speed caps |
GET /segments/conditions.json |
Bound effects in force, keyed by directed OSM way spans (routing feed) |
GET /taxonomy, /schemas/{path} |
The running registry and its JSON Schemas |
GET /coverage |
Live records per country, kind and access mode; live series per property |
GET /status |
health (unlimited) |
The GeoJSON-LD variants extend the GeoJSON-LD 1.1 context and
need a JSON-LD 1.1 processor. Each feature's id is its record's https://openconditions.org/id/
IRI, and the record id stays in properties.id.
OpenConditions installs into an OpenMapX deployment as an extension, in one step:
pnpm openmapx ext install openconditionsThis registers both services (ingest and contributions API) at their pinned tag and starts them. It installs no
integration code: OpenMapX's built-in openconditions integration reads them once OPENCONDITIONS_URL (and, for
Tankerkönig (DE), E-Control (AT) and OpenStreetMap fuel stations, for the share-alike parking and charging
feeds, for the Windy, OpenStreetMap and US 511 cameras and for MeteoAlarm's warnings,
OPENCONDITIONS_OPERATOR_TOKEN) is set in OpenMapX's .env. It feeds the roads domain (conditions overlay,
routing avoidance, live traffic), the fuel domain (fuel stations and prices), the parking domain (car parks and
their occupancy), the charging domain (charging sites, charge-point status and tariffs), the cameras domain (the
webcam layer and its stills) and the hazards domain (the weather alert, wildfire, earthquake and natural event
overlays).
OpenMapX passes a community service's container.environment to the container verbatim, so the services'
configuration is configSchema fields: set the database URL (and the contributions API's grant secret and
reviewer token) once as secrets in the admin services panel. Until they are set, both services stop at boot
and their containers restart in a loop; once they are, apply the change and the services start. Set any
setting there, or as SERVICE_OPENCONDITIONS_INGEST_<KEY> in OpenMapX's .env. Settings kept in OpenMapX's
.env are applied with pnpm openmapx services start openconditions-ingest (which resets every setting saved
only in the admin form, so keep all of them in one place). Settings saved in the form are applied with
Save & Apply. See
services/ingest/README.md.
See OpenMapX's Building an external extension guide for the full flow. OpenMapX's built-in OpenConditions
integration reads roads situations, routing evidence, fuel features, parking sites, charging sites, cameras and
hazards from the ingest's API into the map overlay, routing avoidance, fuel search, the parking layer, the EV
charging layer, the webcam layer and the hazard overlays. A request carrying Authorization: Bearer <OPENCONDITIONS_OPERATOR_TOKEN> reads in the operator scope, which withholds nothing; without it a read is
public-scope. Reads with a bbox fetch stale on-demand feeds first, waiting at most
OPENCONDITIONS_ON_DEMAND_DEADLINE_MS (default 3000). See services/ingest/README.md.
Pseudonymous contributors can augment the official feeds with signed road-condition reports. Read what crowd reporting is — and the guarantees we deliberately do NOT make before relying on it.
- npm:
@openconditions/core,@openconditions/roads(prebuilt, public) - images:
ghcr.io/openconditions/ingest,ghcr.io/openconditions/openlr-resolver - static archive: a nightly GeoParquet snapshot of the published view — the mirrorable artifact for seeding a new instance or backfilling a federation peer (license/expiry/tombstone enforced, no raw crowd evidence, no probe staging)
Releases are cut by tagging vX.Y.Z (see .github/workflows/release.yml).
A two-license split — see LICENSING.md:
- AGPL-3.0-or-later — the ingest service (the deployable network commons server).
- Apache-2.0 — the reusable
@openconditions/*libraries and the standalone OpenLR resolver. - Source data keeps each feed's upstream license (CC0 / CC-BY / dl-de/by / OGL / …); OSM-derived data is ODbL. Every record carries its licence; public exports (the public API, federation, the archive and the emitters) carry only records whose licence grants redistribution and is not share-alike, and never a record of a source whose terms restrict it.
See CONTRIBUTING.md for development setup and the quality bar, SUPPORT.md for where to ask questions, and the Code of Conduct. Contributions are accepted under a CLA.