osm2geojson

July 18, 2026 ยท View on GitHub

Test package PyPI version License: MIT Python versions

Convert OpenStreetMap and Overpass API data (JSON or XML) to GeoJSON or Shapely geometries.

Output closely matches osmtogeojson (the JavaScript converter used by overpass-turbo), verified by a compatibility suite.

Highlights:

  • Assembles full geometries from raw OSM elements: multipolygon and boundary relations, routes, ways and POI nodes
  • Accepts Overpass JSON, Overpass XML and plain OSM XML, including out center and out bb responses
  • Produces a GeoJSON FeatureCollection or a list of Shapely shapes with properties โ€” ready for GIS pipelines or rendering
  • Ships a command-line tool (osm2geojson)
  • Lightweight: the only dependencies are shapely and requests

Installation

pip install osm2geojson

Requires Python 3.8+.

Try the 1.0 release candidate. Version 1.0 changes the produced GeoJSON (matching osmtogeojson) and cleans up the API. Regular installs are unaffected until the final release; to test it now:

pip install --pre --upgrade osm2geojson

See the CHANGELOG and MIGRATION_NOTES.md for what changed - and please report any unexpected output differences.

Quick start

import osm2geojson

# Fetch data from the Overpass API and convert it
xml = osm2geojson.overpass_call('rel(448930); out geom;')
geojson = osm2geojson.xml2geojson(xml)

# Or convert a local OSM/Overpass file
with open('data.osm', encoding='utf-8') as f:
    geojson = osm2geojson.xml2geojson(f.read())

Command-line interface

osm2geojson map.osm map.geojson -i 2    # convert a file, pretty-printed
osm2geojson data.json -                 # Overpass JSON to stdout

Run osm2geojson --help for all options (input format autodetect/override, indentation, custom area/polygon definitions, verbosity).

API reference

Conversion functions

FunctionInputOutput
json2geojson(data, **options)Overpass JSON (dict or str)GeoJSON FeatureCollection
xml2geojson(xml_str, **options)OSM/Overpass XMLGeoJSON FeatureCollection
json2shapes(data, **options)Overpass JSON (dict or str)list of Shape objects
xml2shapes(xml_str, **options)OSM/Overpass XMLlist of Shape objects

All conversion functions accept these optional keyword-only parameters:

ParameterTypeDefaultDescription
filter_used_refsboolTrueDrop elements that are only used as parts of other features (False returns everything)
log_levelstrNoneSet the library logger level for this call ('DEBUG', 'INFO', ...); None leaves your logging configuration untouched
area_keysdictNoneCustom area key definitions (defaults from areaKeys.json)
polygon_featureslistNoneCustom polygon feature whitelist/blacklist (defaults from polygon-features.json)
raise_on_failureboolFalseRaise ConversionError on geometry conversion failure instead of skipping the element

Conversion functions never modify the data passed to them.

Shape objects

json2shapes/xml2shapes return dictionaries pairing a Shapely geometry with the OSM properties:

{
    'shape': Point | LineString | Polygon | ...,  # Shapely geometry
    'properties': {
        'type': 'node' | 'way' | 'relation',
        'tags': { ... },
        'id': 123,
        ...
    }
}

Use shape_to_feature(shape_obj, properties) to turn a Shape object back into a GeoJSON Feature.

overpass_call(query, **options)

Execute an Overpass QL query and return the raw response text:

result = osm2geojson.overpass_call('[out:json];node(50.746,7.154,50.748,7.157);out;')

Optional keyword-only parameters:

ParameterTypeDefaultDescription
endpointstroverpass-api.deOverpass API endpoint URL
timeoutfloat180Timeout in seconds for each HTTP request
retriesint5Retries on rate limiting (429), transient server errors (5xx), timeouts and connection errors; other errors fail immediately (0 disables retrying)
retry_delayfloat5Seconds to sleep between attempts

Examples

Query the Overpass API and convert to GeoJSON

import osm2geojson

query = """
[out:json];
(
  node["amenity"="restaurant"](50.746,7.154,50.748,7.157);
  way["amenity"="restaurant"](50.746,7.154,50.748,7.157);
);
out body geom;
"""

result = osm2geojson.overpass_call(query)
geojson = osm2geojson.json2geojson(result)

Work with Shapely geometries

import json
import osm2geojson

with open('overpass.json', encoding='utf-8') as f:
    data = json.load(f)

shapes = osm2geojson.json2shapes(data)

for shape_obj in shapes:
    geometry = shape_obj['shape']      # Shapely object
    osm_tags = shape_obj['properties']['tags']
    print(f"Type: {geometry.geom_type}, Tags: {osm_tags}")

Upgrading to 1.0

Version 1.0 changed the produced GeoJSON (to match osmtogeojson) and made converter options keyword-only. See the CHANGELOG for what changed and MIGRATION_NOTES.md for upgrade help.

Development

git clone https://github.com/rapkin/osm2geojson.git
cd osm2geojson

make setup       # one-command setup (installs deps + pre-commit hooks)
make all         # format, lint and test (do this before committing!)

Submodules (osm-polygon-features, id-area-keys) are optional - they are only needed to regenerate the bundled JSON data (update-osm-polygon-features.sh). Fetch them with git submodule update --init when needed.

License

MIT License

Credits

Developed by rapkin

Uses data from: