DEV Community

Alex Spinov
Alex Spinov

Posted on

OpenStreetMap Has a Free API — Build Maps Without Google (No Key, No Billing)

Google Maps Charges $7 Per 1000 Requests. OpenStreetMap Charges $0.

OpenStreetMap (OSM) is the Wikipedia of maps. Community-maintained, completely free, and it has multiple APIs for geocoding, routing, and tile rendering.

Geocoding (Address to Coordinates)

Nominatim is the free geocoder:

import requests

def geocode(address):
    r = requests.get("https://nominatim.openstreetmap.org/search", params={
        "q": address, "format": "json", "limit": 1
    }, headers={"User-Agent": "MyApp/1.0"})
    if r.json():
        result = r.json()[0]
        return {"lat": result["lat"], "lon": result["lon"], "display": result["display_name"]}
    return None

location = geocode("Eiffel Tower, Paris")
print(location)
# {lat: 48.858, lon: 2.294, display: Tour Eiffel, Paris, France}
Enter fullscreen mode Exit fullscreen mode

Reverse Geocoding (Coordinates to Address)

def reverse_geocode(lat, lon):
    r = requests.get("https://nominatim.openstreetmap.org/reverse", params={
        "lat": lat, "lon": lon, "format": "json"
    }, headers={"User-Agent": "MyApp/1.0"})
    return r.json().get("display_name")

address = reverse_geocode(40.7128, -74.0060)
print(address)  # New York, NY, USA
Enter fullscreen mode Exit fullscreen mode

Routing (Directions)

OSRM (Open Source Routing Machine) provides free routing:

def get_route(start_lat, start_lon, end_lat, end_lon):
    url = f"http://router.project-osrm.org/route/v1/driving/{start_lon},{start_lat};{end_lon},{end_lat}"
    r = requests.get(url, params={"overview": "false"})
    route = r.json()["routes"][0]
    return {
        "distance_km": round(route["distance"] / 1000, 1),
        "duration_min": round(route["duration"] / 60, 1)
    }

route = get_route(48.8566, 2.3522, 51.5074, -0.1278)  # Paris to London
print(route)  # {distance_km: 456.3, duration_min: 285.7}
Enter fullscreen mode Exit fullscreen mode

Search for Places (POI)

def find_places(query, lat, lon, radius=1000):
    overpass_url = "http://overpass-api.de/api/interpreter"
    overpass_query = f"""
    [out:json];
    node["amenity"="{query}"](around:{radius},{lat},{lon});
    out body 5;
    """
    r = requests.get(overpass_url, params={"data": overpass_query})
    return [{"name": e.get("tags", {}).get("name", "Unknown"),
             "lat": e["lat"], "lon": e["lon"]}
            for e in r.json()["elements"]]

cafes = find_places("cafe", 48.8566, 2.3522)
for c in cafes:
    print(f"{c[name]} ({c[lat]}, {c[lon]})")
Enter fullscreen mode Exit fullscreen mode

Google Maps vs OpenStreetMap

Feature Google Maps OpenStreetMap
Geocoding $5/1000 req Free
Directions $5-10/1000 req Free
Map tiles $7/1000 loads Free
API key Required + billing Not needed
Data ownership Google Community
Self-hosting No Yes

When to Use Google Maps Instead

  • You need Street View
  • You need real-time traffic data
  • You need indoor maps
  • Your app requires guaranteed SLA

For everything else, OSM is free and good enough.


More API tutorials on GitHub.


More from me: 10 Dev Tools I Use Daily | 77 Scrapers on a Schedule | 150+ Free APIs

Top comments (0)