Move off the Google Geocoding API
A local server that answers in Google's format. Your code keeps its requests and its parsing; only the base URL changes, and no address leaves your machine.
The change in your code
$ gridpin serve usa.bin --port 8080 $ curl "http://127.0.0.1:8080/maps/api/geocode/json?address=1600+Pennsylvania+Ave+NW,+Washington,+DC" $ curl "http://127.0.0.1:8080/maps/api/geocode/json?latlng=38.8977,-77.0365"
import requests
# before: BASE = "https://maps.googleapis.com"
BASE = "http://127.0.0.1:8080"
r = requests.get(f"{BASE}/maps/api/geocode/json",
params={"address": "1600 Pennsylvania Ave NW, Washington, DC", "key": "not-needed"})
top = r.json()["results"][0]
top["geometry"]["location"] # {'lat': 38.8976751, 'lng': -77.036547}
top["geometry"]["location_type"] # 'ROOFTOP'
// before: const BASE = 'https://maps.googleapis.com';
const BASE = 'http://127.0.0.1:8080';
const q = new URLSearchParams({ address: '1600 Pennsylvania Ave NW, Washington, DC' });
const { status, results } = await (await fetch(`${BASE}/maps/api/geocode/json?${q}`)).json();
if (status === 'OK') console.log(results[0].geometry.location);
from geopy.geocoders import GoogleV3
GoogleV3(api_key="not-needed", domain="127.0.0.1:8080", scheme="http").geocode("1600 Pennsylvania Ave NW, Washington, DC")
import googlemaps
googlemaps.Client(key="AIzaNotNeeded", base_url="http://127.0.0.1:8080").geocode("1600 Pennsylvania Ave NW, Washington, DC")
Checked on November 7, 2026 with geopy 2.5.0 and googlemaps 4.10.0 against the United States file. A key, language and region are accepted and have no effect.
Which field means what
| Google field | Here |
|---|---|
status | OK, ZERO_RESULTS, and INVALID_REQUEST with HTTP 400 |
geometry.location | the answer's point |
geometry.location_type | ROOFTOP a stored point of the house; RANGE_INTERPOLATED between two houses; GEOMETRIC_CENTER the street; APPROXIMATE the neighbour's point, a postcode or a town |
partial_match | true when the engine itself says check it (weak) or it answered with a neighbour |
address_components | street_number, route, locality, administrative_area_level_1 where the file knows it, country as a code, postal_code |
place_id | our own, stable within one file release; not usable with Google |
geometry.viewport | a box by precision, for framing a map |
components | route, locality, administrative_area, postal_code narrow the query; country of another file gives ZERO_RESULTS |
What the same traffic costs
| Queries a month | Google Geocoding API | GridPin, per query |
|---|---|---|
| 10,000 | $0 | $0 |
| 100,000 | $450 | $0 |
| 500,000 | $2,050 | $0 |
| 1,000,000 | $3,550 | $0 |
| 5,000,000 | $9,550 | $0 |
| 10,000,000 | $11,450 | $0 |
Google's list prices for the Geocoding API, read November 7, 2026 (Google's page dated November 3, 2026): 10,000 free calls a month, then $5.00 per 1,000 up to 100,000, $4.00 to 500,000, $3.00 to 1,000,000, $1.50 to 5,000,000 and $0.38 beyond. Your machine is not free; the file is. See how to cut the bill.
What does not carry over
- One country per process, and only the countries of the release: run one server per country.
- Addresses only: no shops or landmarks by name, no autocomplete, no Places.
- Quality differs by country: see the measured tables before you switch.
- No
bounds,postcode_localitiesor XML output;plus_codeneedswith=codes(new in 0.9.0). - GridPin is not affiliated with Google; the format is followed so that existing code keeps working.
The server itself: gridpin serve.