NewConnect Claude, Gemini, ChatGPT, and other AI agents to API Ninjas via our MCP server

How to Convert a City to Latitude and Longitude in Python

Geocoding APIUpdated August 28, 2026
Create a free API key and it will be pre-filled into every code sample on this page. No credit card required.
Converting a city name to latitude and longitude in Python takes one GET request to the Geocoding API. The only real subtlety is that place names aren't unique — there's a Paris in Texas — so this guide covers the request, disambiguation, and the pattern geocoding usually exists for: feeding coordinates into the next API.

Prerequisites

You need three things:

  • Python 3.8 or newer.
  • The requests library.
  • A free API Ninjas API key — issued instantly, no credit card. If you already have an account, it's on your profile page.
shell
pip install requests

Step 1: Geocode your first city

The endpoint is /v1/geocoding. Pass a city (a US 5-digit ZIP code works too), and optionally country and state:

geocode.py
import requests response = requests.get( 'https://api.api-ninjas.com/v1/geocoding', params={'city': 'San Francisco', 'country': 'US'}, headers={'X-Api-Key': 'YOUR_API_KEY'}, timeout=10, ) response.raise_for_status() results = response.json() place = results[0] print(f"{place['latitude']}, {place['longitude']}") # 37.7790262, -122.4199061

The request on the wire and the full response:

api.api-ninjas.com
GET/v1/geocoding?city=San Francisco&country=US
200 OKapplication/json
[ { "name": "San Francisco", "latitude": 37.7790262, "longitude": -122.4199061, "country": "US", "state": "California" } ]

Coordinates are WGS 84 decimal degrees — the format every map library and GPS system expects.

Step 2: Handle ambiguous names

The response is a list because city names repeat across the world. The fix is to be specific — pass country, and state where countries reuse names internally. A small helper that returns the best match (or None) keeps the rest of your code clean:

geocode_client.py
import os import requests API_URL = 'https://api.api-ninjas.com/v1/geocoding' session = requests.Session() session.headers['X-Api-Key'] = os.environ.get('API_NINJAS_KEY', 'YOUR_API_KEY') def geocode(city: str, country: str | None = None, state: str | None = None) -> dict | None: """Return the best match for a place name, or None if nothing matched.""" params = {'city': city} if country: params['country'] = country if state: params['state'] = state response = session.get(API_URL, params=params, timeout=10) response.raise_for_status() results = response.json() return results[0] if results else None place = geocode('San Francisco', country='US') print(f"{place['name']}: {place['latitude']:.4f}, {place['longitude']:.4f}")
ambiguous.py
# "Paris" alone matches France AND Texas — disambiguate with country/state paris_fr = geocode('Paris', country='FR') paris_tx = geocode('Paris', country='US', state='Texas') print(f"Paris, France: {paris_fr['latitude']:.3f}, {paris_fr['longitude']:.3f}") print(f"Paris, Texas: {paris_tx['latitude']:.3f}, {paris_tx['longitude']:.3f}")

Step 3: Geocode a batch

Store lists, office locations, event venues — batch geocoding is a loop with the shared session:

batch.py
places = [('London', 'GB'), ('Paris', 'FR'), ('Tokyo', 'JP'), ('Sydney', 'AU')] for city, country in places: place = geocode(city, country=country) if place: print(f"{city:10} ({country}) {place['latitude']:>9.4f}, {place['longitude']:>10.4f}")

Geocode once and store the coordinates — place names don't move, so there's no reason to resolve the same city on every page load.

Step 4: Chain into other APIs

Coordinates are rarely the goal — they're the key that unlocks location APIs. The classic chain is geocode-then-weather, both on the same API key:

city_weather.py
def weather_for_city(city: str, country: str) -> dict: """Geocode a city, then fetch current weather for its coordinates.""" place = geocode(city, country=country) if not place: raise ValueError(f'Could not geocode {city}, {country}') response = session.get( 'https://api.api-ninjas.com/v1/weather', params={'lat': place['latitude'], 'lon': place['longitude']}, timeout=10, ) response.raise_for_status() return response.json() weather = weather_for_city('Reykjavik', 'IS') print(f"Reykjavik: {weather['temp']}°C, wind {weather['wind_speed']} m/s")

The same two-step works for the Timezone API and Air Quality API — any endpoint that takes lat/lon.

Step 5: Handle empty results

An unknown or misspelled place is not an HTTP error — the API returns an empty list. The helper from Step 2 turns that into None; always check it before using the result:

missing.py
place = geocode('Atlantis') if place is None: print('No match found — check the spelling or add country/state')

Where to go from here

For the reverse direction — coordinates back to a place — use Reverse Geocoding. And if your input is an IP address rather than a city name, the IP Lookup API jumps straight to coordinates. The complete script is below.

geocode.py

The complete script from this guide: city and country from the command line, coordinates out.

Frequently asked questions

What place formats are supported?

City and town names, optionally narrowed by country (two-letter ISO 3166 code) and state, plus US 5-digit ZIP codes. For ambiguous names like Springfield, always pass country and state.

Can it resolve a full street address?

No — this endpoint resolves place names to coordinates, not house numbers. A street address returns an empty list; geocode the city and use the city-center coordinates instead.

Why is the response a list?

Because place names collide — Paris exists in France and in Texas. The API returns every match; take the first, or filter by the country and state fields.

Can I go the other way — coordinates to a city?

Yes. The Reverse Geocoding endpoint takes lat and lon and returns the nearest city, region, and country.

What coordinate system is used?

WGS 84 decimal degrees — the same system GPS and every mapping library use, so the values drop straight into Leaflet, Google Maps, or a database point column.