Google Maps Search Along Route

Use the Google Search Along Route API to identify places along a route that match a free form text string.

Google Maps Search Along Route

Ever been on the road and needed to find a restaurant, restroom, or gas station nearby? The Google Maps Search Along Route API makes it easy to find places of interest right along your route, without having to make significant detours. In this blog post, I'll explain the basics of making a Google Maps Search Along Route API request, and show you how to use it to build a road trip planning app (source code / demo) that suggests cool places to check out along the way.

The Google Maps Search Along Route API helps you find places along your route
The Google Maps Search Along Route API helps you find places along your route

Part 1: A developer's guide to the Google Routes API
Part 2: Plan a route with multiple stops using the Routes API
Part 3: Using the Google Distance Matrix API for taxi dispatch
Part 4: Google Maps Search Along Route (this article)
Part 5: How to draw a route on Google Maps for Android with the Routes API

Search Along Route
Use the Google Search Along Route API to find places along a route that match a free form text string

How to search along route in Google Maps?

It's easy to find places of interest along your route in the Google Maps app (both web and mobile).

First, enter an origin and destination into the app. In the example below, I used "Vancouver, BC" as my start location and "Kelowna, BC" as my end location. Click the [Search along the route] textbox on the top left of the menu bar.

Click the search along the route box on the top left
Click the search along the route box on the top left

Next, enter whatever you are looking for into the textbox. I'm feeling a little tired and can use a quick nap, so I search for "rest stops". Google Maps automatically appends a "along the route" to my query.

Enter your search term
Enter your search term

Third, hit [🔎 Search] and you'll see your search results both on the map and on the listing view on the left hand side.

View search results in Google Maps
View search results in Google Maps

The Google Maps Search Along Route API allows you to programmatically add this same functionality to your app or website.

What is the Google Maps Search Along Route API?

The Google Maps Search Along Route API enables developers to find places of interest (e.g. gas stations, restaurants, rest stops) that are located along a predefined route. Unlike standard location based searches, this API ensures results are relevant to a driver's actual route, reducing unnecessary detours.

The Search Along Route API is actually the Google Places Text Search API with searchAlongRouteParameters added to the request body. To keep things simple, I'll just call it Search Along Route. It uses the encoded polyline generated by the Routes API to bias search results so as to only return places that are conveniently located along the route provided. Let's take a simple example of three restaurants, A, B and C along a highway. Your drive starts from origin and ends at destination.

Stops A, B and C along a route
Stops A, B and C along a route

Calling Text Search with "textQuery" : "Restaurants nearby" with a locationBias around your current location will return a list of restaurants nearby. But if you pass in a searchAlongRouteParameters.polyline.encodedPolyline that matches the route from origin to destination, it will return restaurants A, B and C because they are physically near the route and have minimal detour times from the origin to the destination.

Detour calculation for stops along a route
Detour calculation for stops along a route

A detour is the additional time required to visit a place compared to the time taken using a direct route from origin to destination. For example, suppose that visiting restaurant C and getting back on the highway takes an extra 5 minutes. If you hadn't made the detour, it would have only taken 3 minutes to get to the destination. The detour duration then is 5 minutes - 3 minutes = 2 minutes additional travel time. The Search Along Route API does its best to return places near the route with minimal detour durations.

Google Maps Search Along Route example

