Reverse Geocoding Using Python

Get addresses from coordinates using Python

Converting coordinates to addresses using Python and Geoapify API
Converting coordinates to addresses using Python and Geoapify API

Reverse geocoding is the process of converting geographic coordinates (latitude and longitude) into human-readable addresses. It's an essential feature for location-based applications — from mapping tools and logistics systems to travel apps and data analysis workflows. You can learn more about how it works in our article What is Reverse Geocoding?

In this tutorial, you'll learn how to perform reverse geocoding in Python using the Geoapify Reverse Geocoding API. Specifically, we will:

  • Introduce the Reverse Geocoding API and its capabilities
  • Show how to make API calls from Python
  • Explain how to handle batch reverse geocoding while respecting rate limits
  • Provide a GitHub example you can download and integrate into your own project

This guide is ideal for developers looking to turn geographic coordinates into useful address data efficiently and reliably.

Reverse Geocoding API Overview

The Geoapify Reverse Geocoding API allows you to convert geographic coordinates (latitude and longitude) into readable addresses or specific location elements such as city, street, or country. This is especially useful for mapping applications, geospatial analysis, and location-based services.

If you're not sure how reverse geocoding differs from regular geocoding, check out our comparison: Geocoding vs. Reverse Geocoding.

Important: To use the script, you’ll need a Geoapify API key. You can get a free API key by signing up on Geoapify.com — no credit card required.

One of the key features of the API is the type parameter, which lets you specify the location type you want to retrieve. This allows you to fine-tune the response to your needs and minimize unnecessary data.

Supported type values:

  • country – Get the country name and code
  • state – Get the state or administrative region
  • city – Get the city or town
  • postcode – Get the postal code
  • street – Get the street name
  • amenity – Get nearby amenities like buildings or landmarks

Examples

Get Full Address from Latitude and Longitude

https://api.geoapify.com/v1/geocode/reverse?lat=52.21802590162346&lon=20.978425629505296&format=json&apiKey=YOUR_API_KEY

This request returns a complete address, including street, postcode, city, and country - "Biblioteka PW filia DS Babilon, Kopińska 12/16, 02-315 Warsaw, Poland"

Get Only the Street Name

https://api.geoapify.com/v1/geocode/reverse?lat=52.21802590162346&lon=20.978425629505296&format=json&type=street&apiKey=YOUR_API_KEY

Returns only the street name near the specified coordinates - "Węgierska, 02-318 Warsaw, Poland"

Get the Postcode from Coordinates

https://api.geoapify.com/v1/geocode/reverse?lat=52.21802590162346&lon=20.978425629505296&type=postcode&apiKey=YOUR_API_KEY

This request returns only the postal code associated with the specified coordinates - "02-318 Warsaw".

Get the City from Coordinates

https://api.geoapify.com/v1/geocode/reverse?lat=52.21802590162346&lon=20.978425629505296&type=city&apiKey=YOUR_API_KEY

Returns the city name — in this case, Warsaw.

Response Example

Here's a simplified JSON response from a full reverse geocoding query for the provided coordinates:

{
  "results": [
    {
      "country": "Poland",
      "country_code": "pl",
      "state": "Masovian Voivodeship",
      "city": "Warsaw",
      "postcode": "02-318",
      "suburb": "Ochota",
      "quarter": "Stara Ochota",
      "iso3166_2": "PL-14",
      "datasource": {
        "sourcename": "openstreetmap",
        "attribution": "© OpenStreetMap contributors",
        "license": "Open Database License",
        "url": "https://www.openstreetmap.org/copyright"
      },
      "result_type": "postcode",
      "lon": 20.979253,
      "lat": 52.2175982,
      "distance": 73.74792796920609,
      "formatted": "02-318 Warsaw, Poland",
      "address_line1": "02-318 Warsaw",
      "address_line2": "Poland",
      "category": "administrative",
      "timezone": {
        "name": "Europe/Warsaw",
        "offset_STD": "+01:00",
        "offset_STD_seconds": 3600,
        "offset_DST": "+02:00",
        "offset_DST_seconds": 7200,
        "abbreviation_STD": "CET",
        "abbreviation_DST": "CEST"
      },
      "plus_code": "9G426X9H+2P",
      "plus_code_short": "6X9H+2P Warsaw, Masovian Voivodeship, Poland"
    }
  ],
  "query": {
    "lat": 52.21802590162346,
    "lon": 20.978425629505296,
    "plus_code": "9G426X9H+69"
  }
}

