Forward geocoding with the Google Geocoding API

Learn how to use the Google Geocoding API to convert addresses into latitude and longitude. Includes real world examples and sample code.

Forward geocoding with the Google Geocoding API

Forward geocoding is the process of converting a street address into geographic coordinates (latitude and longitude), which can then be used to place markers on a map, plan efficient routes or verify delivery addresses. In this article, I'll show you how to use the forward geocoding endpoint of the Google Geocoding API to do all these and more!

What we'll build - a demo app to test the Google Geocoding API
What we'll build - a demo app to test the Google Geocoding API

Part 1: A practical guide to the Google Geocoding API
Part 2: Forward geocoding with the Google Geocoding API (this article)
Part 3: Google Maps reverse geocoding: Get addresses from coordinates
Part 4: Google Address Validation API: Better than USPS?
Part 5: Google Maps Building Outlines and Entrances API

I’ll explain what forward geocoding is, walk through a typical request, and cover common use cases. Together, we'll build a simple demo app (https://google-forward-geocoding.afi.dev/) to learn how Google geocoding works in practice. As always, you can find sample code (frontend / backend) for this project on GitHub.

Google Forward Geocoding Demo
How to use the Google Geocoding API to convert address strings into geographic coordinates

What is forward geocoding?

Forward geocoding converts a written address e.g. "555 West Hastings Street, Vancouver BC V6B4N4, Canada" into geographic coordinates e.g. 49.2846966, -123.1119349. It's the first step in turning real world addresses into usable data.

Forward geocoding on the Google Geocoding API turns addresses into coordinates
Forward geocoding on the Google Geocoding API turns addresses into coordinates

Google Maps can do this because over the years it has built a vast database of business and residential addresses along with their exact geographic coordinates. Some of this data is sourced through public records and commercial or postal service datasets, but increasingly, a lot of it is user contributed e.g. business owners updating listings via Google Business Profile.

What is forward geocoding used for?

Forward geocoding is essential when you need to display an address on a map or provide location data to an API.

Visualizing data on a map
Forward geocoding is most often used to visualize locations on a map. For instance, instead of showing a plain list of addresses, mapping Vancouver’s best craft breweries makes the information far more useful and engaging.

Multiple geocoding results from Google Places Text Search
Multiple geocoding results from Google Places Text Search

Address validation
Forward geocoding is also useful for address validation, especially when working with data imported from spreadsheets or legacy systems. The Google Geocoding API helps assess the accuracy of an address by returning a location_type field (e.g., "ROOFTOP", "RANGE_INTERPOLATED", or "APPROXIMATE"), which indicates the precision of the geocode. This allows companies to determine whether an address is reliable enough to use.

Address validation using the Google Geocoding API
Address validation using the Google Geocoding API

Planning efficient delivery routes
Addresses can be ambiguous or imprecise, and many of Google Map's more advanced routing and navigation products such as the Google Maps Route Optimization API, the Routes API and the Navigation SDK work best with known, mappable coordinates. This is especially important when matching points to road networks, considering traffic, or snapping to the nearest valid route. Forward geocoding is the crucial first step in converting human readable addresses into coordinates that these APIs can consume.

Route optimization using addresses geocoded from the Google Geocoding API
Route optimization using addresses geocoded from the Google Geocoding API

Google Geocoding API example (forward geocoding)

Here's a simple geocoding example that returns the latitude and longitude for "555 West Hastings Street, Vancouver".

EndpointGET

https://maps.googleapis.com/maps/api/geocode/json?
address={ADDRESS}&
key={YOUR_API_KEY}

{ADDRESS} is the street address that you want to geocode. Give as much detail as possible including the postal code, but leave out business names and unit, suite or floor numbers.

{YOUR_API_KEY} is your Google Maps API key with the Google Geocoding API enabled.

Endpoint: GET

https://maps.googleapis.com/maps/api/geocode/json?address=555+west+hastings+street+vancouver&key={GOOGLE_MAPS_API_KEY}

Response

{
    "results": [
        {
            "address_components": [
                {
                    "long_name": "555",
                    "short_name": "555",
                    "types": [
                        "street_number"
                    ]
                },
                {
                    "long_name": "West Hastings Street",
                    "short_name": "W Hastings St",
                    "types": [
                        "route"
                    ]
                },
                {
                    "long_name": "Central Vancouver",
                    "short_name": "Central Vancouver",
                    "types": [
                        "neighborhood",
                        "political"
                    ]
                },
                {
                    "long_name": "Vancouver",
                    "short_name": "Vancouver",
                    "types": [
                        "locality",
                        "political"
                    ]
                },
                {
                    "long_name": "Metro Vancouver",
                    "short_name": "Metro Vancouver",
                    "types": [
                        "administrative_area_level_2",
                        "political"
                    ]
                },
                {
                    "long_name": "British Columbia",
                    "short_name": "BC",
                    "types": [
                        "administrative_area_level_1",
                        "political"
                    ]
                },
                {
                    "long_name": "Canada",
                    "short_name": "CA",
                    "types": [
                        "country",
                        "political"
                    ]
                },
                {
                    "long_name": "V6B 4N4",
                    "short_name": "V6B 4N4",
                    "types": [
                        "postal_code"
                    ]
                }
            ],
            "formatted_address": "555 W Hastings St, Vancouver, BC V6B 4N4, Canada",
            "geometry": {
                "bounds": {
                    "northeast": {
                        "lat": 49.2851751,
                        "lng": -123.111479
                    },
                    "southwest": {
                        "lat": 49.28441489999999,
                        "lng": -123.1126507
                    }
                },
                "location": {
                    "lat": 49.2846966,
                    "lng": -123.1119349
                },
                "location_type": "ROOFTOP",
                "viewport": {
                    "northeast": {
                        "lat": 49.28614398029149,
                        "lng": -123.1107158697085
                    },
                    "southwest": {
                        "lat": 49.28344601970849,
                        "lng": -123.1134138302915
                    }
                }
            },
            "navigation_points": [
                {
                    "location": {
                        "latitude": 49.2845048,
                        "longitude": -123.1124829
                    }
                }
            ],
            "place_id": "ChIJUcKFZ3hxhlQREJGVU1foPaE",
            "types": [
                "premise",
                "street_address"
            ]
        }
    ],
    "status": "OK"
}

When you make a forward geocoding request to the Google Maps Geocoding API, the response is an array, results. Each item in this array contains detailed information about the geocoded address, including its formatted address, geographic coordinates and level of accuracy.

formatted_address is a string that provides the official, human readable version of an address - essentially, the way you'd write it on a postcard or envelope when sending mail to that location.

types is an array of place types that apply to the geocoded address. Most addresses have multiple types. For example, "Vancouver, Canada" is tagged with both locality and political, which indicates it is both a city and a political entity.

The geometry object contains geographic details about the geocoded result, specifically:

  • location, which contains the exact location.lat and location.lng of the place.
{
    "location": {
        "lat": 49.2827291,
        "lng": -123.1207375
    }
}
  • location_type, which indicates the accuracy of the geocoded result.
    • "ROOFTOP" means the result is highly precise, accurate down to a specific street address.
    • "RANGE_INTERPOLATED" and "APPROXIMATE" suggest the location is estimated and less reliable.

As a rule of thumb, only addresses with "ROOFTOP" accuracy should be considered deliverable.

place_id is the Google Place ID, which uniquely identifies a place in the Google Maps database (docs). You can use it to retrieve additional information about the place e.g. photos, user ratings and reviews.

When should you use the Google Geocoding API for forward geocoding?


Generally, only one entry in the results array is returned when you forward geocode an address with the Google Geocoding API. This means that the API works best when handling unambiguous queries such as complete postal address strings. The Google Geocoding API is not recommended if your application handles ambiguous or incomplete queries, such as “123 Main St”, or if it handles queries that may contain non address information such as apartment numbers or business names.

If you need to geocode a query such as "Tim Hortons, Vancouver" that will likely have multiple locations, use Google Text Search instead.

Google Maps forward geocoding demo

In this final section, we’ll build a web app that geocodes an address and displays its location on a Google Map, similar to the demo app in Google’s official documentation. The app features three main components:

  1. A text input field in the top-left corner that lets you enter an address or place name to be geocoded.
  2. A red marker that indicates the geocoded location of the address.
  3. A basic information popup that displays the name of the geocoded location and its coordinates.

While the code in this app is fairly simple, it serves as a helpful template for building map based applications that accept user input, call an API, and display the results on a map. If you don't want to pull the code from GitHub and run the app locally, you can still play around with it at https://google-forward-geocoding.afi.dev/.

How our code is organized

google_forward_geocoding is a simple React app created with the Vite build tool. The app works together with google_geocoding_backend, which retrieves place data from the Google Geocoding API.

App.jsx

App.jsx is the main building block of our app. Think of it as the "frame" or "shell" that holds everything else you see on the screen.

The structure of our Google Geocoding API demo app
The structure of our Google Geocoding API demo app

The App.jsx file is built around three main components:

  • <SearchBox/>, a presentational component that includes a text input field and two buttons - [Clear], which resets the map and removes any markers, and [Geocode], which sends the entered address to the Google Geocoding API.
  • <GoogleMap/>, a wrapper for the react-google-maps <Map/> component that handles map rendering.
  • <Marker/>, a red map marker positioned at the geocoded location. When clicked, it opens an <InfoWindow/> displaying the place name and coordinates of the geocoded address.
/*** App.jsx ***/
import { APIProvider } from "@vis.gl/react-google-maps";
import axios from "axios";
import { useState } from "react";

import GoogleMap from "~/components/GoogleMap";
import SearchBox from "~/components/SearchBox";

import "./App.scss";

function App() {
  const [address, setAddress] = useState("");
  const [places, setPlaces] = useState([]);

  const handleChangeAddress = (e) => {
    setAddress(e.target.value);
  };

  // ... action handler methods

  return (
    <APIProvider apiKey={import.meta.env.VITE_GOOGLE_MAP_API_KEY}>
      <div className="App">
        <SearchBox
          address={address}
          onChangeAddress={handleChangeAddress}
          onSearchAddress={handleSearchAddress}
          onClearAddress={handleClearAddress}
        />

        <GoogleMap places={places} />
      </div>
    </APIProvider>
  );
}

export default App;

SearchBox.jsx

SearchBox.jsx is a simple address input UI that lets users type in a location, then either clear the input or trigger a geocoding search.

*** components/SearchBox.jsx ***
import "./SearchBox.scss";

const SearchBox = ({
  address,
  onSearchAddress,
  onChangeAddress,
  onClearAddress,
}) => {
  return (
    <div className="SearchBox">
      <div className="input-group">
        <label className="label">Location</label>
        <input
          placeholder="Enter your location"
          onChange={onChangeAddress}
          value={address}
        />
      </div>

      <div className="button">
        <button className="btn clear-btn" onClick={onClearAddress}>
          Clear
        </button>

        <button
          className="btn geocode-btn"
          onClick={() => onSearchAddress(address)}
        >
          Geocode
        </button>
      </div>
    </div>
  );
};

export default SearchBox;

In SearchBox.jsx, the text input is controlled by the address state. When the user types, the onChangeAddress() function (which points to to handleChangeAddress() in App.jsx) is called with the event object, allowing the parent component to update the address value.

/*** App.jsx ***/
const [address, setAddress] = useState("");

const handleChangeAddress = (e) => {
  setAddress(e.target.value);
};

The contents of the text input field are passed to handleChangeAddress() automatically because React sends a SyntheticEvent to the onChange handler whenever the user types in the <input/>. This event contains the typed address string.

When the user clicks the [Geocode] button, the address is passed to the onSearchAddress() prop, which calls the handleSearchAddress() function in App.jsx.

*** App.jsx ***
const handleSearchAddress = async (address) => {
  if (!address) return;

  const response = await axios.get(`${import.meta.env.VITE_API_URL}/geocode`, {
    params: {
      address: address,
    },
  });

  if (response.data.results) {
    setPlaces(response.data.results);
  }
};

handleSearchAddress() uses an API loading wrapper pattern to fetch data from the Google Geocoding API. It sends the address string to the /geocode endpoint of google_geocoding_backend. If the response includes geocoded results, they are saved in state using the setPlaces() function.

geocode.js

geocode.js in google_geocoding_backend is a thin proxy client for the Google Geocoding API. Calls to /geocode are routed to the getGeocode() function, which then forwards each request to the Geocoding API.

/*** services/geocode.js ***
import axios from "axios";
import dotenv from "dotenv";

dotenv.config();
const GOOGLE_MAP_API_KEY = process.env.GOOGLE_MAP_API_KEY;

const getGeocode = async (address) => {
  const res = await axios.get(
    "https://maps.googleapis.com/maps/api/geocode/json",
    {
      params: {
        address,
        key: GOOGLE_MAP_API_KEY,
      },
    },
  );

  return res.data;
};

// ... reverse geocoding endpoint

export default {
  getGeocode,
  getReverseGeocode,
};

Here, the popular Axios HTTP client library is used to make a GET request to the Google Geocoding API (https://maps.googleapis.com/maps/api/geocode/json) by passing in the address and key (the Google Maps API key retrieved from the .env configuration file) parameters. Axios automatically encodes those parameters into a URL that looks like:

https://maps.googleapis.com/maps/api/geocode/json?address=555 west hastings street vancouver&key={YOUR_API_KEY}

This URL is used to make the API call, and the response from the Geocoding API (below) is stored in the res.data object. The data is then returned to App.jsx (from google_forward_geocoding) and saved in the places state, allowing the geocoded address to be displayed on the map.

{
    "results": [
        {
            "address_components": [
                //... address components
            ],
            "formatted_address": "555 W Hastings St, Vancouver, BC V6B 4N4, Canada",
            "geometry": {
                "location": {
                    "lat": 49.2846966,
                    "lng": -123.1119349
                },
                "location_type": "ROOFTOP"
            },
            "navigation_points": [
                //... navigation info
            ],
            "place_id": "ChIJUcKFZ3hxhlQREJGVU1foPaE",
            "types": [
                "premise",
                "street_address"
            ]
        }
    ],
    "status": "OK"
}

GoogleMap.jsx

GoogleMap.jsx, found in components/GoogleMap/index.jsx, is a React component that displays a full screen Google Map using the @vis.gl/react-google-maps library. It takes in a single prop, places, the array of geocoded location data returned by the Google Geocoding API.

/*** components/GoogleMap/index.jsx ***/
import { Map } from "@vis.gl/react-google-maps";

