OpenCage Geocoding API Python Tutorial
Topics covered in this tutorial
- General Background
- Video tutorials
- installing the OpenCage Python module
- Reverse geocoding
- Forward geocoding
- Geocoding a list of places
- Making requests in parallel
- SSL issues
- Alternatives
- Further reading
Background
The code examples below will use your geocoding API key once you log in.
Video Tutorials
If you prefer video, over on YouTube we have two 10 minute tutorial videos showing how to geocode using Python, one tutorial video focused on reverse geocoding, the other explaining forward geocoding.
Install the OpenCage Python module
Compatible with Python version 3.9 and newer.
Install using pip
pip3 install opencage
Conda users: use pip inside your conda environment.
Install using uv
uv pip install opencage
Add the module to your pyproject.toml:
uv add opencage
Convert coordinates to location (reverse geocoding)
from opencage.geocoder import OpenCageGeocode
from pprint import pprint
apikey = 'YOUR-API-KEY'
geocoder = OpenCageGeocode(apikey)
results = geocoder.reverse_geocode(44.8303087, -0.5761911)
pprint(results)
# [{'components': {'ISO_3166-1_alpha-2': 'FR',
# 'ISO_3166-1_alpha-3': 'FRA',
# 'ISO_3166-2': ['FR-NAQ', 'FR-33'],
# '_category': 'building',
# '_normalized_city' : 'Bordeaux',
# '_type': 'building',
# 'city': 'Bordeaux',
# 'continent': 'Europe',
# 'country': 'France',
# 'country_code': 'fr',
# 'county': 'Gironde',
# 'house_number': '11',
# 'local_authority': 'Bordeaux Métropole',
# 'municipality': 'Bordeaux',
# 'political_union': 'European Union',
# 'postcode': '33000',
# 'region': 'Metropolitan France',
# 'road': 'Rue Sauteyron',
# 'state': 'New Aquitaine',
# 'state_code': 'NAQ',
# 'suburb': 'Victoire'},
# 'confidence': 10,
# 'formatted': '11 Rue Sauteyron, 33800 Bordeaux, France',
# 'geometry': {'lat': 44.8303087, 'lng': -0.5761911}}]
# print just the suburb
print(results[0]['components']['suburb'])
# safer with .get() in case the field is missing:
print(results[0]['components'].get('suburb'))
# Victoire
Set output language, error handling
from opencage.geocoder import OpenCageGeocode
from opencage.geocoder import InvalidInputError, RateLimitExceededError, UnknownError
apikey = 'YOUR-API-KEY'
geocoder = OpenCageGeocode(apikey)
try:
results = geocoder.reverse_geocode(44.8303087, -0.5761911, language='de', no_annotations='1')
if results and len(results):
print(results[0].get('formatted'))
# 11 Rue Sauteyron, 33800 Bordeaux, Frankreich
else
print('No result found.')
except RateLimitExceededError as ex:
print(ex)
# You have used the requests available on your plan.
except InvalidInputError as ex:
# this happens for example with invalid unicode in the input data
Lookup coordinates from address (forward geocoding)
from opencage.geocoder import OpenCageGeocode
apikey = 'YOUR-API-KEY'
geocoder = OpenCageGeocode(apikey)
query = u'Bosutska ulica 10, Trnje, Zagreb, Croatia'
# no need to URI encode query, module does that for you
results = geocoder.geocode(query)
print(u'%f;%f;%s' % (results[0]['geometry']['lat'],
results[0]['geometry']['lng'],
results[0]['components']['country_code']))
# 45.797095;15.982453;hr
# annotations might not present (for example when no_annotations='1')
timezone = results[0].get('annotations', {}).get('timezone', {}).get('name')
if timezone:
print(timezone)
# Europe/Belgrade
Improving accuracy with countrycode and bounds
For ambiguous queries, use
countrycode
to restrict results to a specific country, or
bounds
to limit results to a bounding box (min longitude, min latitude, max longitude, max latitude).
Both can be combined.
from opencage.geocoder import OpenCageGeocode
apikey = 'YOUR-API-KEY'
geocoder = OpenCageGeocode(apikey)
# restrict to United States by country code
results = geocoder.geocode('Berlin')
print(results[0]['formatted'])
# Berlin, Germany
results = geocoder.geocode('Berlin', countrycode='us')
# Berlin, New Hampshire, United States of America
# restrict to a bounding box covering New Hampshire
results = geocoder.geocode('Berlin', bounds='-73.63,42.52,-69.52,45.60')
Batch geocode a file of addresses
Create a file containing addresses, or use one of our example address lists.
Madrid, Spain
Milan, Italy
Berlin, Germany
München, Deutschland
Pappelallee 78/79, 10437 Berlin, Germany
import sys
from opencage.geocoder import OpenCageGeocode, RateLimitExceededError
apikey = 'YOUR-API-KEY'
geocoder = OpenCageGeocode(apikey)
addressfile = 'addresses.txt'
try:
with open(addressfile,'r') as f:
for line in f:
address = line.strip()
results = geocoder.geocode(address, no_annotations='1')
if results and len(results):
longitude = results[0]['geometry']['lng']
latitude = results[0]['geometry']['lat']
print(u'%f;%f;%s' % (latitude, longitude, address))
# 40.416705;-3.703582;Madrid, Spain
# 45.466797;9.190498;Milan, Italy
# 52.517037;13.388860;Berlin, Germany
# 48.1371079;11.5753822;München, Deutschland
# 52.5432379;13.4142133;Pappelallee 78/79, 10437 Berlin, Germany
else:
sys.stderr.write("not found: %s\n" % address)
except IOError:
print('Error: File %s does not appear to exist.' % addressfile)
except RateLimitExceededError as ex:
print(ex)
# You have used the requests available on your plan.
Running many parallel queries
By default the Python Request HTTP library will only run one HTTP request, even if you wrap the logic inside multipthreading or asynchronous calls. At low level it will block other HTTP requests.
Instead you should use the asyncio library for HTTP requests. We prepared a more complex code example of python parallel batch requests using a queue and task workers. We've used variations of the script for lists of 10s of millions of addresses.
Our Python module comes with a command line interface (CLI) tool, see our full geocoding CLI tutorial.
Before you start geocoding at high volume, please read our guide to geocoding large datasets where we explain various strategies and points to consider.
Storing your API key securely
It's best practice to avoid putting your API key directly in source code. Read it from an environment variable instead:
import os
from opencage.geocoder import OpenCageGeocode
apikey = os.environ.get('OPENCAGE_API_KEY')
geocoder = OpenCageGeocode(apikey)
SSL work-around
If you have trouble accessing the OpenCage API with https, e.g. issues with OpenSSL libraries in your environment, then you can set the 'http' protocol instead. Please understand that the connection to the OpenCage API will no longer be encrypted.
from opencage.geocoder import OpenCageGeocode
apikey = 'YOUR-API-KEY'
geocoder = OpenCageGeocode(apikey, 'http')
Alternative Python modules
- Jupyter Notebooks can execute Python. Our Jupyter Notebook geocoding tutorial explains how to use the OpenCage geocoding API in Jupyter.
- Denis Carriere's Python Geocoder library has a sub-library and command line interface for OpenCage API. Here is a further code sample.
- geopy has an OpenCage method and supports advanced proxy configuration, logging, asynchronous (parallel) querying and distance calculations.