You can extract the desired fields from the properties object, depending on whether you need a full address, a specific element like the street name, or nearby amenities.

The Geoapify Reverse Geocoding API also includes a distance field in the response. This value represents the distance (in meters) between the input coordinates you provided and the location that was matched and returned by the API.

This is helpful because:

  • It lets you assess how close the returned result is to your input coordinates.
  • If you're dealing with approximate or noisy GPS data, you can use the distance to filter or validate results.
  • For batch processing, you can rank multiple results based on proximity or discard results that exceed a specific distance threshold.

How to Call the Reverse Geocoding API with Python

To call the Geoapify Reverse Geocoding API in Python, you can use the popular requests library to send HTTP GET requests. Below is a reusable function that demonstrates how to query the API and handle different response types.

Reverse Geocoding Python Code Example

import requests
import logging

logger = logging.getLogger(__name__)

GEOAPIFY_API_URL = "https://api.geoapify.com/v1/geocode/reverse"

def reverse_geocode(api_key, lat, lon, country_filter=None, result_type=None, output_format="json"):
    params = {
        'lat': lat,
        'lon': lon,
        'apiKey': api_key,
        'format': output_format
    }
    if country_filter:
        params['filter'] = 'countrycode:' + country_filter
    if result_type:
        params['type'] = result_type

    try:
        response = requests.get(GEOAPIFY_API_URL, params=params)
        if response.status_code == 200:
            data = response.json()
            if 'results' in data:
                return data['results'][0]
            elif 'features' in data:
                return data['features'][0]
            else:
                return {}
        elif response.status_code == 429:
            logger.warning("Rate limit exceeded. Too many requests.")
            return {}
        else:
            logger.error(f"Error: {response.status_code} for coordinates: ({lat}, {lon})")
            return {}
    except Exception as e:
        logger.error(f"Exception occurred: {e} for coordinates: ({lat}, {lon})")
        return {}

How It Works

  • The function accepts coordinates (lat, lon), your API key, and optional parameters:

    • country_filter — to restrict results to a specific country.
    • result_type — to request a specific location type (e.g. street, city, postcode).
    • output_format — defaults to "json", but you can change it to "geojson" if needed.
  • It builds a request to the API with those parameters and parses the result.

  • It handles:

    • Valid results (results or features fields in the response),
    • Rate limit errors (429 Too Many Requests), and
    • Unexpected exceptions with helpful logging.

This structure makes it easy to integrate into larger applications and handle a variety of use cases with minimal changes.

Reverse Geocoding Multiple Coordinates

The previous example shows how to reverse geocode a single coordinate. However, in practice, you often need to reverse geocode a list of coordinates — for example, GPS traces, delivery stops, or datasets with location data.

When sending many API requests, it’s important to respect rate limits to avoid overloading the API or being temporarily throttled. Geoapify’s Reverse Geocoding API has soft rate limits, which means brief spikes are tolerated, but consistent overuse may result in slower responses or blocked access. You can find tips on handling rate limits in our Geocoding in Python tutorial – API Limits section.

Sending Requests in Batches with Python

To efficiently process multiple coordinates, you can group them into batches and use ThreadPoolExecutor from the concurrent.futures module to send parallel requests. Add a short sleep between batches to control the request rate.

Here’s how it works:

from concurrent.futures import ThreadPoolExecutor, wait, ALL_COMPLETED
from time import sleep
import json

