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.

| March 24, 2026
How to Geocode Addresses in Python: Complete Guide with Code Examples

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
Installing CSV2GEO Python SDK with pip install csv2geo in terminal

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
Python terminal showing single address geocoding with CSV2GEO SDK — converting address to lat/long coordinates

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

Approach10,000 AddressesAPI CallsTime
One-by-one loopLoop with rate limiting10,00030–60 minutes
Batch APISingle request130–90 seconds

That is not a typo. Batch processing is 20–40x faster because it eliminates network round-trip overhead for each address.

Python batch geocoding 5 world landmarks with CSV2GEO — New York, Berlin, Sydney, Paris, Rome in one API call

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.

Reverse geocoding Eiffel Tower coordinates to street address in Python with CSV2GEO SDK

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())
Geocoding a pandas DataFrame with CSV2GEO Python SDK — loading CSV, batch geocoding, adding lat/long columns

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 None

Understanding the Geocoding Response

Every geocode call returns a structured result object. Here is what each field means.

FieldTypeDescriptionExample
latitudefloatDecimal degrees, WGS8440.7484
longitudefloatDecimal degrees, WGS84-73.9857
confidencefloatMatch quality, 0 to 1.01.0
formatted_addressstrFull structured address350 5th Ave, New York, NY 10118, US
streetstrParsed street name5th Avenue
house_numberstrParsed street number350
citystrCity or localityNew York
statestrState or provinceNew York
postcodestrPostal/ZIP code10118
countrystrCountry nameUnited States
country_codestrISO 3166-1 alpha-2US

Confidence score interpretation:

ScoreLevelWhat It Means
1.0RooftopExact building match — coordinates point to the specific address
0.8–0.99Near-rooftopVery reliable — correct building or parcel
0.5–0.79Street-levelCorrect street, not the exact building
Below 0.5Area-levelCity 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.latitude

Complete 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
Production Python geocoding script processing 1,247 addresses with 96% high confidence results

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 csv2geo

Get 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.

CSV2GEO geocoding API documentation page showing 18 endpoints for forward, reverse, batch, and places geocoding

Need help? Visit our Help center or contact us.

I.A.

CSV2GEO Creator

Ready to geocode your addresses?

Use our batch geocoding tool to convert thousands of addresses to coordinates in minutes. Start with 100 free addresses.

Try Batch Geocoding Free →