> ## Content Index
> Fetch the complete content index at: https://blog.afi.io/llms.txt
> Use this file to discover other available public pages before exploring further.

# Google Maps Search Along Route
- URL: https://blog.afi.io/blog/google-maps-search-along-route/
- Published: 2025-03-12T04:03:11.000Z
- Updated: 2026-08-21T05:38:49.000Z
- Description: Use the Google Search Along Route API to identify places along a route that match a free form text string.
- Author: Afian Anwar
- Tags: googlemaps

Ever been on the road and needed to find a restaurant, restroom, or gas station nearby? The Google Maps [Search Along Route API](https://developers.google.com/maps/documentation/places/web-service/sar-overview?ref=blog.afi.io) 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](https://github.com/afilabs/search%5Falong%5Froute?ref=blog.afi.io) / [demo](https://search-along-route.afi.dev/?ref=blog.afi.io)) that suggests cool places to check out along the way.

![The Google Maps Search Along Route API helps you find places along your route](https://storage.ghost.io/c/c6/4d/c64da7e8-63a6-4cff-acdc-2782a6ebc377/content/images/2025/03/Google-Search-Along--1-.png)

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](https://blog.afi.io/blog/a-developers-guide-to-the-google-routes-api/)  
Part 2: [Plan a route with multiple stops using the Routes API](https://blog.afi.io/blog/plan-a-route-with-multiple-stops-using-the-routes-api/)  
Part 3: [Using the Google Distance Matrix API for taxi dispatch ](https://www.afi.io/blog/using-the-google-distance-matrix-api-for-taxi-dispatch/?ref=blog.afi.io)  
**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 RouteUse the Google Search Along Route API to find places along a route that match a free form text string![](https://storage.ghost.io/c/c6/4d/c64da7e8-63a6-4cff-acdc-2782a6ebc377/content/images/icon/logo192-13.png)![](https://storage.ghost.io/c/c6/4d/c64da7e8-63a6-4cff-acdc-2782a6ebc377/content/images/thumbnail/logo512-13.png)](https://search-along-route.afi.dev/?ref=blog.afi.io)

### 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](https://storage.ghost.io/c/c6/4d/c64da7e8-63a6-4cff-acdc-2782a6ebc377/content/images/2025/03/image.png)

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](https://storage.ghost.io/c/c6/4d/c64da7e8-63a6-4cff-acdc-2782a6ebc377/content/images/2025/03/image-1.png)

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](https://storage.ghost.io/c/c6/4d/c64da7e8-63a6-4cff-acdc-2782a6ebc377/content/images/2025/03/image-2.png)

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](https://developers.google.com/maps/documentation/places/web-service/search-along-route?ref=blog.afi.io) 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](https://blog.afi.io/blog/google-places-text-search/) with `searchAlongRouteParameters` added to the request body. To keep things simple, I'll just call it *Search Along Route*. It uses the [encoded polyline](https://developers.google.com/maps/documentation/routes/traffic%5Fon%5Fpolylines?ref=blog.afi.io) generated by the [Routes API](https://blog.afi.io/blog/a-developers-guide-to-the-google-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](https://storage.ghost.io/c/c6/4d/c64da7e8-63a6-4cff-acdc-2782a6ebc377/content/images/2025/03/image-7.png)

Stops A, B and C along a route

Calling [Text Search](https://developers.google.com/maps/documentation/places/web-service/text-search?ref=blog.afi.io) 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](https://storage.ghost.io/c/c6/4d/c64da7e8-63a6-4cff-acdc-2782a6ebc377/content/images/2025/03/image-9.png)

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/](https://search-along-route.afi.dev/?ref=blog.afi.io)). This is one of my all-time favorite summer road trips starting from Vancouver.

![Google Maps Search Along Route example](https://storage.ghost.io/c/c6/4d/c64da7e8-63a6-4cff-acdc-2782a6ebc377/content/images/2025/03/Google-Direction--6-.png)

Google Maps Search Along Route example

To get started, we first call the [Compute Routes endpoint of the Routes API](https://blog.afi.io/blog/plan-a-route-with-multiple-stops-using-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](https://routes.googleapis.com/directions/v2:computeRoutes?ref=blog.afi.io)

**Headers**  
Content-Type: *application/json*  
X-Goog-Api-Key: *YOUR\_API\_KEY*  
X-Goog-FieldMask: *routes.polyline*

**Request Body**

```JSON
{
    "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](https://developers.google.com/maps/documentation/places/web-service/search-text?ref=blog.afi.io) as a `searchAlongRouteParameters.polyline.encodedPolyline` like so:

**Google Text Search API**

Endpoint `POST` [https://places.googleapis.com/v1/places:searchText](https://places.googleapis.com/v1/places:searchText?ref=blog.afi.io)

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](https://storage.ghost.io/c/c6/4d/c64da7e8-63a6-4cff-acdc-2782a6ebc377/content/images/2025/03/Screenshot-2025-03-10-at-9.09.46-PM.png)

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](https://developers.google.com/maps/documentation/javascript/reference/geometry?ref=blog.afi.io#encoding.decodePath) 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](https://storage.ghost.io/c/c6/4d/c64da7e8-63a6-4cff-acdc-2782a6ebc377/content/images/2025/03/image-14.png)

Applying locationBias to the middle 50% of the route

1. Apply the [LatLngBounds.extend() method](https://developers.google.com/maps/documentation/javascript/reference/coordinates?ref=blog.afi.io#LatLngBounds.extend) of the [Google Maps Geometry Library](https://developers.google.com/maps/documentation/javascript/geometry?ref=blog.afi.io) 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](https://storage.ghost.io/c/c6/4d/c64da7e8-63a6-4cff-acdc-2782a6ebc377/content/images/2025/03/image-15.png)

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.

```JSON
{
    "locationBias": {
        "rectangle": {
            "low": {
                "latitude": 49.36168000000001,
                "longitude": -121.44006000000002
            },
            "high": {
                "latitude": 50.09975000000001,
                "longitude": -120.55021
            }
        }
    }
}
```

1. Finally, use the [LatLngBounds.getSouthWest()](https://developers.google.com/maps/documentation/javascript/reference/coordinates?ref=blog.afi.io#LatLngBounds.getSouthWest) method to retrieve the coordinates for `low` and [LatLngBounds.getNorthEast()](https://developers.google.com/maps/documentation/javascript/reference/coordinates?ref=blog.afi.io#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](https://storage.ghost.io/c/c6/4d/c64da7e8-63a6-4cff-acdc-2782a6ebc377/content/images/2025/03/Screenshot-2025-03-11-at-10.41.20-PM.png)

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](https://storage.ghost.io/c/c6/4d/c64da7e8-63a6-4cff-acdc-2782a6ebc377/content/images/2025/03/image-16.png)

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 ](https://storage.ghost.io/c/c6/4d/c64da7e8-63a6-4cff-acdc-2782a6ebc377/content/images/2025/03/image-17.png)

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](https://blog.afi.io/blog/google-maps-building-outlines-and-entrances-api/), [Pollen](https://mapsplatform.google.com/maps-products/pollen/?ref=blog.afi.io), and [Places Insights](https://developers.google.com/maps/documentation/places-insights/overview?ref=blog.afi.io) 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/](https://roadtrippers.com/?ref=blog.afi.io) or a local tourism board e.g. [https://www.hellobc.com/travel-ideas/road-trips/](https://www.hellobc.com/travel-ideas/road-trips/?ref=blog.afi.io) 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](https://developers.google.com/maps/documentation/geocoding/overview?ref=blog.afi.io), 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](https://blog.afi.io/blog/plan-a-route-with-multiple-stops-using-the-routes-api/) ($5 CPM) to generate the encoded polyline. The next is to [Google Text Search](https://developers.google.com/maps/documentation/places/web-service/text-search?ref=blog.afi.io) ($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](https://cloud.google.com/find-a-partner/?products=Google+Maps+Platform&ref=blog.afi.io) 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](https://roadtrippers.com/?ref=blog.afi.io), [Wanderlog](https://wanderlog.com/?ref=blog.afi.io) or [RV Trip Wizard](https://tripwizard.rvlife.com/?ref=blog.afi.io). As always, we'll be using the fantastic Google Maps React component library from [@vis.gl/react-google-maps](https://visgl.github.io/react-google-maps/?ref=blog.afi.io) to quickly scaffold our app and manage map interactions and UI in a way that is consistent with [React](https://react.dev/?ref=blog.afi.io).

There are two ways to follow along. If you have some software engineering experience, you should fork [search\_along\_route](https://github.com/afilabs/search%5Falong%5Froute?ref=blog.afi.io) 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/](https://search-along-route.afi.dev/?ref=blog.afi.io).

**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](https://blog.afi.io/blog/google-address-autocomplete-with-the-places-api/) 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](https://storage.ghost.io/c/c6/4d/c64da7e8-63a6-4cff-acdc-2782a6ebc377/content/images/2025/03/image-20.png)

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](https://developers.google.com/maps/documentation/routes?ref=blog.afi.io) once and origin and destination addresses are selected, and passing the encoded route polyline over to the [Text Search API](https://developers.google.com/maps/documentation/places/web-service/text-search?ref=blog.afi.io) 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](https://axios-http.com/?ref=blog.afi.io) to send API requests. 

💡

[Axios](https://www.npmjs.com/package/axios?ref=blog.afi.io) 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](https://places.googleapis.com/v1/places:searchText?ref=blog.afi.io). 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](https://axios-http.com/docs/req%5Fconfig?ref=blog.afi.io)).

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](https://blog.afi.io/blog/google-address-autocomplete-with-the-places-api/) search box for selecting the start and end points of a route. It processes the `place` data returned from [Google Place Autocomplete](https://developers.google.com/maps/documentation/places/web-service/place-autocomplete?ref=blog.afi.io), 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](https://blog.afi.io/blog/google-address-autocomplete-with-the-places-api/) to suggest places dynamically as the user types.

![Google Places Autocomplete used to retrieve the start and end points of our route](https://storage.ghost.io/c/c6/4d/c64da7e8-63a6-4cff-acdc-2782a6ebc377/content/images/2025/03/image-21.png)

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](https://blog.afi.io/blog/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](https://visgl.github.io/react-google-maps/examples/autocomplete?ref=blog.afi.io)). 

```
/*** 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](https://developers.google.com/maps/documentation/javascript/places?ref=blog.afi.io), 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](https://react-select.com/home?ref=blog.afi.io) 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](https://storage.ghost.io/c/c6/4d/c64da7e8-63a6-4cff-acdc-2782a6ebc377/content/images/2025/03/image-22.png)

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](https://react.dev/?ref=blog.afi.io) 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/>`.

![](https://storage.ghost.io/c/c6/4d/c64da7e8-63a6-4cff-acdc-2782a6ebc377/content/images/2025/03/Screenshot-2025-03-14-at-1.55.52-PM.png)

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](https://storage.ghost.io/c/c6/4d/c64da7e8-63a6-4cff-acdc-2782a6ebc377/content/images/2025/03/image-23.png)

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](https://developers.google.com/maps/documentation/places/web-service/text-search?ref=blog.afi.io). It's important to note that Text Search does not use [Google Place Types](https://developers.google.com/maps/documentation/places/web-service/place-types?ref=blog.afi.io). 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](https://visgl.github.io/react-google-maps/docs/api-reference/components/map?ref=blog.afi.io). 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](https://visgl.github.io/react-google-maps/examples/geometry?ref=blog.afi.io) of the [react-google-maps](https://visgl.github.io/react-google-maps/?ref=blog.afi.io) library.

Adding markers to the `<Map/>` is just as easy. The `renderMarkers()` function iterates over the `places` array and adds clickable [<Marker/> components](https://visgl.github.io/react-google-maps/docs/api-reference/components/marker?ref=blog.afi.io) 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](https://developers.google.com/maps/documentation/javascript/reference/advanced-markers?ref=blog.afi.io), which allows us to create customizable, interactive markers on Google Maps using SVG files.

![SVG files imported as react components](https://storage.ghost.io/c/c6/4d/c64da7e8-63a6-4cff-acdc-2782a6ebc377/content/images/2025/03/Screenshot-2025-03-14-at-10.53.08-PM.png)

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](https://github.com/afilabs/search%5Falong%5Froute?ref=blog.afi.io) 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/](https://search-along-route.afi.dev/?ref=blog.afi.io).

### 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](https://storage.ghost.io/c/c6/4d/c64da7e8-63a6-4cff-acdc-2782a6ebc377/content/images/2025/03/Screenshot-2025-03-15-at-1.01.16-AM.png)

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/](https://search-along-route.afi.dev/?ref=blog.afi.io) 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.

**This article was written by** [**Afi Labs**](https://afi.io/?ref=blog.afi.io)**, a** [**Google Maps Premier Partner**](https://www.afi.io/?ref=blog.afi.io) **and reseller. We build route optimization, navigation, and fleet tracking software on Google Maps, and offer volume pricing on GMP licensing.** [**Talk to an engineer**](https://www.afi.io/contact%5Fus?ref=blog.afi.io) **or** [**follow Afian on LinkedIn**](https://www.linkedin.com/in/afian-anwar/?ref=blog.afi.io)**.**

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