How to Geocode Addresses in Python: Complete Guide with Code Examples
Geocode addresses in Python with working code examples. Single, batch (10K/request), reverse geocoding, pandas DataFrames. Free SDK, 1,000 requests/day.
Geocoding in Python means converting street addresses into latitude and longitude coordinates programmatically. You feed in "350 5th Ave, New York" and get back 40.7484, -73.9857 — two numbers that place that address on a map, enable distance calculations, and unlock spatial analysis.
This guide covers every method — from geocoding a single address to batch-processing 100,000 rows from a CSV file with pandas DataFrames. Every code example uses the csv2geo Python SDK and works out of the box. Copy, paste, run. The free tier gives you 1,000 API requests per day with no credit card.
Prerequisites
Install the CSV2GEO Python SDK and get your free API key:
pip install csv2geo
Get your API key from csv2geo.com/api-keys — takes 30 seconds, no credit card required.
from csv2geo import Client
client = Client(api_key="your_api_key_here")Method 1: Geocode a Single Address
The simplest case. One address in, one coordinate pair out.
from csv2geo import Client
client = Client(api_key="geo_live_k8x2m9...")
# Geocode a single address
result = client.geocode(
"1600 Amphitheatre Parkway, Mountain View, CA 94043"
)
print(f"Latitude: {result.latitude}")
print(f"Longitude: {result.longitude}")
print(f"Confidence: {result.confidence}")
print(f"Address: {result.formatted_address}")Output:
Latitude: 37.4224764
Longitude: -122.0842499
Confidence: 0.98
Address: 1600 Amphitheatre Pkwy, Mountain View, CA 94043, US
The confidence score (0 to 1.0) tells you how certain the geocoder is about the match. Above 0.90 is a high-quality rooftop result. Below 0.5 means the geocoder fell back to city or postal code level.
Structured Input for Better Accuracy
When you have address components separated, pass them individually for more precise results:
result = client.geocode(
street="1600 Amphitheatre Parkway",
city="Mountain View",
state="CA",
postcode="94043",
country="US"
)Structured input eliminates ambiguity. "Springfield" exists in 34 US states — adding state and ZIP narrows it to exactly one.
Method 2: Geocode a List of Addresses
When you have a handful of addresses, loop through them:
from csv2geo import Client
client = Client(api_key="geo_live_k8x2m9...")
addresses = [
"10 Downing Street, London, UK",
"1600 Pennsylvania Ave, Washington, DC",
"Champs-Élysées 101, Paris, France",
"Alexanderplatz 1, Berlin, Germany",
"Shibuya Crossing, Tokyo, Japan",
]
for address in addresses:
result = client.geocode(address)
print(f"{address}")
print(f" → {result.latitude}, {result.longitude} (confidence: {result.confidence})")
print()This works for dozens of addresses. For hundreds or thousands, use the batch method below — it is dramatically faster.
Method 3: Batch Geocoding (Up to 10,000 at Once)
CSV2GEO’s batch endpoint processes up to 10,000 addresses per API request. Instead of 10,000 individual API calls, you make one.
from csv2geo import Client
client = Client(api_key="geo_live_k8x2m9...")
# Batch geocode — up to 10,000 addresses per request
addresses = [
{"street": "350 Fifth Avenue", "city": "New York", "country": "US"},
{"street": "Friedrichstraße 43-45", "city": "Berlin", "country": "DE"},
{"street": "1 Harbour Street", "city": "Sydney", "country": "AU"},
{"street": "5 Avenue Anatole France", "city": "Paris", "country": "FR"},
{"street": "Piazza del Colosseo 1", "city": "Rome", "country": "IT"},
]
results = client.batch_geocode(addresses)
for r in results:
print(f"{r.formatted_address}")
print(f" → {r.latitude}, {r.longitude} (confidence: {r.confidence})")Why Batch Matters
| Approach | 10,000 Addresses | API Calls | Time |
|---|---|---|---|
| One-by-one loop | Loop with rate limiting | 10,000 | 30–60 minutes |
| Batch API | Single request | 1 | 30–90 seconds |
That is not a typo. Batch processing is 20–40x faster because it eliminates network round-trip overhead for each address.

Method 4: Reverse Geocoding (Coordinates to Address)
You have coordinates and need the address. Common with GPS data, mobile apps, and IoT devices.
from csv2geo import Client
client = Client(api_key="geo_live_k8x2m9...")
# Reverse geocode: coordinates → address
result = client.reverse_geocode(latitude=48.8584, longitude=2.2945)
print(f"Address: {result.formatted_address}")
print(f"Street: {result.street}")
print(f"City: {result.city}")
print(f"Country: {result.country}")For a deep dive into reverse geocoding, see our reverse geocoding guide.

Working with Pandas DataFrames
Most Python geocoding projects start with a CSV or Excel file loaded into pandas. Here is how to geocode a DataFrame efficiently.
import pandas as pd
from csv2geo import Client
client = Client(api_key="geo_live_k8x2m9...")
# Load CSV into pandas
df = pd.read_csv("properties.csv")
print(f"Loaded {len(df)} addresses\n")
# Build batch request from DataFrame
address_list = [
{"street": row["address"], "city": row["city"],
"state": row["state"], "country": "US"}
for _, row in df.iterrows()
]
# Geocode all at once
results = client.batch_geocode(address_list)
# Add coordinates back to DataFrame
df["latitude"] = [r.latitude for r in results]
df["longitude"] = [r.longitude for r in results]
df["confidence"] = [r.confidence for r in results]
# Save enriched CSV
df.to_csv("properties_geocoded.csv", index=False)
print(df[["address", "latitude", "longitude", "confidence"]].to_string())
Handle Large Files in Chunks
For files with more than 10,000 rows, process in chunks to stay within the batch limit:
import pandas as pd
from csv2geo import Client
client = Client(api_key="geo_live_k8x2m9...")
CHUNK_SIZE = 5000
chunks = pd.read_csv("large_dataset.csv", chunksize=CHUNK_SIZE)
first_chunk = True
for i, chunk in enumerate(chunks):
print(f"Processing chunk {i + 1} ({len(chunk)} rows)...")
address_list = [
{"street": row["address"], "city": row["city"], "country": row["country"]}
for _, row in chunk.iterrows()
]
results = client.batch_geocode(address_list)
chunk["latitude"] = [r.latitude for r in results]
chunk["longitude"] = [r.longitude for r in results]
chunk.to_csv("output.csv", mode="w" if first_chunk else "a",
header=first_chunk, index=False)
first_chunk = False
print("Done!")Error Handling for Production Code
Production code needs to handle failures gracefully. Addresses can be malformed, API limits can be reached, and networks can be unreliable.
from csv2geo import Client
from csv2geo.exceptions import RateLimitError, InvalidAddressError, ApiError
import time
client = Client(api_key="geo_live_k8x2m9...")
def geocode_safe(address, retries=3):
"""Geocode with retry logic and error handling."""
for attempt in range(retries):
try:
result = client.geocode(address)
if result.confidence < 0.5:
print(f" Low confidence ({result.confidence}) for: {address}")
return result
except RateLimitError:
wait = 2 ** attempt # Exponential backoff: 1s, 2s, 4s
print(f" Rate limited. Waiting {wait}s...")
time.sleep(wait)
except InvalidAddressError:
print(f" Invalid address: {address}")
return None
except ApiError as e:
print(f" API error: {e}")
if attempt == retries - 1:
return None
time.sleep(1)
return NoneUnderstanding the Geocoding Response
Every geocode call returns a structured result object. Here is what each field means.
| Field | Type | Description | Example |
|---|---|---|---|
latitude | float | Decimal degrees, WGS84 | 40.7484 |
longitude | float | Decimal degrees, WGS84 | -73.9857 |
confidence | float | Match quality, 0 to 1.0 | 1.0 |
formatted_address | str | Full structured address | 350 5th Ave, New York, NY 10118, US |
street | str | Parsed street name | 5th Avenue |
house_number | str | Parsed street number | 350 |
city | str | City or locality | New York |
state | str | State or province | New York |
postcode | str | Postal/ZIP code | 10118 |
country | str | Country name | United States |
country_code | str | ISO 3166-1 alpha-2 | US |
Confidence score interpretation:
| Score | Level | What It Means |
|---|---|---|
| 1.0 | Rooftop | Exact building match — coordinates point to the specific address |
| 0.8–0.99 | Near-rooftop | Very reliable — correct building or parcel |
| 0.5–0.79 | Street-level | Correct street, not the exact building |
| Below 0.5 | Area-level | City or postal code centroid — address was too vague |
Why Use the SDK Instead of Raw API Calls
You can call the CSV2GEO API directly with requests.get(). But the SDK handles several things you would otherwise build yourself:
- Rate limit management — automatic backoff and retry when you hit daily limits
- Batch chunking — splits large lists into 10K-address chunks automatically
- Response parsing — typed objects with .latitude, .longitude instead of raw JSON
- Error classification — distinct exceptions for rate limits, invalid addresses, server errors
- Connection pooling — reuses HTTP connections for better throughput
# Raw API call (works but verbose)
import requests
resp = requests.get("https://csv2geo.com/api/v1/geocode", params={
"q": "350 5th Ave, New York",
"country": "US",
"api_key": "your_key"
})
data = resp.json()
lat = data["results"][0]["latitude"]
# SDK (same result, less code, better error handling)
from csv2geo import Client
client = Client(api_key="your_key")
result = client.geocode("350 5th Ave, New York", country="US")
lat = result.latitudeComplete Production Script
A production-ready script that reads a CSV, geocodes every row in batches, handles errors, shows progress, and saves results:
#!/usr/bin/env python3
"""Geocode a CSV file using CSV2GEO batch API."""
import sys, pandas as pd
from csv2geo import Client
client = Client(api_key="geo_live_k8x2m9...")
df = pd.read_csv(sys.argv[1])
print(f"\n📂 Loaded {len(df)} rows from {sys.argv[1]}")
results = client.batch_geocode([
{"address": row["address"]} for _, row in df.iterrows()
])
df["latitude"] = [r.latitude for r in results]
df["longitude"] = [r.longitude for r in results]
df["confidence"] = [r.confidence for r in results]
df.to_csv(sys.argv[2], index=False)
high = sum(1 for r in results if r.confidence >= 0.9)
print(f"✅ Geocoded {len(df)} addresses")
print(f"📊 High confidence (≥0.9): {high}/{len(df)} ({100*high/len(df):.0f}%)")
print(f"💾 Saved to {sys.argv[2]}")Run it:
python geocode_csv.py my_addresses.csv my_addresses_geocoded.csv
No Code? No Problem
If Python is not your thing, you can geocode CSV and Excel files directly on csv2geo.com/batchgeocoding — upload your file, map the columns, and download results. No code required, 100 rows per day free.
See our CSV geocoding guide or Excel geocoding guide for step-by-step walkthroughs.
Frequently Asked Questions
What Python library is best for geocoding?
The csv2geo SDK provides the simplest interface for production geocoding in Python. Install with pip install csv2geo, initialize with your API key, and call client.geocode() or client.batch_geocode(). It handles rate limits, retries, and error handling internally.
How do I geocode a CSV file in Python?
Load the CSV with pandas.read_csv(), extract the address column, pass addresses to client.batch_geocode() in chunks of up to 10,000, and add the resulting lat/long columns back to the DataFrame. The complete working script above does exactly this.
Is there a free geocoding API for Python?
Yes. CSV2GEO offers 1,000 free API requests per day with no credit card required. Get your API key at csv2geo.com/api-keys. The free tier covers 200+ countries and 461M+ addresses.
How do I batch geocode thousands of addresses in Python?
Use CSV2GEO’s batch endpoint: client.batch_geocode(addresses) processes up to 10,000 addresses in a single API call. For larger datasets, split into chunks of 5,000–10,000 and process sequentially. This is 20–40x faster than geocoding one address at a time.
How do I handle geocoding errors in Python?
Wrap API calls in try/except blocks catching RateLimitError, InvalidAddressError, and ApiError. Implement exponential backoff for rate limits, log invalid addresses for manual review, and check the confidence score to flag low-quality results.
Can I reverse geocode coordinates to addresses in Python?
Yes. Use client.reverse_geocode(latitude=48.8584, longitude=2.2945) to convert any coordinate pair to a structured address. See the reverse geocoding guide for more details.
Start Geocoding in Python
Install the SDK and make your first geocode in under a minute:
pip install csv2geoGet your free API key at csv2geo.com/api-keys — 1,000 requests per day, no credit card, 200+ countries, 461M+ addresses. The full API documentation covers all 18 endpoints.

Need help? Visit our Help center or contact us.
I.A.
CSV2GEO Creator
Use our batch geocoding tool to convert thousands of addresses to coordinates in minutes. Start with 100 free addresses.
Try Batch Geocoding Free →