A service catalog maps geography to upstreams. A point, bbox, parcel ID, address or owner query resolves to the correct jurisdictions automatically.
One URL. Every jurisdiction. Field Maps just works.
Across the United States there are well over a thousand state, county, parish and CAD services publishing public parcel data — each with its own URL, its own schema and its own outages. This service puts a single stable mount point in front of all of them.
Enumerating a thousand URLs does not scale
Wiring every county endpoint into every Field Maps device, web map and analyst notebook breaks down in four predictable ways.
URLs drift
Endpoints move or get retired, and field crews end up with silently broken layers they only discover on site.
Schemas vary
Every jurisdiction names its fields differently, so downstream code turns into a pile of case statements.
Outages cascade
One upstream going down breaks maps that did not even need that county's data.
Wiring repeats
Every new app integration redoes the same endpoint plumbing from scratch.
One mount point, four guarantees
A registry, an adapter layer and a cache — behind a URL that never changes.
Whatever field names the upstream used, the response comes back as one canonical parcel record.
Redis with an in-memory LRU in front, so repeated queries do not hammer county infrastructure.
One upstream failing degrades that jurisdiction's results, not the map.
Add one URL to the client you already use
The proxy speaks the contracts these applications were built to consume — there is nothing to install on the client side.
| Client | URL to add |
|---|---|
| ArcGIS Field Maps offline | https://parcels.example.org/parcels/FeatureServer/0 |
| ArcGIS Web Map / Map Viewer | https://parcels.example.org/parcels/FeatureServer |
| ArcGIS Pro | Add Data → URL → the FeatureServer URL above |
| Experience Builder | The FeatureServer layer URL, as any hosted layer |
| MapLibre / OpenLayers | https://parcels.example.org/parcels/ogc/collections/parcels/items?bbox=… |
| QGIS | OGC API Features → the items URL above |
Documented, executable, boring in the right way
Swagger UI is served automatically and grouped into FeatureServer, OGC API Features, Search and Admin, with a Try it out button on every route. ReDoc is served alongside it, and the OpenAPI document is available for client generation.
- FeatureServer — service descriptor, layer descriptor and the Esri
/querycontract. - OGC API Features — collection metadata and items, for MapLibre, OpenLayers and QGIS.
- Search — one high-level endpoint across every federated upstream.
- Admin — registry inspection, health and discovery-candidate review, never exposed to mapping clients.
A handful of requests covers most of it
pip install -e . uvicorn parcel_proxy.main:app --reload --port 8080 # Swagger UI open http://localhost:8080/docs # ReDoc open http://localhost:8080/redoc # Or with Docker Compose docker compose -f deploy/docker-compose.yml up -d
# Layer descriptor — what Field Maps asks for first curl '…/parcels/FeatureServer/0?f=json' # Spatial envelope query, as GeoJSON curl '…/parcels/FeatureServer/0/query?where=1=1&\ geometry=-83.0,40.0,-82.9,40.1&\ geometryType=esriGeometryEnvelope&f=geojson' # Search by parcel ID, address or owner — any jurisdiction curl '…/parcels/search?parcel_id=010-001234&state=OH' curl '…/parcels/search?address=1+main+st+columbus+oh'
Whatever the county happens to publish
Each upstream is wrapped by an adapter implementing one protocol, so adding a jurisdiction is a registry entry rather than a code change.
| Adapter | Upstream type |
|---|---|
featureserver | Esri FeatureServer |
mapserver | Esri MapServer |
ogc_features | OGC API Features |
wfs | OGC WFS |
regrid | Regrid commercial parcel API |
webscrape | Fallback for jurisdictions with no service |
Discovery, with a human in the loop
A back-office discovery tool crawls ArcGIS Online, data.gov and public search for candidate parcel endpoints, walks each ArcGIS REST directory, and stages the parcel-shaped ones for review. Nothing it finds can reach a live map on its own.
- Candidates are forced to
enabled: falseby a model validator — a constraint, not a convention. - Promotion writes a disabled entry; an operator must then flip the flag and reload. Two human acts, minimum.
- The runtime query path imports nothing from the discovery package, so a discovery failure cannot break the proxy.
- The walker respects
robots.txt, caps per-host concurrency, throttles, and refuses to retry on 429 or 503.
* The discovery tool is partially shipped — models, configuration, the staging store and robots.txt enforcement are implemented; the walker, seed harvest, scraper, pipeline, admin endpoints and CLI are still being built. The runtime query path is unaffected either way.
Point it at your service territory
Tell us the states and counties your crews actually work in, and we will demo the federation against those upstreams.