import MapHandler from "./MapHandler";
import Marker from "./Marker";

const DEFAULT_CENTER = { lat: 49.25307278849622, lng: -123.12095840000302 };

const GoogleMap = ({ places }) => {
  return (
    <div className="GoogleMap">
      <Map
        style={{
          height: "100dvh",
          width: "100dvw",
        }}
        defaultZoom={12}
        defaultCenter={DEFAULT_CENTER}
        gestureHandling="greedy"
        disableDefaultUI
        reuseMaps
      >
        <MapHandler places={places} />

        {places.length > 0 &&
          places.map((place) => {
            return <Marker key={place.place_id} place={place} />;
          })}
      </Map>
    </div>
  );
};

export default GoogleMap;

If places is non empty, it loops through each place and renders a <Marker/> for each one. Each <Marker/> knows how to position itself on the map based on the geometry.location.lat and geometry.location.lng returned by the Geocoding API and stored inside each place.

Marker.jsx

Map marker on the location on an address geocoded with the Google Geocoding API
Map marker on the location on an address geocoded with the Google Geocoding API

<Marker/> is a React component that displays a standard red pin on the map. It accepts a single prop - a place object - and uses it to position the marker at the geocoded location on the Google Map.

/*** components/GoogleMap/Marker.jsx ***/
import {
  Marker as GMarker,
  InfoWindow,
  useAdvancedMarkerRef,
} from "@vis.gl/react-google-maps";
import { useEffect, useState } from "react";

import "./Marker.scss";

const Marker = ({ place }) => {
  const [infowindowOpen, setInfowindowOpen] = useState(true);
  const [markerRef, marker] = useAdvancedMarkerRef();

  const position = {
    lat: place.geometry.location.lat,
    lng: place.geometry.location.lng,
  };

  useEffect(() => {
    setInfowindowOpen(false);
  }, [position.lat, position.lng]);

  return (
    <>
      <GMarker
        ref={markerRef}
        position={position}
        onClick={() => setInfowindowOpen((prev) => !prev)}
      />

      {infowindowOpen && (
        <InfoWindow className="info-window" anchor={marker} headerDisabled>
          <div className="info-detail">
            <div className="info-header">{place.formatted_address}</div>

            <div className="info-location">
              {position.lat}, {position.lng}
            </div>
          </div>

          <button
            className="btn-close"
            onClick={() => setInfowindowOpen(false)}
          >
            X
          </button>
        </InfoWindow>
      )}
    </>
  );
};

export default Marker;

When the <Marker /> is clicked, the infowindowOpen boolean is set to true, which triggers the <InfoWindow /> component to appear. This window displays the place’s formatted_address and GPS coordinates.

Running the app

To try the app, head over to https://google-forward-geocoding.afi.dev/ and enter an address or place name e.g. "Harbor Center, Vancouver" in the text field at the top left. Hit the [Geocode] button and you'll see a map marker appear at the geocoded location.

If you prefer to run the app locally:

  1. Fork both the google_forward_geocoding and google_geocoding_backend repositories on GitHub.
  2. In google_geocoding_backend, run npm install to install the dependencies followed by npm start.
  3. In geocoding_api_frontend, run npm install followed by vite run dev to start the app. Open your browser to http://localhost:3000/ to view the app.

Remember to update the .env files in both folders with a Google Maps API key that has the Google Geocoding API enabled.

Next up

In this post, I explained how forward geocoding works using the Google Geocoding API and showed you how to build a simple web app with a map interface to visualize the results. In the next one, we’ll explore Google’s Reverse Geocoding API and build a similar tool that converts coordinates into human readable addresses.

👋 As always, if you have any questions or suggestions for me, please reach out or say hello on LinkedIn.

Next: Part 3: Google Maps reverse geocoding: Get addresses from coordinates