The Geocoding API v4 introduces several new methods that replace functionality in v3 of the API. This guide shows you how to migrate your app to use the new v4 methods.
You can use your existing API keys with the new v4 methods. However, if you have requested a quota uplift on v3 of the API, you must request an uplift on the new v4 APIs.
Migrate from v3 Forward Geocoding
If you use v3 Geocoding to geocode addresses, you should migrate to the v4 Geocode an address method, which accepts a GET request.
The v4 API changes names, structure, and support for several parameters. We strongly recommend that you use a field mask to specify the fields you want returned in the response.
Request parameter changes
| v3 Parameter | v4 Parameter | Notes |
|---|---|---|
address, components |
address |
Unstructured address (v3 address) is now passed in URL path. Structured address components (v3 components) can be passed as address.* query parameters. See Reproduce v3 component filters. |
bounds |
locationBias.rectangle |
Renamed; structure changed to object. |
language |
languageCode |
Renamed. |
region |
regionCode |
Renamed. |
extra_computations |
Removed | Replaced by SearchDestinations method. |
Response field changes
| v3 Field | v4 Field | Notes |
|---|---|---|
status, error_message |
Removed | v4 uses HTTP status codes and error bodies. |
results.address_components.long_name / results.address_components.short_name |
results.addressComponents.longText / results.addressComponents.shortText |
Renamed. |
results.geometry.location_type |
results.granularity |
Renamed. |
results.geometry.location |
results.location |
Field names: lat/lng -> latitude/longitude. |
results.geometry.viewport |
results.viewport |
Field names: northeast/southwest -> high/low. |
results.postcode_localities |
results.postalCodeLocalities |
Renamed. Now returned for one or more localities (v3 required >1). |
results.partial_match |
Removed | |
| New | results.addressComponents.languageCode |
Language of the specific address component. |
| New | results.bounds |
Explicit bounds using high/low. |
| New | results.place |
Resource name for the place. |
| New | results.postalAddress |
Structured PostalAddress object. |
Reproduce v3 component filters
Forward Geocoding in Geocoding v3 included a components parameter that enabled
hard filtering of results for specific components (e.g.,
components=country:US). Forward Geocoding in v4 does not support this type of
hard filtering in the request parameters. In v4, you can provide address
information as either a single unstructured string in the path or as structured
query parameters like address.addressLines, address.locality,
address.administrativeArea, address.postalCode, and address.regionCode.
Structured parameters don't act as hard filters. Instead, all the provided
components are combined to form the complete address the API will attempt to
geocode. The API searches for the best match for the entire address specified
across all components. Providing components in a structured way can help the API
better understand the intent, especially when the address information is
collected from separate form fields. This can aid the API in handling minor
typos or ambiguities within each component, as the type of information in each
field is clear.
To achieve behavior similar to v3's hard component filters, you must implement
client-side filtering on the results array returned by the v4 API based on the
postalAddress and addressComponents objects in the response.
The following table shows the best match between the v3 components filters and
the v4 postalAddress fields:
| v3 component filter | v4 response field |
|---|---|
country |
postalAddress.regionCode |
postal_code |
postalAddress.postalCode |
administrative_area |
postalAddress.administrativeArea or addressComponents |
Client-side filtering examples
The following examples show how to filter results to achieve behavior similar to v3 component filtering for supported fields: country, administrative area, and postal code. It is not recommended to filter on other fields as reliable filtering criteria does not exist.
Filter by Country
Match the address.regionCode from your request with the postalAddress.regionCode in each result. Note that while the API accepts lowercase region codes in the request, it always returns them in uppercase in the response, so you must normalize your input to uppercase before comparison.
Python Code Example
def filter_by_country(results, region_code): return [ res for res in results if res.get('postalAddress', {}).get('regionCode') == region_code.upper() ] # Example usage: # v4_response = ... # API call response # filtered = filter_by_country(v4_response.get('results', []), 'US')
Node.js Code Example
function filterByCountry(results, regionCode) { return results.filter(res => res.postalAddress?.regionCode === regionCode.toUpperCase()); } // Example usage: // const v4Response = ... # API call response // const filtered = filterByCountry(v4Response.results, 'US');
Filter by Administrative Area
Match the address.administrativeArea from your request with the postalAddress.administrativeArea in each result. Similar to country codes, you should normalize your input to uppercase before comparison. This is only reliable when the administrativeArea in your request is provided with a standard 2-letter abbreviation. The postalAddress.administrativeArea in the response may not directly match ISO 3166-2 code suffixes for several reasons. Firstly, in some areas the subdivision corresponding the the ISO 3166-2 code is not part of standard representation of postal addresses. For example, in Spain, the administrative area level 1 (e.g., "CN" for Canarias) might be present in the addressComponents, but postalAddress.administrativeArea might contain the level 2 area (e.g., "Santa Cruz de Tenerife"). Secondly, in some areas the subdivision's
abbreviation is not commonly used and its represented in postalAddress.administrativeArea
with a longer name (for similar reasons, addressComponents.shortText for address component
corresponding to the subdivision may not match the subdivision's ISO 3166-2 code suffix). Additonally, the subdivision in some cases may be represented at the address component for administrative_area_level_n with n greater than 1.
For the most comprehensive results, you should check for a match in both postalAddress.administrativeArea and any addressComponents with an administrative_area_level_n type (e.g. administrative_area_level_1).
Python Code Example
def filter_by_admin_area(results, admin_area): target = admin_area.upper() filtered = [] for res in results: # Check postalAddress pa_aa = res.get('postalAddress', {}).get('administrativeArea', '') if pa_aa == target: filtered.append(res) continue # Check all administrative area levels in addressComponents for comp in res.get('addressComponents', []): is_admin_level = any(t.startswith('administrative_area_level_') for t in comp.get('types', [])) if is_admin_level: short = comp.get('shortText', '') if short == target: filtered.append(res) break return filtered # Example usage: # filtered = filter_by_admin_area(v4_response.get('results', []), 'CA')
Node.js Code Example
function filterByAdminArea(results, adminArea) { const target = adminArea.toUpperCase(); return results.filter(res => { // Check postalAddress.administrativeArea if (res.postalAddress?.administrativeArea === target) { return true; } // Check addressComponents for any administrative area level return res.addressComponents?.some(c => { const isAdmin = c.types?.some(t => t.startsWith('administrative_area_level_')); return isAdmin && c.shortText === target; }); }); } // Example usage: // const filtered = filterByAdminArea(v4Response.results, 'CA');
Filter by Postal Code
Match the address.postalCode from your request with the postalAddress.postalCode in each result. You must normalize both the input and result postal codes before comparison. The normalization logic is highly dependent on the region. A basic approach involves removing spaces and hyphens and converting to a consistent case.
More advanced normalization might be needed to handle postal code prefixes (e.g., "L2" in the UK) or suffixes (e.g., "+4" in US ZIP codes). The specific normalization logic required will vary depending on the country and the formats of postal codes involved. You may need to adapt the provided normalization functions or implement more sophisticated logic for the regions you are targeting.
The provided example handle US ZIP codes and allow matching on the 5-digit base even if ZIP+4 is provided or returned.
Python Code Example (US ZIP Code focused)
import re def normalize_postal_code_us(pc): # Basic normalization for US: uppercase, alphanumeric only if not pc: return "" normalized = re.sub(r'[^A-Z0-9]', '', pc.upper()) # Return only the first 5 digits for US ZIP codes return normalized[:5] def filter_by_postal_code_us(results, postal_code): normalized_input = normalize_postal_code_us(postal_code) if not normalized_input: return [] filtered_results = [] for res in results: pa_pc = res.get('postalAddress', {}).get('postalCode', '') if normalize_postal_code_us(pa_pc) == normalized_input: filtered_results.append(res) return filtered_results # Example usage: # Matches '94043', '94043-1351', '940431351' # filtered = filter_by_postal_code_us(v4_response.get('results', []), '94043') # filtered = filter_by_postal_code_us(v4_response.get('results', []), '94043-1234')
Node.js Code Example (US ZIP Code focused)
function normalizePostalCodeUs(pc) { // Basic normalization for US: uppercase, alphanumeric only const normalized = (pc || '').toUpperCase().replace(/[^A-Z0-9]/g, ''); // Return only the first 5 digits for US ZIP codes return normalized.substring(0, 5); } function filterByPostalCodeUs(results, postalCode) { const normalizedInput = normalizePostalCodeUs(postalCode); if (!normalizedInput) { return []; } return results.filter(res => { const paPc = res.postalAddress?.postalCode || ''; return normalizePostalCodeUs(paPc) === normalizedInput; }); } // Example usage: // Matches '94043', '94043-1351', '940431351' // const filtered = filterByPostalCodeUs(v4Response.results, '94043'); // const filtered = filterByPostalCodeUs(v4Response.results, '94043-1234');
Migrate from v3 Reverse Geocoding
If you use v3 Reverse Geocoding to turn coordinates into addresses, you should migrate to the v4 Reverse geocode a location method, which accepts a GET request.
The v4 API changes names, structure, and support for several parameters. We strongly recommend that you use a field mask to specify the fields you want returned in the response.
Request parameter changes
| v3 Parameter | v4 Parameter | Notes |
|---|---|---|
language |
languageCode |
Renamed. |
region |
regionCode |
Renamed. |
result_type |
types |
Renamed; uses repeated query parameters. |
location_type |
granularity |
Renamed; uses repeated query parameters. |
extra_computations |
Removed | Replaced by SearchDestinations method. |
Response field changes
| v3 Field | v4 Field | Notes |
|---|---|---|
status, error_message |
Removed | v4 uses HTTP status codes and error bodies. |
results.address_components.long_name / results.address_components.short_name |
results.addressComponents.longText / results.addressComponents.shortText |
Renamed. |
results.geometry.location_type |
results.granularity |
Renamed. |
results.geometry.location |
results.location |
Field names: lat/lng -> latitude/longitude. |
results.geometry.viewport |
results.viewport |
Field names: northeast/southwest -> high/low. |
| New | results.addressComponents.languageCode |
Language of the specific address component. |
| New | results.bounds |
Explicit bounds using high/low. |
| New | results.place |
Resource name for the place. |
| New | results.postalAddress |
Structured PostalAddress object. |
Migrate from v3 Address descriptors
If you use address_descriptor to get additional information about a location with Geocoding v3, you must migrate to using the landmarks field of the SearchDestinationsResponse.
Migrate from v3 Place geocoding
If you use place_id to get the address for a specific Place ID with Geocoding
v3, you must migrate to the v4 Place
Geocoding method, which
accepts a GET request.
The v4 API changes names, structure, and support for several parameters. We strongly recommend that you use a field mask to specify the fields you want returned in the response.
Request parameter changes
| v3 Parameter | v4 Parameter | Notes |
|---|---|---|
place_id |
place field in request proto |
The Place ID is now provided as a path parameter places/{place}, for example: https://geocode.googleapis.com/v4/geocode/places/ChIJj61dQgK6j4AR4GeTYWZsKWw. This maps to the place field in the underlying request. |
language |
languageCode |
Renamed. |
region |
regionCode |
Renamed. |
Response field changes
| v3 Field | v4 Field | Notes |
|---|---|---|
status, error_message |
Removed | v4 uses HTTP status codes and error bodies. |
results |
(root) | v4 returns a single result object, not a results array. |
results.address_components.long_name / results.address_components.short_name |
addressComponents.longText / addressComponents.shortText |
Renamed. |
results.geometry.location_type |
granularity |
Renamed. |
results.geometry.location |
location |
Field names: lat/lng -> latitude/longitude. |
results.geometry.viewport |
viewport |
Field names: northeast/southwest -> high/low. |
results.postcode_localities |
postalCodeLocalities |
Renamed. Now returned for one or more localities (v3 required >1). |
| New | addressComponents.languageCode |
Language of the specific address component. |
| New | bounds |
Explicit bounds using high/low. |
| New | place |
Resource name for the place. |
| New | postalAddress |
Structured PostalAddress object. |
Migrate from Geocoding Hyperlocal Data to Destinations
The following features in the Geocoding API v3 are being replaced by the SearchDestinations method of the Geocoding API v4:
- Entrances
- Navigation points
- Building outlines
- Grounds
If you were using the Geocoding API v3 for the above features, use this document
to help you use the SearchDestinations method instead to get these features.
This document explains where in the SearchDestinations response to find
these features, and differences in how these features are represented in the API
responses between the Geocoding API v3 and the SearchDestinations method of
the Geocoding API v4.
Entrances
To get the entrances associated with a
destination,
use the field destination.entrances.
Note that the format of an
entrance
is slightly different from the entrance format in the Geocoding API
v3. Each entrance
in destination.entrances has the following fields:
displayName- this is a new optional field that will have a human readable name for the entrance, for example "Gate B".location- this is a location of typeLatLng, which is different from the format used in the Geocoding API v3.tags- this is the same as thetagsfield of the entrances from the Geocoding API v3.place- analogous to thebuildingPlaceIdfield of the entrances from the Geocoding API v3. However, the Place ID in this field could be for a Place of any type, not necessarily just a building.
Navigation points
To get the navigation points associated with a destination, use the field
destination.navigationPoints.
Note that the format of a
navigationPoint
is slightly different from the navigation point format in the Geocoding API
v3. Each navigation
point in destination.navigationPoints has the following fields:
displayName- this is a new optional field that will have a human readable name for the navigation point, for example "5th Ave".location- this is a location of typeLatLng, which is different from the format used in the Geocoding API v3.travelModes- this is similar to therestrictedTravelModesfield of the navigation points from the Geocoding API v3. The possible enum values are the same, the only difference is that this field now represents the acceptable travel modes for the navigation point, rather than the restricted travel modes.usage- this is a new field which contains the use cases supported by the navigation point. Note that most navigation points will have anUNKNOWNusage, but that does not necessarily mean the navigation point's usage is restricted in any way.
Building outlines
To get the building outlines associated with a destination, you should use the
displayPolygon field of the
placeView
objects in the destination that represent buildings. For each placeView, you
can check if it is a building with the
placeView.structureType
field. If the structure type is BUILDING, you can get the outline from the
placeView.displayPolygon field. The placeView will also have additional
fields for the building that were not in the Geocoding API v3.
A destination can have a placeView object that represents a building in the
following fields:
destination.primary- this is the primary place for the destination.destination.containingPlaces- this is a repeated field that can hold larger places that "contain" the primary place. For example, if the primary place is asubpremise,containingPlaceswill usually hold theplaceViewrepresenting the building.destination.subDestinations- this is a repeated field that can hold sub-destinations of the primary place. For example, individual apartment units of a building. This field won't typically have aplaceViewrepresenting a building.
Note that the format of placeView.displayPolygon matches the building outline
format in the Geocoding API
v3, which is the
GeoJSON format, using the RFC 7946
format.
Grounds
Similar to building outlines, to get the grounds associated with a
destination, you should use the displayPolygon field of the placeView
objects in the destination that represent grounds. For each placeView, you
can check if it is a grounds with the placeView.structureType field. If the
structure type is GROUNDS, you can get the outline from the
placeView.displayPolygon field. The placeView will also have additional
fields for the grounds that were not in the Geocoding API v3.
A destination can have a placeView object that represents a grounds in the
following fields:
destination.primarydestination.containingPlacesdestination.subDestinations
Note that the format of placeView.displayPolygon matches the grounds outline
format in the Geocoding API v3,
which is the GeoJSON format, using the RFC 7946
format.
Precision of results
In the Geocoding API v3, the location_type field in the response geometry
indicated the precision of the results, and some clients would rank or filter
results based on these values (ROOFTOP, RANGE_INTERPOLATED,
GEOMETRIC_CENTER, and APPROXIMATE). In standard Geocoding API v4 migrations,
this field is renamed granularity.
In the Destinations API (v4 SearchDestinations), there is no location_type
field. Instead, spatial information is handled differently:
- No manual client-side filtering needed: While standard Geocoding
provides multiple results across different granularities, the
SearchDestinationsmethod minimizes ambiguity by resolving to a single, optimized destination whenever possible. This removes the need for clients to filter by location type to determine which result is best. - Spatial information represented by structure type and display polygons:
Spatial geometry and structure are indicated by:
- The
displayPolygon(for exact geometry). - The
structureTypefield within theplaceViewobject.
- The
- Structure type mapping:
- A
structureTypeofPOINT,BUILDING, orSECTIONgenerally corresponds to what was calledROOFTOPpreviously. - A
structureTypeofGROUNDSgenerally corresponds toGEOMETRIC_CENTER.
- A
Use a field mask to request these features
The SearchDestinations
method requires a field mask, as explained in Choose fields to
return. The field mask can be set
to * in order to return all fields, or you can set it to the specific fields
you want to receive. For example, the following API request sets the field mask
to receive all fields required to get the entrances, navigation points, building
outlines, and grounds of a destination:
curl -X POST -d '{"place": "places/ChIJG3kh4hq6j4AR_XuFQnV0_t8"}' \
-H "X-Goog-Api-Key: API_KEY" \
-H "Content-Type: application/json" \
-H "X-Goog-FieldMask: destinations.entrances,destinations.navigationPoints,destinations.primary,destinations.containingPlaces,destinations.subDestinations" \
https://geocode.googleapis.com/v4/geocode/destinations
Security considerations
The Geocoding API v4 is designed as a server-to-server API. There is no direct migration path for JavaScript users from v3 to v4. Calling the v4 methods directly from client-side JavaScript (for example, in a browser) using an API key exposes your API key to a high risk of theft and misuse.
HTTP referrer restrictions, while useful, are not sufficient protection for web
service endpoints as they can be trivially bypassed by attackers who forge the
Referer header in their requests.
Recommended approach
The recommended way to use the Geocoding API v4 is from your own backend server. Your client application should make requests to this intermediary server, which then securely calls the Google API using a protected API key (for example, a key stored in an environment variable or a secret manager). This ensures that your API key is never exposed in the frontend code.
Alternates for client-side needs
If you have client-side needs that require geocoding, consider using one of the existing client-side solutions:
- Geocoding Service in the Maps JavaScript API: The Geocoding Service continues to use the v3 backend and is designed for use in a browser environment.
- Places UI Kit: Use the Places UI Kit, including Place Autocomplete elements, for address-related user interface elements.