Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Exceed 23 waypoint per request limit on Google Directions API (Business/Work level)

I would like to use the google directions API to develop route planning software for a company that handles snowplows in the winter and landscaping in the summer. One of the customers requirements is that he be able to calculate routes with at least 30 ( preferably more ) waypoints. According to the documentation (quoted below) even Google Maps API for Work customers are limited to just 23 waypoints per request.

Use of the Google Directions API is subject to a query limit of 2,500 directions requests per day. Individual directions requests may contain up to 8 intermediate waypoints in the request. Google Maps API for Work customers may query up to 100,000 directions requests per day, with up to 23 waypoints allowed in each request.

Is anyone aware of a workaround -- any way at all -- to get around this?

Also -- might it be possible to use a workaround for the free API? I hear the premier accounts are quite expensive.

Thanks!! Marc

like image 233
Marc H Avatar asked Jan 08 '12 18:01

Marc H


People also ask

How many waypoints can you set on Google Maps?

You can add up to nine stops on Google Maps.

Is Google Directions API free?

The Directions API uses a pay-as-you-go pricing model. Directions API requests generate calls to one of two SKUs depending on the type of request: basic or advanced. Along with the overall Google Terms of Use, there are usage limits specific to the Directions API.

How much does Google Directions API cost?

Google Maps Platform offers a $200 monthly credit for Maps, Routes, and Places (see Billing Account Credits). With the $200 monthly credit, some customers find their use cases are at no charge. You won't be charged until your usage exceeds $200 in a month.


2 Answers

