Search Along Route with Places API

This document describes how to find a hotel, a restaurant or a gas station along a planned route. You will learn how to use Routes API to get a route polyline and use that with Places API Search Along Route (SAR) request. Also you will learn how to get best results by setting the search origin along the route, for example 2 hours into the trip.

Routes API

In order to search places along the route, we are going to use Routes API. Route data from the Routes API response is a series of LatLong coordinates from the origin to the destination. Route data contains legs and steps which follow the road network.

Routes are also returned as an encoded polyline, which you pass on as an input parameter to the SAR request. Polyline encoding is a lossy compression algorithm that lets you to store a series of coordinates as a single string. Getting the polyline from Routes API is not mandatory. You may create the data yourself but for purposes of this example, Routes API is a fast and sure way of getting the required data.

In this tutorial we use a route from London (-37.8167,144.9619) to Manchester (-37.8155, 144.9663)

Route from London to Manchester

Route in the example: London to Manchester

Step 1: Get a route from the Routes API

To get a route from the Routes API, you will need to provide the following information:

  • The origin and destination locations
  • The mode of transportation (driving, walking, etc.)
  • Any waypoints (optional)
  • Any preferences (avoid tolls, avoid highways, etc.)
  • Traffic aware routing preference will give you the most precise estimates but it is computationally heavier operation and thus adds to latency of the response.
{"origin":{
    "location": {
        "latLng":{
            "latitude":  -37.8167,
            "longitude": 144.9619
        }
    }
},
"destination":{
    "location": {
        "latLng":{
            "latitude":-37.8155,
            "longitude": 144.9663
        }
    }
},
"routingPreference":"TRAFFIC_AWARE",
"travelMode":"DRIVE"
}

When making the call make sure to include the "encodedPolyline" field in the headers field mask.

headers = {
    "Content-Type": "application/json",
    "X-Goog-FieldMask": "routes.distanceMeters,routes.duration,routes.legs,routes.polyline.encodedPolyline"
}

The full documentation with examples of how to get a route and get route polylines.