# Request results asynchronously for each batch
tasks = []
with ThreadPoolExecutor(max_workers=10) as executor:
    for batch in coordinates:
        logger.info(batch)
        for coord in batch:
            if order == 'latlon':
                lat, lon = map(float, coord.split(','))
            elif order == 'lonlat':
                lon, lat = map(float, coord.split(','))
            tasks.append(
                executor.submit(reverse_geocode, api_key, lat, lon, country_filter, result_type, output_format)
            )
        sleep(1)  # Wait 1 second between batches to respect RPS limits

# Wait for all tasks to complete
wait(tasks, return_when=ALL_COMPLETED)

Explanation

  • ThreadPoolExecutor manages concurrent requests to speed up processing.
  • sleep() pauses execution between batches to help stay within rate limits.
  • Results are gathered after all requests complete using wait().

This method allows you to scale your reverse geocoding process while being API-friendly and efficient.

GitHub Example: Reverse Geocoding in Python

To help you get started quickly, we’ve prepared a working example in our Geoapify Maps API Code Samples repository. The script demonstrates how to reverse geocode a list of coordinates and write the results to a file.

Setup Instructions

1. Clone the Repository

git clone https://github.com/geoapify/maps-api-code-samples.git
cd maps-api-code-samples/python/

2. Create a Virtual Environment (Optional)

We recommend using a virtual environment to manage dependencies cleanly:

python -m venv env
source env/bin/activate  # On Windows: env\Scripts\activate

3. Install Dependencies

Install required packages using pip:

pip install requests

Running the Reverse Geocoding Script

Once dependencies are installed, navigate to the reverse geocoding folder and run the script:

cd reverse-geocoding
python reverse_geocode.py --api_key YOUR_API_KEY --input input.txt --output output.ndjson --order latlon
  • The script reads coordinates from input.txt (one per line).
  • It performs reverse geocoding using the Geoapify API.
  • The results are saved to output.ndjson in NDJSON format — one JSON object per line, ideal for large or streamed datasets.

You can modify the --order parameter to match your coordinate format (latlon or lonlat) and optionally adjust filtering options in the script.

This example is a great starting point for integrating reverse geocoding into your own Python-based tools or data processing pipelines.

Conclusion

Reverse geocoding is a key component in many location-based applications, helping you transform raw geographic coordinates into meaningful address data. With the Geoapify Reverse Geocoding API and a few lines of Python code, you can easily retrieve full addresses or specific location elements like streets, postcodes, or cities.

In this tutorial, you learned how to:

  • Call the Reverse Geocoding API from Python
  • Handle batch requests efficiently while respecting rate limits
  • Use filtering options like type and countrycode
  • Work with real-world code examples, including one from GitHub

Ready to get started? Sign up for a free API key and try it with your own data — no credit card required.

Read more

FAQ

What is reverse geocoding?

Reverse geocoding is the process of converting geographic coordinates (latitude and longitude) into a human-readable address or location description, such as a city name, street, or postal code.

How do I perform reverse geocoding in Python?

You can use the Geoapify Reverse Geocoding API along with the Python 'requests' library to send coordinate-based queries and retrieve address data. This tutorial provides complete code examples and setup instructions.

Can I reverse geocode multiple coordinates at once?

Yes. You can process a list of coordinates in batches using Python’s ThreadPoolExecutor to send requests in parallel while respecting API rate limits. Our GitHub example demonstrates this approach in detail.

What is the 'type' parameter used for?

The 'type' parameter lets you specify which part of the address to return — for example, 'street', 'city', or 'postcode'. This helps reduce response size and extract only the data you need.

Do I need an API key to use the Geoapify Reverse Geocoding API?

Yes. You can get a free API key by signing up at www.geoapify.com. No credit card is required.

What happens if I exceed the rate limit?

If you exceed the limit (5 requests per second on the Free plan), you may receive a 429 Too Many Requests error. To avoid this, space out requests and follow the guidelines in our API rate limit section.

Where can I find the full reverse geocoding example in Python?

You can find a complete working example with input/output file support on GitHub.