function initMap() {      var service = new google.maps.DirectionsService;      var map = new google.maps.Map(document.getElementById('map'));        // list of points      var stations = [          {lat: 48.9812840, lng: 21.2171920, name: 'Station 1'},          {lat: 48.9832841, lng: 21.2176398, name: 'Station 2'},          {lat: 48.9856443, lng: 21.2209088, name: 'Station 3'},          {lat: 48.9861461, lng: 21.2261563, name: 'Station 4'},          {lat: 48.9874682, lng: 21.2294855, name: 'Station 5'},          {lat: 48.9909244, lng: 21.2295512, name: 'Station 6'},          {lat: 48.9928871, lng: 21.2292352, name: 'Station 7'},          {lat: 48.9921334, lng: 21.2246742, name: 'Station 8'},          {lat: 48.9943196, lng: 21.2234792, name: 'Station 9'},          {lat: 48.9966345, lng: 21.2221262, name: 'Station 10'},          {lat: 48.9981191, lng: 21.2271386, name: 'Station 11'},          {lat: 49.0009168, lng: 21.2359527, name: 'Station 12'},          {lat: 49.0017950, lng: 21.2392890, name: 'Station 13'},          {lat: 48.9991912, lng: 21.2398272, name: 'Station 14'},          {lat: 48.9959850, lng: 21.2418410, name: 'Station 15'},          {lat: 48.9931772, lng: 21.2453901, name: 'Station 16'},          {lat: 48.9963512, lng: 21.2525850, name: 'Station 17'},          {lat: 48.9985134, lng: 21.2508423, name: 'Station 18'},          {lat: 49.0085000, lng: 21.2508000, name: 'Station 19'},          {lat: 49.0093000, lng: 21.2528000, name: 'Station 20'},          {lat: 49.0103000, lng: 21.2560000, name: 'Station 21'},          {lat: 49.0112000, lng: 21.2590000, name: 'Station 22'},          {lat: 49.0124000, lng: 21.2620000, name: 'Station 23'},          {lat: 49.0135000, lng: 21.2650000, name: 'Station 24'},          {lat: 49.0149000, lng: 21.2680000, name: 'Station 25'},          {lat: 49.0171000, lng: 21.2710000, name: 'Station 26'},          {lat: 49.0198000, lng: 21.2740000, name: 'Station 27'},          {lat: 49.0305000, lng: 21.3000000, name: 'Station 28'},      ];            // Zoom and center map automatically by stations (each station will be in visible map area)      var lngs = stations.map(function(station) { return station.lng; });      var lats = stations.map(function(station) { return station.lat; });      map.fitBounds({          west: Math.min.apply(null, lngs),          east: Math.max.apply(null, lngs),          north: Math.min.apply(null, lats),          south: Math.max.apply(null, lats),      });            // Show stations on the map as markers      for (var i = 0; i < stations.length; i++) {          if (!stations[i].name)              continue;          new google.maps.Marker({              position: stations[i],              map: map,              title: stations[i].name          });      }        // Divide route to several parts because max stations limit is 25 (23 waypoints + 1 origin + 1 destination)      for (var i = 0, parts = [], max = 8 - 1; i < stations.length; i = i + max)          parts.push(stations.slice(i, i + max + 1));        // Callback function to process service results      var service_callback = function(response, status) {          if (status != 'OK') {              console.log('Directions request failed due to ' + status);              return;          }          var renderer = new google.maps.DirectionsRenderer;          renderer.setMap(map);          renderer.setOptions({ suppressMarkers: true, preserveViewport: true });          renderer.setDirections(response);      };                // Send requests to service to get route (for stations count <= 25 only one request will be sent)      for (var i = 0; i < parts.length; i++) {          // Waypoints does not include first station (origin) and last station (destination)          var waypoints = [];          for (var j = 1; j < parts[i].length - 1; j++)              waypoints.push({location: parts[i][j], stopover: false});          // Service options          var service_options = {              origin: parts[i][0],              destination: parts[i][parts[i].length - 1],              waypoints: waypoints,              travelMode: 'WALKING'          };          // Send request          service.route(service_options, service_callback);      }    }
html, body {      height: 100%;      margin: 0;      padding: 0;  }  #map {      height: 100%;           width: 100%;      height: 100%;  }
<div id="map"></div>    <!-- without API KEY set variable "max" to 8 -->  <script async defer src="https://maps.googleapis.com/maps/api/js?callback=initMap"></script>    <!-- with API KEY set variable "max" to 25 -->  <!-- <script async defer src="https://maps.googleapis.com/maps/api/js?callback=initMap&key=YOUR_API_KEY"></script>-->

With following code you can use as many waypoints as you need and you will never get error MAX_WAYPOINTS_EXCEEDED. Do not forget to replace "YOUR_API_KEY" to your API KEY or remove &key=YOUR_API_KEY from google API URL and set variable "max" to 8 (max = 25 when using API KEY, max = 8 when not using API KEY).

<style> html, body { height: 100%; margin: 0; padding: 0; } #map { height: 100%; width: 100%; height: 100%; } </style> <div id="map"></div> <script>   function initMap() {     var service = new google.maps.DirectionsService;     var map = new google.maps.Map(document.getElementById('map'));      // list of points     var stations = [         {lat: 48.9812840, lng: 21.2171920, name: 'Station 1'},         {lat: 48.9832841, lng: 21.2176398, name: 'Station 2'},         {lat: 48.9856443, lng: 21.2209088, name: 'Station 3'},         {lat: 48.9861461, lng: 21.2261563, name: 'Station 4'},         {lat: 48.9874682, lng: 21.2294855, name: 'Station 5'},         {lat: 48.9909244, lng: 21.2295512, name: 'Station 6'},         {lat: 48.9928871, lng: 21.2292352, name: 'Station 7'},         {lat: 48.9921334, lng: 21.2246742, name: 'Station 8'},         {lat: 48.9943196, lng: 21.2234792, name: 'Station 9'},         {lat: 48.9966345, lng: 21.2221262, name: 'Station 10'},         {lat: 48.9981191, lng: 21.2271386, name: 'Station 11'},         {lat: 49.0009168, lng: 21.2359527, name: 'Station 12'},         {lat: 49.0017950, lng: 21.2392890, name: 'Station 13'},         {lat: 48.9991912, lng: 21.2398272, name: 'Station 14'},         {lat: 48.9959850, lng: 21.2418410, name: 'Station 15'},         {lat: 48.9931772, lng: 21.2453901, name: 'Station 16'},         {lat: 48.9963512, lng: 21.2525850, name: 'Station 17'},         {lat: 48.9985134, lng: 21.2508423, name: 'Station 18'},         {lat: 49.0085000, lng: 21.2508000, name: 'Station 19'},         {lat: 49.0093000, lng: 21.2528000, name: 'Station 20'},         {lat: 49.0103000, lng: 21.2560000, name: 'Station 21'},         {lat: 49.0112000, lng: 21.2590000, name: 'Station 22'},         {lat: 49.0124000, lng: 21.2620000, name: 'Station 23'},         {lat: 49.0135000, lng: 21.2650000, name: 'Station 24'},         {lat: 49.0149000, lng: 21.2680000, name: 'Station 25'},         {lat: 49.0171000, lng: 21.2710000, name: 'Station 26'},         {lat: 49.0198000, lng: 21.2740000, name: 'Station 27'},         {lat: 49.0305000, lng: 21.3000000, name: 'Station 28'},         // ... as many other stations as you need     ];      // Zoom and center map automatically by stations (each station will be in visible map area)     var lngs = stations.map(function(station) { return station.lng; });     var lats = stations.map(function(station) { return station.lat; });     map.fitBounds({         west: Math.min.apply(null, lngs),         east: Math.max.apply(null, lngs),         north: Math.min.apply(null, lats),         south: Math.max.apply(null, lats),     });      // Show stations on the map as markers     for (var i = 0; i < stations.length; i++) {         new google.maps.Marker({             position: stations[i],             map: map,             title: stations[i].name         });     }      // Divide route to several parts because max stations limit is 25 (23 waypoints + 1 origin + 1 destination)     for (var i = 0, parts = [], max = 25 - 1; i < stations.length; i = i + max)         parts.push(stations.slice(i, i + max + 1));      // Service callback to process service results     var service_callback = function(response, status) {         if (status != 'OK') {             console.log('Directions request failed due to ' + status);             return;         }         var renderer = new google.maps.DirectionsRenderer;         renderer.setMap(map);         renderer.setOptions({ suppressMarkers: true, preserveViewport: true });         renderer.setDirections(response);     };      // Send requests to service to get route (for stations count <= 25 only one request will be sent)     for (var i = 0; i < parts.length; i++) {         // Waypoints does not include first station (origin) and last station (destination)         var waypoints = [];         for (var j = 1; j < parts[i].length - 1; j++)             waypoints.push({location: parts[i][j], stopover: false});         // Service options         var service_options = {             origin: parts[i][0],             destination: parts[i][parts[i].length - 1],             waypoints: waypoints,             travelMode: 'WALKING'         };         // Send request         service.route(service_options, service_callback);     }   } </script> <script async defer src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap"></script> 

You can see screen here.

fiddle with show/hide line buttons

like image 147
mikep Avatar answered Sep 29 '22 04:09

mikep


You are correct the premier pricing is rather expensive starting at $10,000, last time I spoke with a google rep on the phone.

I found a workaround that I put into place to in a way bypasss the 8 waypoints limitation. I was able to make it work.

I did this by receiving my waypoints and breaking them up into different routes but drawing them together as the same route.

Example being if there were 30 waypoints needed I would draw 4 lines, but with the same color etc. So, basically you cut the waypoints into different routes calling the directions renderer each time as if it was a different route. The key is after the first route that the next route has to start with the last waypoint of the previous route (this makes sure that the route lines are connected to each other)

It works but you need to write a lot more code than what you would if you had a premier account, and you are calling for directions a lot more in this instance.

I have searched and thought about other ways to do this without having a premier account and have failed.

Although, I when speaking with google they did say that they intended on creating a tiered structure of payment for customers with different wants/needs. For instance, if a customer just needed more waypts and not a bunch more direction requests.

Hope this helps, as it worked for me in a practice application.

like image 35
Bill Blankenship Avatar answered Sep 29 '22 04:09

Bill Blankenship