Once you have provided this information in the request, the Routes API will return a route object. The route object will contain the following information:

  • The total distance of the route
  • The total duration of the route
  • The legs and steps of the route
  • The encoded polyline of the route, legs and steps.
{
  "routes": [
    {
      "legs": [
        {
          "distanceMeters": 321799,
          "duration": "15401s",
          "staticDuration": "14518s",
          "polyline": {
            "encodedPolyline": "y_kyH`_XOr@q@xKGnBBZ|AlGPj@Y^k@^MEqAfAQLK?eI … <rest of content removed for readability>"
          },
          "startLocation": {
            "latLng": {
              "latitude": 51.507334500000006,
              "longitude": -0.1280107
            }
          },
          "endLocation": {
            "latLng": {
              "latitude": 53.4808513,
              "longitude": -2.2425864
            }
          },
          "steps": [
            {
              "distanceMeters": 320,
              "staticDuration": "82s",
              "polyline": {
                "encodedPolyline": "y_kyH`_XOr@q@xKGnBBZ|AlG"
              },
              "startLocation": {
                "latLng": {
                  "latitude": 51.507334500000006,
                  "longitude": -0.1280107
                }
              },
              "endLocation": {
                "latLng": {
                  "latitude": 51.507207,
                  "longitude": -0.1323681
                }
              },
              "navigationInstruction": {
                "maneuver": "DEPART",
                "instructions": "Head northwest on Trafalgar Sq/A4 toward Spring Gardens\nContinue to follow A4\nLeaving toll zone\nEntering toll zone\nLeaving toll zone in 210m at Haymarket"
              },
              "localizedValues": {
                "distance": {
                  "text": "0.3 km"
                },
                "staticDuration": {
                  "text": "1 min"
                }
              },
# rest of the response removed for readability

Step 2: Search Along the Route request

Places API Text Search has a Search Along Route request that lets you to search for places along a route. To do a Search Along Route request, you will need to provide the following minimum information:

  • Field mask of which fields are returned in the response
  • A valid API key for the API enabled in the Google Cloud console
  • Search text string stating what places you are looking for, for example "spicy vegetarian restaurant"
  • The encoded polyline of the route, retrieved from the previous Routes API call
  • Url for the Places Text Search API endpoint
import requests

url = 'https://places.googleapis.com/v1/places:searchText'
api_key = 'YOUR_API_KEY'  # Replace with your actual API key
route_polyline = 'YOUR_ROUTE_POLYLINE'  # Replace with your encoded route polyline

headers = {
    'Content-Type': 'application/json',
    'X-Goog-Api-Key': api_key,
    'X-Goog-FieldMask': 'places.displayName,places.formattedAddress,places.priceLevel'
}

data = {
    "textQuery":
 "Spicy Vegetarian Food",
    "searchAlongRouteParameters": {
        "polyline": {
            "encodedPolyline": route_polyline
        }
    }
}

response = requests.post(url, headers=headers, json=data)

Example request data

The Search Along Route request will return a list of places that are located along the route. Here is a short part of the example data. The length of the response can be limited by setting the maximum number of results parameters and adding more fields of course grows the amount of data received. For more details about the Places API response see the documentation.

{
  "places": [
    {
      "formattedAddress": "33 Haymarket, London SW1Y 4HA, UK",
      "displayName": {
        "text": "xxx",
        "languageCode": "en"
      }
    },
    {
      "formattedAddress": "224 Piccadilly, London W1J 9HP, UK",
      "priceLevel": "PRICE_LEVEL_MODERATE",
      "displayName": {
        "text": "yyy",
        "languageCode": "en"
      }
    },
    {
      "formattedAddress": "63 Neal St, London WC2H 9PJ, UK",
      "displayName": {
        "text": "zzz",
        "languageCode": "en"
      }
    },

Example response data

Routing summary and detour times

Finding just the locations is great but it will be useful to add the information of how much time it takes to go to these locations. SAR in Places API Text Search can also return a routing summaries field that contains both the duration and distance to travel. Routing summaries data field is a child of the response root, so you must not include the "places." prefix in the field mask.

'X-Goog-FieldMask': 'places.displayName,places.formattedAddress,places.priceLevel,routingSummaries'

In order to get the summaries, you must also provide the origin location parameter for the search which is used for the calculations.

"routingParameters": {
      "origin": {
        "latitude":  -37.8167,
        "longitude": 144.9619
      }
    }

When you receive the response it has a new section with routing summary containing legs that have duration and distance in meters.

"routingSummaries": [
    {
      "legs": [
        {
          "duration": "662s",
          "distanceMeters": 3093
        }
      ]
    },

Next we have a look at how you can define where along the route to start the search.

Step 3: Get location 2 hours along the route

Consider a normal use case where the driver wants to find restaurants not at the start of the route, but further down the road. In our example the ride from London to Manchester is about 4 hours. The driver wants to find a restaurant 2 hours along the route. This request gets us the duration of 120 minutes * 60 seconds = 7200 seconds.

In the Routes API response we have the duration of each leg of the route and each step of a leg. Make sure to include the "legs" field in the field mask in your request. Loop through the legs and steps until the accumulated duration reaches the 2 hours or 7200 second limit. Then we have found the leg and step which to set as the origin of the SAR request

To speed up your work, you might want to try out the polyline library for Python. You can use it to get the coordinates from the "polyline.endodedPolyline" data field.

Run the following commands in your environment terminal.

> pip install polyline
import requests
import polyline

# We've covered getting a Routes API response earlier,
data = response.json()

  # Extract the first route and its encoded polyline
  route = data["routes"][0]
  polyline_points = polyline.decode(route["polyline"]["encodedPolyline"])

  # Calculate total duration of the route in seconds
  total_duration_seconds = route["duration"]

  # Calculate the desired time offset in seconds, 2h = 120 minutes * 60
  desired_time_offset_seconds = time_offset_minutes * 60

  # Iterate through the legs and steps to find the point at the desired time offset
  elapsed_time_seconds = 0
  for leg in route["legs"]:
      for step in leg["steps"]:
          step_duration_seconds = step["staticDuration"]

          # Check if the desired time offset falls within this step, remove last "s" from string and convert to int
          second_value = int(step_duration_seconds[:-1])
          if elapsed_time_seconds + second_value >= desired_time_offset_seconds:
              # Interpolate to find the exact point within the step
              fraction_of_step = (desired_time_offset_seconds - elapsed_time_seconds) / second_value
              step_polyline_points = polyline.decode(step["polyline"]["encodedPolyline"])
              index = int(len(step_polyline_points) * fraction_of_step)
              return step_polyline_points[index]

          elapsed_time_seconds += second_value

  # If the point is not found (e.g., time offset exceeds route duration)
  return None

Now that we have found the location on the route which is 2 hours into the trip, we can use that in the request. Simply add the latitude and longitude in the "origin" parameter, which is in turn part of the "routingParameters" parameter. The "routingSummaries" data field which we covered previously is recommended. You may also add additional parameters such as travel mode and instructions to avoid tolls if you so want.


"routingParameters": {
    "origin": {
      "latitude": xx.xxxx,
      "longitude": yy.yyyy
    },
    "travelMode":"DRIVE",
    "routeModifiers": {
      "avoidTolls": true
    }
  }

Route with search results

Example results (car icon added to show search origin).

As you can see in the image, the API returns places which are biased to the end of the route, results starting about mid-trip. The search is still empowered by the same Google Maps Platform data which takes into account place relevance and distance among other factors.

Conclusion

In this tutorial we learned how to combine two Google Maps Platform APIs, Routes and Places, to plan a trip and find places to eat after 2 hours into the journey. The steps needed to take are getting an encoded polyline containing the latitude and longitude coordinates for each step of the way and setting the Search Along Route request origin to get the best results.

This feature adds a powerful new tool to the already existing text search and nearby search available in the Places API. The logical follow up would be adding location services so that you might use the driver location as a starting point for finding the optimal search origin. In addition this feature would work perfectly together with an in-car voice assistant to which you would voice your preferred dining options.

Next Actions

Suggested Further Reading:

Contributors

Google maintains this document. The following contributor originally wrote it.

Principal author: Mikko Toivanen | Google Maps Platform Solutions Engineer