Here's a basic example of how a Search Along Route API call is structured. We'll set "Vancouver, BC" as the origin, "Kelowna, BC" as the destination, and "rest stops" as the text query (you can also play around with the Search Along Route API at https://search-along-route.afi.dev/). This is one of my all-time favorite summer road trips starting from Vancouver.

Google Maps Search Along Route example
Google Maps Search Along Route example

To get started, we first call the Compute Routes endpoint of the Routes API with "Vancouver, BC" as the origin and "Kelowna, BC" as the destination. Put routes.polyline in your field mask so that only the route polyline gets returned.

Google Routes API

Endpoint POST https://routes.googleapis.com/directions/v2:computeRoutes

Headers
Content-Type: application/json
X-Goog-Api-Key: YOUR_API_KEY
X-Goog-FieldMask: routes.polyline

Request Body

{
    "origin": {
        "address": "Vancouver, BC"
    },
    "destination": {
        "address": "Kelowna, BC"
    },
    "travelMode": "DRIVE",
    "polylineQuality": "OVERVIEW",
    "routingPreference": "TRAFFIC_AWARE",
    "departureTime": "2026-02-24T15:00:00Z"
}

Response

{
    "routes": [
        {
            "polyline": {
                "encodedPolyline": "ABCqxkHpbnnVwC{ElOiXhD_ ... BcBbCuA|B} "
            }
        }
    ]
}

Pass this encoded polyline string in the response to the Text Search API as a searchAlongRouteParameters.polyline.encodedPolyline like so:

Google Text Search API

Endpoint POST https://places.googleapis.com/v1/places:searchText

Content-Type: application/json
X-Goog-Api-Key: YOUR_API_KEY
X-Goog-FieldMask: places.displayName,places.formattedAddress,places.location

Request

{
    "textQuery": "rest stops",
    "searchAlongRouteParameters": {
        "polyline": {
            "encodedPolyline": "qxkHpbnn ... i@q@[u@Sy@KoAOa@OKk@@WDaKAUEQ[Qk@I}@AeL"
        }
    }
}

Response

{
    "places": [
        {
            "formattedAddress": "7399 Delta Line Rd, Ferndale, WA 98248, USA",
            "location": {
                "latitude": 48.9092536,
                "longitude": -122.6222666
            },
            "displayName": {
                "text": "Custer-Northbound Rest Area",
                "languageCode": "en"
            }
        },
        {
            "formattedAddress": "Bow Hill Rest Area, Bow, WA 98232, USA",
            "location": {
                "latitude": 48.5846413,
                "longitude": -122.34704759999998
            },
            "displayName": {
                "text": "Bow Hill Rest Area Southbound",
                "languageCode": "en"
            }
        },
        // ... 10 more entries
    ],
    "routingSummaries": [
        {
            "legs": [
                {
                    "duration": "3849s",
                    "distanceMeters": 70625
                },
                {
                    "duration": "14247s",
                    "distanceMeters": 360036
                }
            ],
            "directionsUri": "https://www.google.com/maps/dir/49.28303,-123.12121/''/49.88632,-119.4966/data=!4m7!4m6!1m0!1m2!1m1!1s0x5485b8d0356424c3:0x70ecef3593f0e432!1m0!3e0"
        },
        {
            "legs": [
                {
                    "duration": "5286s",
                    "distanceMeters": 112246
                },
                {
                    "duration": "15388s",
                    "distanceMeters": 388667
                }
            ],
            "directionsUri": "https://www.google.com/maps/dir/49.28303,-123.12121/''/49.88632,-119.4966/data=!4m7!4m6!1m0!1m2!1m1!1s0x54850ca726ded57f:0x4b994177317941ae!1m0!3e0"
        },
        // ... 10 more entries
    ]
}

The Search Along Route API provides a list of places that match the search query and are located near the specified route. Each place object has a:

formattedAddress, a human readable, properly formatted address of the place.

location, which gives us the coordinates of the place in latitude and and longitude,

displayName, a convenient human readable name for the place and,

routingSummaries, an array of route summaries for each place in the response, including the duration and distance from the origin to the place, as well as from the place to the destination. This information allows us to calculate the total detour duration for each place and filter results to show only those with a detour duration below a specified limit.

Google Maps Search Along Route API location bias

If you use the Search Along Route API with a common search term like "restaurants," you may notice that most results are clustered near the start or end of the route. This happens because the API tends to over index larger cities along the route, which is also where most trips begin and end.

Search results clustered at the start and end of a route
Search results clustered at the start and end of a route

To improve your search results, you can add a locationBias on the middle portion of the route and ignore the start and end segments. Here one way to do this:

  1. Decode the route polyline into an array of geographic coordinates, and make note of the 25th and 75th percentile elements. All the coordinates between these two points represent the "middle" 50% of the route.
Applying locationBias to the middle 50% of the route
Applying locationBias to the middle 50% of the route
  1. Apply the LatLngBounds.extend() method of the Google Maps Geometry Library on each point between the 25th and 75th percentile coordinates. This will determine the "corner" southwest and northeast bounds of the bounding box that contains these points.
The bounding box taken from the middle 50% of our route
The bounding box taken from the middle 50% of our route
  1. With the bounding box returned in step 2, call the Text Search API and include a locationBias object (example shown below). This is a soft constraint that ensures that any place results returned will likely be inside or near the bounding box. rectangle is a latitude-longitude viewport, represented as two diagonally opposite low and high points. The low point marks the southwest corner of the rectangle, and the high point represents the northeast corner of the rectangle.
{
    "locationBias": {
        "rectangle": {
            "low": {
                "latitude": 49.36168000000001,
                "longitude": -121.44006000000002
            },
            "high": {
                "latitude": 50.09975000000001,
                "longitude": -120.55021
            }
        }
    }
}
  1. Finally, use the LatLngBounds.getSouthWest() method to retrieve the coordinates for low and LatLngBounds.getNorthEast() method for high. Here’s the same Search Along Route request for restaurants along the Vancouver - Kelowna route, but with locationBias applied to the middle section.
locationBias applied to the Google Maps Search Along Route API
locationBias applied to the Google Maps Search Along Route API

Ignoring far away places with the Google Maps Search Along Route API

Returning to our original example where we searched for rest stops between Vancouver and Kelowna, you might have noticed that the search results included two rest stops in Washington State. Although kinda along the route, a quick check on Google Maps shows that making a detour to these two rest stops would take almost an hour without traffic.

How to filter for poor search results from the Search Along Route API
How to filter for poor search results from the Search Along Route API

I'll show you how to filter out places that are far away from the original route, but it's not as easy as it should be. In the routingSummaries array, you'll find the duration and distance required to detour to that place as a two-leg trip.

Calculating the detour duration using the routingSummaries object
Calculating the detour duration using the routingSummaries object

The first leg represents the travel duration and distance from the route's starting point to the place (e.g. from the origin to Place A). The second leg represents the travel duration and distance from the place to the final destination (e.g. from Place A to the destination). If you sum the duration of both these legs up and subtract them from the TRAFFIC_UNAWARE route duration returned by the Routes API, you can get the detour duration which is the duration difference between the original trip (from the origin to the destination) and the new trip (from the origin to the destination through A).

In the example above, the detour duration for Place A is calculated as 3849s + 14247s - 15278s = 2818s. Once you have the detour duration, you can set a threshold (e.g., 600 seconds or 10 minutes) and filter out any search results that exceed this limit.

Google Maps Search Along Route use cases

The Search Along Route API, like many of Google’s newer products such as Building Outlines and Entrances, Pollen, and Places Insights is very cool and an impressive technological feat. However, its practical use might be somewhat limited. Here's what I mean. Although there is value for a road trip planning app e.g. https://roadtrippers.com/ or a local tourism board e.g. https://www.hellobc.com/travel-ideas/road-trips/ to use Search Along Route to help their users find all the best stops at their destination and along the way, there isn't enough value generated to compel their users to pay for it, especially since the same functionally can be found on the Google Maps consumer app for free. This is unlike e.g. the Geocoding API, where there is tremendous value in knowing exactly where an address is so that packages can be delivered to the correct location.

Google Maps Search Along Route pricing

The Search Along Route API requires making two separate API calls. The first is to the Routes API ($5 CPM) to generate the encoded polyline. The next is to Google Text Search ($32 CPM) to find places near the route polyline that match the search term. So a single Search Along Route API will cost $0.005 + $0.032 = $0.037 (3.7 cents). As always, you can work with a Google Maps Partner to access discounted pricing.

Building a road trip planning app using the Google Maps Search Along Route API

In this last section, we are going to use the Search Along Route API to build a road trip planning app similar to RoadTrippers, Wanderlog or RV Trip Wizard. As always, we'll be using the fantastic Google Maps React component library from @vis.gl/react-google-maps to quickly scaffold our app and manage map interactions and UI in a way that is consistent with React.

There are two ways to follow along. If you have some software engineering experience, you should fork search_along_route and run the app locally. Try making small changes e.g. adding a new place type to the search filter and see if it works. If you don't want to pull code from GitHub, you can still play around with a live demo at https://search-along-route.afi.dev/.

How it works

Our road trip planning app makes it easy to find interesting stops along your route:

  1. Users enter a start and end location using an address autocomplete search box. The route is then displayed as a blue polyline on the map.
  2. Next, they select a place type from a dropdown menu. The curated list includes options like hiking areas, rest stops, gas stations, and other useful locations for long drives.
  3. Once a place type is chosen, the app calls the Search Along Route API, displaying matching locations along the route on the map.

App.jsx

How our road trip planning app is structured
How our road trip planning app is structured

App.jsx is the main entry point into our app. It handles the overall structure, routing, and layout (above). It is also responsible for calling the Routes API once and origin and destination addresses are selected, and passing the encoded route polyline over to the Text Search API to perform a search along the route.

/*** App.jsx ***/
import request from './Utils/request';

const App = () => {

  const getPolyline = async (requestBody) => {
    const routesResponse = await request('https://routes.googleapis.com/directions/v2:computeRoutes', {
      headers: {
        'X-Goog-FieldMask': 'routes.polyline',
      },
      method: 'POST',
      data: requestBody,
    });

    const polyline = routesResponse.routes ? routesResponse.routes[0] : null;

    if (!polyline) return null;

    setEncodedPolyline(polyline.polyline.encodedPolyline);
    return polyline;
  };

  const searchAlongRoute = async () => {
    if (!encodedPolyline || !selectedPlaceType) return;

    try {
      const placesResponse = await request('https://places.googleapis.com/v1/places:searchText', {
        headers: {
          'X-Goog-FieldMask':
            'places.displayName,places.formattedAddress,places.primaryType,places.id,places.location,places.rating,places.userRatingCount,places.photos',
        },
        method: 'POST',
        data: {
          textQuery: selectedPlaceType.value,
          searchAlongRouteParameters: {
            polyline: {
              encodedPolyline: encodedPolyline,
            },
          },
        },
      });

      setPlaceResults(placesResponse?.places);
    } catch (error) {
      console.error('Error fetching polyline or places:', error);
    }
  };
}

Request.js

The heavy lifting of making the API call is done in request.js, which can be found in Utils/request.js helper function. This function is imported into App.jsx via the line import request from './Utils/request'; so that it can be called with the request() method.

/*** Utils/request.js ***/
import axios from 'axios';

async function request(url, opts) {
  const { headers, ...options } = opts;

  const defaultHeaders = {
    'Content-Type': 'application/json',
    'X-Goog-Api-Key': process.env.REACT_APP_GOOGLE_API_KEY,
  };

  const config = Object.assign(
    {
      url,
      headers: Object.assign(defaultHeaders, headers),
      timeout: 60000,
    },
    options,
  );

  try {
    const response = await axios.request(config);

    return response.data;
  } catch (error) {
    console.log('Error:', error);
  }
}

export default request;

request() utilizes the Axios HTTP client library to send API requests.

💡
Axios is a promise-based HTTP client for Javascript that allows you to make requests to APIs from both the browser and Node.js.

For example, if we need to make a Search Along Routes request to the Google Text Search API within App.jsx, we would invoke request() as follows:

/*** request.js ***/
const placesResponse = await request('https://places.googleapis.com/v1/places:searchText', {
        headers: {
          'X-Goog-FieldMask':
            'places.displayName,places.formattedAddress,places.primaryType,places.id,places.location,places.rating,places.userRatingCount,places.photos',
        },
        method: 'POST',
        data: {
          textQuery: selectedPlaceType.value,
          searchAlongRouteParameters: {
            polyline: {
              encodedPolyline: encodedPolyline,
            },
          },
        },
      });

The first parameter is the request URL, which in the case for Text Search is https://places.googleapis.com/v1/places:searchText. The second is a Javascript object that contains the headers, method, and data (that includes the encodedPolyline). This data is used as the request body (see Axios request config).

The line const { headers, ...options } = opts; at the start of the request() function is an example of object destructuring with the rest operator (...). It extracts the headers property from the opts object and creates a new object (options) that contains all the remaining properties of opts except headers. All this information is stuffed into a config object:

/*** Utils/request.js ***/
const config = Object.assign(
  {
    url,
    headers: Object.assign(defaultHeaders, headers),
    timeout: 60000,
  },
  options,
);

which is immediately used to make an Axios HTTP POST request: const response = await axios.request(config);. The response is returned and used in App.jsx.

PlaceSearch.jsx

<PlaceSearch/> is a container component that wraps <PlaceAutocompleteInput/>, the address autocomplete search box for selecting the start and end points of a route. It processes the place data returned from Google Place Autocomplete, reformatting the response to make it more convenient for the subsequent call to the Search Along Route API.

/*** Components/PlaceSearch.jsx ***/
const handlePlaceSelect = useCallback(
    (place) => {
      if (!place || !placesService) return;

      placesService.getDetails(
        {
          placeId: place.place_id,
          fields: ['geometry', 'name', 'formatted_address', 'place_id'],
        },
        (result) => {
          const formatResult = {
            id: result.place_id,
            displayName: {
              text: result.name,
            },
            formattedAddress: result.formatted_address,
            location: {
              latitude: result.geometry.location.lat(),
              longitude: result.geometry.location.lng(),
            },
          };

          onSelectPlace(formatResult);
        },
      );
    },
    [placesService],
  );

PlaceAutocompleteInput.jsx

The <PlaceAutocompleteInput/> component, as the name suggests, contains a text input field that uses Google Places Autocomplete to suggest places dynamically as the user types.

Google Places Autocomplete used to retrieve the start and end points of our route
Google Places Autocomplete used to retrieve the start and end points of our route

I've already published a detailed tutorial, Google address autocomplete with the Places API, that explains how to add a Place Autocomplete widget to your website - so I won't repeat myself here (it's mostly boilerplate code anyway, and there's lots of excellent working code you can find online e.g. https://visgl.github.io/react-google-maps/examples/autocomplete).

/*** Components/PlaceAutocompleteInput.jsx ***/
import React, { useRef, useEffect, useState } from 'react';
import { useMapsLibrary } from '@vis.gl/react-google-maps';

const PlaceAutocompleteInput = ({ onPlaceSelect }) => {
  const [placeAutocomplete, setPlaceAutocomplete] = useState(null);
  const inputRef = useRef(null);
  const places = useMapsLibrary('places');

  useEffect(() => {
    if (!places || !inputRef.current) return;

    const options = {
      fields: ['place_id', 'geometry', 'name', 'formatted_address'],
    };

    setPlaceAutocomplete(new places.Autocomplete(inputRef.current, options));
  }, [places]);

  useEffect(() => {
    if (!placeAutocomplete) return;

    placeAutocomplete.addListener('place_changed', () => {
      onPlaceSelect(placeAutocomplete.getPlace());
    });
  }, [onPlaceSelect, placeAutocomplete]);

  return (
    <div className="autocomplete-container">
      <input ref={inputRef} />
    </div>
  );
};

export default PlaceAutocompleteInput;

There are three things you need to do to get autocomplete working:

  1. Add a text input field to the address search box component, and give it the ref="inputRef".
  2. Create an Autocomplete component with the places.Autocomplete method of the Maps Javascript API Places Library, and bind it to the text input field.
  3. Pass updated place data to the onPlaceSelect callback prop which gets called when a user selects a place from the Google Place Autocomplete dropdown.
/*** Components/PlaceAutocompleteInput.jsx ***/
useEffect(() => {
  if (!placeAutocomplete) return;

  placeAutocomplete.addListener("place_changed", () => {
    onPlaceSelect(placeAutocomplete.getPlace());
  });
}, [onPlaceSelect, placeAutocomplete]);

Once this is done, the parent <PlaceSearch/> component can receive the place object and reformat it, before sending it up to App.jsx.

PlaceTypeSelector.jsx

<PlaceTypeSelector/> is a customizable select/dropdown component based on the popular react-select library. It pulls a list of hardcoded place types from Constants/index.js and displays them as a list of selectable options. Each option includes an icon and label e.g. 🅿️ for "Parking".

React select dropdown used to select our desired place type
React select dropdown used to select our desired place type

Dropdown components are one of the most useful and popular UI elements out there, so it's worth spending some time to understand how to implement them effectively in a React app.

The predefined place types are imported into App.jsx using import { PLACE_TYPE_OPTIONS } from './Constants';. They are then passed as the options prop to <PlaceTypeSelector/>.

These options are structured as an array of objects, where each object contains:

  • value – A unique identifier for the place type.
  • label – The display name (a text string) of the place type.
  • icon – An encoded SVG file that functions like a React component.
/*** Components/PlaceTypeSelector.jsx ***/
import React from 'react';
import Select, { components } from 'react-select';
import './PlaceTypeSelector.scss';

const SingleValueLabel = ({ children, data, ...props }) => {
  const Icon = data.icon;
  return (
    <components.SingleValue {...props}>
      <div className="single-value-container">
        <Icon />
        <span>{children}</span>
      </div>
    </components.SingleValue>
  );
};

const MultiValueLabel = ({ data, ...props }) => {
  const Icon = data.icon;
  return (
    <components.MultiValue {...props}>
      <div className="multi-value-container">
        <Icon className="multi-value-icon" />
        <span>{data.label}</span>
      </div>
    </components.MultiValue>
  );
};

const DropdownOption = ({ data, ...props }) => {
  const Icon = data.icon;
  return (
    <components.Option {...props}>
      <div className="dropdown-option">
        <Icon className="option-icon" />
        <span>{data.label}</span>
      </div>
    </components.Option>
  );
};

const PlaceTypeSelector = ({ options, onSelectionChange }) => {
  return (
    <div className="PlaceTypeSelector">
      <label className="selector-label">Place Types</label>
      <Select
        options={options}
        components={{ SingleValue: SingleValueLabel, MultiValue: MultiValueLabel, Option: DropdownOption }}
        onChange={onSelectionChange}
      />
    </div>
  );
};

export default React.memo(PlaceTypeSelector);

PlaceTypeSelector.jsx renders a <Select/> component from the react-select library. The appearance and behavior of <Select/> adapts dynamically based on user interaction. It automatically determines which components to display, such as dropdown options, selected values, or multi-select tags, depending on how the user interacts with it.

Different components of the react select dropdown
Different components of the react select dropdown

The components prop dictates what is shown, and when. When displaying dropdown items inside the menu, the <DropdownOption/> component is used, but when a single option is selected, react-select renders the <SingleValueLabel/> component instead. Both components present the place type icon and label side by side for a consistent look.

When the user selects a place type, his choice is saved and sent back to App.jsx through the onSelectionChanged prop, where the label of his selected place is used as the textQuery to call the Text Search API. It's important to note that Text Search does not use Google Place Types. Instead, we are passing in a text string such as "Hiking Area" as a keyword (similar to how you would use Google Search), and asking Google Text Search find relevant places based on this keyword.

GoogleMap.jsx

GoogleMap.jsx is a wrapper for the react-google-maps <Map/> component. It is responsible for receiving both the encoded route polyline from the Routes API as well as the along the route place results from the Text Search API, and sending it to <Map/> for rendering.

/*** Components/Map/GoogleMap.jsx ***/
import React, { memo, useEffect } from 'react';
import { Map, useMap } from '@vis.gl/react-google-maps';
import Polyline from '../External/Polyline';
import Marker from './Marker';
import MapHandler from './MapHandler';

function GoogleMap({ polyline, places, startLocation, endLocation, onMarkerClick, activePlace }) {
  const map = useMap();

  const renderMarkers = (places) => {
    return places.map((place) => {
      return (
        <Marker
          style={{ width: 30 }}
          active={activePlace.id === place.id}
          key={place.id}
          id={place.id}
          position={place.location}
          type={place.primaryType}
          onToggle={() => onMarkerClick(place)}
        ></Marker>
      );
    });
  };

  useEffect(() => {
    if (activePlace?.id) {
      const latLng = {
        lat: activePlace.location.latitude,
        lng: activePlace.location.longitude,
      };
      map.panTo(latLng);
    }
  }, [activePlace, map]);

  return (
    <div className="GoogleMap" style={{ width: '100%', height: '100%' }}>
      <Map
        mapId={process.env.REACT_APP_GOOGLE_MAP_ID}
        defaultZoom={12}
        defaultCenter={{ lat: 49.25307278849622, lng: -123.12095840000302 }}
        gestureHandling={'greedy'}
        disableDefaultUI={true}
      >
        {startLocation && (
          <Marker
            key={startLocation.id}
            id={startLocation.id}
            position={startLocation.location}
            type="startLocation"
            style={{ width: 40, position: 'relative', top: 30 }}
          ></Marker>
        )}

        {places?.length > 0 && renderMarkers(places)}

        {endLocation && (
          <Marker
            key={endLocation.id}
            id={endLocation.id}
            position={endLocation.location}
            type="endLocation"
            style={{ width: 40, position: 'relative', top: 30 }}
          ></Marker>
        )}

        {polyline && <Polyline polyline={polyline} />}
      </Map>
      <MapHandler startLocation={startLocation} endLocation={endLocation} markers={places} />
    </div>
  );
}

export default memo(GoogleMap);

Rendering a polyline is simple - just add <Polyline/> as a child of <Map/> and pass the encoded polyline string as a prop. color (#ff9ff3 - blue), strokeWeight (4.0f) and other attributes are hardcoded in External/Polyline.jsx, which was shamelessly lifted from the Geometry Example of the react-google-maps library.

Adding markers to the <Map/> is just as easy. The renderMarkers() function iterates over the places array and adds clickable  <Marker/> components at each place.location. Clicking a marker sets it as the activePlace, which triggers <Map/> to pan to its location and scrolls the corresponding <PlaceItem/> into view.

Marker.jsx

The last component we'll look at is <Marker/>. Marker.jsx is a wrapper for Google's AdvancedMarkerElement, which allows us to create customizable, interactive markers on Google Maps using SVG files.

SVG files imported as react components
SVG files imported as react components

To render these SVG files as react components, we first import the SVG file as a React component.

import { ReactComponent as StartMarker } from '../../assets/images/start_marker.svg';

Next, we assign that ReactComponent object to the Icon variable.

/*** Components/Map/Marker.jsx ***/
const Marker = ({ id, position, type, style, onToggle, active }) => {
  let Icon;

  if (type === "startLocation") {
    Icon = StartMarker;
  }
};

Finally, in the return statement of Marker.jsx, we insert the Icon variable as an <Icon/> component.

/*** Components/Map/Marker.jsx ***/
return (
  <AdvancedMarker
    key={id}
    position={{
      lat: position.latitude,
      lng: position.longitude,
    }}
    className={`marker ${active ? "active" : ""}`}
    zIndex={active ? 2 : 1}
    onClick={onToggle}
  >
    <Icon style={style} />
  </AdvancedMarker>
);

<Icon/> is for all intents and purposes a native JSX element, so it can be styled by applying props like fill, width, and height.

Deploy and run

To run the app locally, clone the search_along_route repository, update the .env file with your Google Maps API key and Map ID, and then run npm install to install dependencies and npm run to start the app. Alternatively, you can view the Search Along Route demo online at: https://search-along-route.afi.dev/.

Closing thoughts

I maintain this blog and write code so that I can share my expertise with others. I rarely build apps for myself these days, which is why I'm so excited about the Search Along Route API. It's 15th March here in Vancouver, Canada where I live. Summer is almost here, and for me that means camping, hiking and biking all over the Pacific Northwest. And driving, lots of driving to get from one place to the next.

Hiking areas along the route between Revelstoke and Golden in British Columbia
Hiking areas along the route between Revelstoke and Golden in British Columbia

I was super motivated to build the road trip planner at https://search-along-route.afi.dev/ because I'd often plan my drives around visits to gas stations, supermarkets, rest stops and short hikes, and was thrilled to finally find an API that could do this for me in an automated way.

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

Next: Part 5: How to draw a route on Google Maps for Android with the Routes API