You're all set!

To start developing, please head over to our developer documentation.

Activate the Google Maps Roads API

To get you started we'll guide you through the Google Developers Console to do a few things first:

  1. Create or choose a project
  2. Activate the Google Maps Roads API
  3. Create appropriate keys
Continue

Snap to Roads

The Google Maps Roads API takes up to 100 GPS points collected along a route, and returns a similar set of data, with the points snapped to the most likely roads the vehicle was traveling along. Optionally, you can request that the points be interpolated, resulting in a path that smoothly follows the geometry of the road.

Requests

A request to snap to road must be sent via HTTPS, and takes the following form:

https://roads.googleapis.com/v1/snapToRoads?parameters&key=YOUR_API_KEY

Parameter Usage

Required Parameters

  • path — The path to be snapped. The path parameter accepts a list of latitude/longitude pairs. Latitude and longitude values should be separated by commas. Coordinates should be separated by the pipe character: "|". For example: path=60.170880,24.942795|60.170879,24.942796|60.170877,24.942796.

    Note: The snapping algorithm works best for points that are not too far apart. If you observe odd snapping behavior, try creating paths that have points closer together. To ensure the best snap-to-road quality, you should aim to provide paths on which consecutive pairs of points are within 300m of each other. This will also help in handling any isolated, long jumps between consecutive points caused by GPS signal loss, or noise.

  • key — Your application's API key. Your application must identify itself every time it sends a request to the Google Maps Roads API by including an API key with each request. Learn how to get a key.

Optional Parameters

  • interpolate — Whether to interpolate a path to include all points forming the full road-geometry. When true, additional interpolated points will also be returned, resulting in a path that smoothly follows the geometry of the road, even around corners and through tunnels. Interpolated paths will most likely contain more points than the original path. Defaults to false.

Responses

For each valid request, the Google Maps Roads API will return a response in the format indicated within the request URL. The following elements may be present in a Snap to Roads response.

  • snappedPoints — An array of snapped points. Each point consists of the following fields:
    • location — Contains a latitude and longitude value.
    • originalIndex — An integer that indicates the corresponding value in the original request. Each value in the request should map to a snapped value in the response. However, if you've set interpolate=true, then it's possible that the response will contain more coordinates than the request. Interpolated values will not have an originalIndex. These values are indexed from 0, so a point with an originalIndex of 4 will be the snapped value of the 5th latitude/longitude passed to the path parameter.
    • placeId — A unique identifier for a place. All place IDs returned by the Google Maps Roads API correspond to road segments. Place IDs can be used with other Google APIs, including the Google Places API and the Google Maps JavaScript API. For example, if you need to get road names for the snapped points returned by the Google Maps Roads API, you can pass the placeId to the Google Places API or the Google Maps Geocoding API. Within the Google Maps Roads API, you can pass the placeId in a speed limits request to determine the speed limit along that road segment.

Example Request

The following request will snap the specified points to the road geometry. This particular set of data follows a circular road; setting interpolate=true ensure that the returned geometry will match the curvature of the road. With interpolate=false, the snapped path will still follow the road, but the resulting polyline will not be as smooth.

Request

https://roads.googleapis.com/v1/snapToRoads?path=-35.27801,149.12958|-35.28032,149.12907|-35.28099,149.12929|-35.28144,149.12984|-35.28194,149.13003|-35.28282,149.12956|-35.28302,149.12881|-35.28473,149.12836&interpolate=true&key=YOUR_API_KEY

Response

{
  "snappedPoints": [
    {
      "location": {
        "latitude": -35.2784167,
        "longitude": 149.1294692
      },
      "originalIndex": 0,
      "placeId": "ChIJoR7CemhNFmsRQB9QbW7qABM"
    },
    {
      "location": {
        "latitude": -35.280321693840129,
        "longitude": 149.12908274880189
      },
      "originalIndex": 1,
      "placeId": "ChIJiy6YT2hNFmsRkHZAbW7qABM"
    },
    {
      "location": {
        "latitude": -35.2803415,
        "longitude": 149.1290788
      },
      "placeId": "ChIJiy6YT2hNFmsRkHZAbW7qABM"
    },
    {
      "location": {
        "latitude": -35.2803415,
        "longitude": 149.1290788
      },
      "placeId": "ChIJI2FUTGhNFmsRcHpAbW7qABM"
    },
    {
      "location": {
        "latitude": -35.280451499999991,
        "longitude": 149.1290784
      },
      "placeId": "ChIJI2FUTGhNFmsRcHpAbW7qABM"
    },
    {
      "location": {
        "latitude": -35.2805167,
        "longitude": 149.1290879
      },
      "placeId": "ChIJI2FUTGhNFmsRcHpAbW7qABM"
    },
    {
      "location": {
        "latitude": -35.2805901,
        "longitude": 149.1291104
      },
      "placeId": "ChIJI2FUTGhNFmsRcHpAbW7qABM"
    },
    {
      "location": {
        "latitude": -35.2805901,
        "longitude": 149.1291104
      },
      "placeId": "ChIJW9R7smlNFmsRMH1AbW7qABM"
    },
    {
      "location": {
        "latitude": -35.280734599999995,
        "longitude": 149.1291517
      },
      "placeId": "ChIJW9R7smlNFmsRMH1AbW7qABM"
    },
    {
      "location": {
        "latitude": -35.2807852,
        "longitude": 149.1291716
      },
      "placeId": "ChIJW9R7smlNFmsRMH1AbW7qABM"
    },
    {
      "location": {
        "latitude": -35.2808499,
        "longitude": 149.1292099
      },
      "placeId": "ChIJW9R7smlNFmsRMH1AbW7qABM"
    },
    {
      "location": {
        "latitude": -35.280923099999995,
        "longitude": 149.129278
      },
      "placeId": "ChIJW9R7smlNFmsRMH1AbW7qABM"
    },
    {
      "location": {
        "latitude": -35.280960897210818,
        "longitude": 149.1293250692261
      },
      "originalIndex": 2,
      "placeId": "ChIJW9R7smlNFmsRMH1AbW7qABM"
    },
    ... results truncated ...
    {
      "location": {
        "latitude": -35.284728724835304,
        "longitude": 149.12835061713685
      },
      "originalIndex": 7,
      "placeId": "ChIJW5JAZmpNFmsRegG0-Jc80sM"
    }
  ]
}

Demo

  1. Get an API Key.
  2. Make a copy of the code below, and replace the API key with your own key. The demo will not work without an API key.
  3. Load the demo in a browser.
    You should see a map centered on Sydney, Australia.
  4. Click around on the map to create a vehicle track. Note that if your points are too far apart, they may not snap correctly.
  5. Double click to snap your track to the road and color-code the polyline based on speed limit:
    • purple <= 40 km/h
    • blue = 40-50 km/h
    • green = 50-60 km/h
    • yellow = 70-80 km/h
    • orange = 90-100 km/h
    • red = >100 km/h

Note: The snapping algorithm works best for points that are close together. If you observe odd snapping behavior, try creating paths that have points closer together. For example, in a city, points should be within a few city blocks of one another to improve snap-to-road quality.

View this example full screen.

JavaScript
var apiKey = 'YOUR_API_KEY';

var map;
var drawingManager;
var placeIdArray = [];
var polylines = [];
var snappedCoordinates = [];

function initialize() {
  var mapOptions = {
    zoom: 17,
    center: {lat: -33.8667, lng: 151.1955}
  };
  map = new google.maps.Map(document.getElementById('map'), mapOptions);

  // Adds a Places search box. Searching for a place will center the map on that
  // location.
  map.controls[google.maps.ControlPosition.RIGHT_TOP].push(
      document.getElementById('bar'));
  var autocomplete = new google.maps.places.Autocomplete(
      document.getElementById('autoc'));
  autocomplete.bindTo('bounds', map);
  autocomplete.addListener('place_changed', function() {
    var place = autocomplete.getPlace();
    if (place.geometry.viewport) {
      map.fitBounds(place.geometry.viewport);
    } else {
      map.setCenter(place.geometry.location);
      map.setZoom(17);
    }
  });

  // Enables the polyline drawing control. Click on the map to start drawing a
  // polyline. Each click will add a new vertice. Double-click to stop drawing.
  drawingManager = new google.maps.drawing.DrawingManager({
    drawingMode: google.maps.drawing.OverlayType.POLYLINE,
    drawingControl: true,
    drawingControlOptions: {
      position: google.maps.ControlPosition.TOP_CENTER,
      drawingModes: [
        google.maps.drawing.OverlayType.POLYLINE
      ]
    },
    polylineOptions: {
      strokeColor: '#696969',
      strokeWeight: 2
    }
  });
  drawingManager.setMap(map);

  // Snap-to-road when the polyline is completed.
  drawingManager.addListener('polylinecomplete', function(poly) {
    var path = poly.getPath();
    polylines.push(poly);
    placeIdArray = [];
    runSnapToRoad(path);
  });

  // Clear button. Click to remove all polylines.
  $('#clear').click(function(ev) {
    for (var i = 0; i < polylines.length; ++i) {
      polylines[i].setMap(null);
    }
    polylines = [];
    ev.preventDefault();
    return false;
  });
}

// Snap a user-created polyline to roads and draw the snapped path
function runSnapToRoad(path) {
  var pathValues = [];
  for (var i = 0; i < path.getLength(); i++) {
    pathValues.push(path.getAt(i).toUrlValue());
  }

  $.get('https://roads.googleapis.com/v1/snapToRoads', {
    interpolate: true,
    key: apiKey,
    path: pathValues.join('|')
  }, function(data) {
    processSnapToRoadResponse(data);
    drawSnappedPolyline();
    getAndDrawSpeedLimits();
  });
}

// Store snapped polyline returned by the snap-to-road service.
function processSnapToRoadResponse(data) {
  snappedCoordinates = [];
  placeIdArray = [];
  for (var i = 0; i < data.snappedPoints.length; i++) {
    var latlng = new google.maps.LatLng(
        data.snappedPoints[i].location.latitude,
        data.snappedPoints[i].location.longitude);
    snappedCoordinates.push(latlng);
    placeIdArray.push(data.snappedPoints[i].placeId);
  }
}

// Draws the snapped polyline (after processing snap-to-road response).
function drawSnappedPolyline() {
  var snappedPolyline = new google.maps.Polyline({
    path: snappedCoordinates,
    strokeColor: 'black',
    strokeWeight: 3
  });

  snappedPolyline.setMap(map);
  polylines.push(snappedPolyline);
}

// Gets speed limits (for 100 segments at a time) and draws a polyline
// color-coded by speed limit. Must be called after processing snap-to-road
// response.
function getAndDrawSpeedLimits() {
  for (var i = 0; i <= placeIdArray.length / 100; i++) {
    // Ensure that no query exceeds the max 100 placeID limit.
    var start = i * 100;
    var end = Math.min((i + 1) * 100 - 1, placeIdArray.length);

    drawSpeedLimits(start, end);
  }
}

// Gets speed limits for a 100-segment path and draws a polyline color-coded by
// speed limit. Must be called after processing snap-to-road response.
function drawSpeedLimits(start, end) {
    var placeIdQuery = '';
    for (var i = start; i < end; i++) {
      placeIdQuery += '&placeId=' + placeIdArray[i];
    }

    $.get('https://roads.googleapis.com/v1/speedLimits',
        'key=' + apiKey + placeIdQuery,
        function(speedData) {
          processSpeedLimitResponse(speedData, start);
        }
    );
}

// Draw a polyline segment (up to 100 road segments) color-coded by speed limit.
function processSpeedLimitResponse(speedData, start) {
  var end = start + speedData.speedLimits.length;
  for (var i = 0; i < speedData.speedLimits.length - 1; i++) {
    var speedLimit = speedData.speedLimits[i].speedLimit;
    var color = getColorForSpeed(speedLimit);

    // Take two points for a single-segment polyline.
    var coords = snappedCoordinates.slice(start + i, start + i + 2);

    var snappedPolyline = new google.maps.Polyline({
      path: coords,
      strokeColor: color,
      strokeWeight: 6
    });
    snappedPolyline.setMap(map);
    polylines.push(snappedPolyline);
  }
}

function getColorForSpeed(speed_kph) {
  if (speed_kph <= 40) {
    return 'purple';
  }
  if (speed_kph <= 50) {
    return 'blue';
  }
  if (speed_kph <= 60) {
    return 'green';
  }
  if (speed_kph <= 80) {
    return 'yellow';
  }
  if (speed_kph <= 100) {
    return 'orange';
  }
  return 'red';
}

$(window).load(initialize);
JavaScript + HTML
<!DOCTYPE html>
<html>
  <head>
    <meta name="viewport" content="initial-scale=1.0, user-scalable=no">
    <meta charset="utf-8">
    <title>Roads API Demo</title>
    <style>
      html, body, #map {
        height: 100%;
        margin: 0px;
        padding: 0px
      }

      #panel {
        position: absolute;
        top: 5px;
        left: 50%;
        margin-left: -180px;
        z-index: 5;
        background-color: #fff;
        padding: 5px;
        border: 1px solid #999;
      }

      #bar {
        width: 240px;
        background-color: rgba(255, 255, 255, 0.75);
        margin: 8px;
        padding: 4px;
        border-radius: 4px;
      }

      #autoc {
        width: 100%;
        box-sizing: border-box;
      }
    </style>

    <script src="/_static/js/jquery-bundle.js"></script>
    <script
      src="https://maps.googleapis.com/maps/api/js?libraries=drawing,places"></script>
    <script>
var apiKey = 'YOUR_API_KEY';

var map;
var drawingManager;
var placeIdArray = [];
var polylines = [];
var snappedCoordinates = [];

function initialize() {
  var mapOptions = {
    zoom: 17,
    center: {lat: -33.8667, lng: 151.1955}
  };
  map = new google.maps.Map(document.getElementById('map'), mapOptions);

  // Adds a Places search box. Searching for a place will center the map on that
  // location.
  map.controls[google.maps.ControlPosition.RIGHT_TOP].push(
      document.getElementById('bar'));
  var autocomplete = new google.maps.places.Autocomplete(
      document.getElementById('autoc'));
  autocomplete.bindTo('bounds', map);
  autocomplete.addListener('place_changed', function() {
    var place = autocomplete.getPlace();
    if (place.geometry.viewport) {
      map.fitBounds(place.geometry.viewport);
    } else {
      map.setCenter(place.geometry.location);
      map.setZoom(17);
    }
  });

  // Enables the polyline drawing control. Click on the map to start drawing a
  // polyline. Each click will add a new vertice. Double-click to stop drawing.
  drawingManager = new google.maps.drawing.DrawingManager({
    drawingMode: google.maps.drawing.OverlayType.POLYLINE,
    drawingControl: true,
    drawingControlOptions: {
      position: google.maps.ControlPosition.TOP_CENTER,
      drawingModes: [
        google.maps.drawing.OverlayType.POLYLINE
      ]
    },
    polylineOptions: {
      strokeColor: '#696969',
      strokeWeight: 2
    }
  });
  drawingManager.setMap(map);

  // Snap-to-road when the polyline is completed.
  drawingManager.addListener('polylinecomplete', function(poly) {
    var path = poly.getPath();
    polylines.push(poly);
    placeIdArray = [];
    runSnapToRoad(path);
  });

  // Clear button. Click to remove all polylines.
  $('#clear').click(function(ev) {
    for (var i = 0; i < polylines.length; ++i) {
      polylines[i].setMap(null);
    }
    polylines = [];
    ev.preventDefault();
    return false;
  });
}

// Snap a user-created polyline to roads and draw the snapped path
function runSnapToRoad(path) {
  var pathValues = [];
  for (var i = 0; i < path.getLength(); i++) {
    pathValues.push(path.getAt(i).toUrlValue());
  }

  $.get('https://roads.googleapis.com/v1/snapToRoads', {
    interpolate: true,
    key: apiKey,
    path: pathValues.join('|')
  }, function(data) {
    processSnapToRoadResponse(data);
    drawSnappedPolyline();
    getAndDrawSpeedLimits();
  });
}

// Store snapped polyline returned by the snap-to-road service.
function processSnapToRoadResponse(data) {
  snappedCoordinates = [];
  placeIdArray = [];
  for (var i = 0; i < data.snappedPoints.length; i++) {
    var latlng = new google.maps.LatLng(
        data.snappedPoints[i].location.latitude,
        data.snappedPoints[i].location.longitude);
    snappedCoordinates.push(latlng);
    placeIdArray.push(data.snappedPoints[i].placeId);
  }
}

// Draws the snapped polyline (after processing snap-to-road response).
function drawSnappedPolyline() {
  var snappedPolyline = new google.maps.Polyline({
    path: snappedCoordinates,
    strokeColor: 'black',
    strokeWeight: 3
  });

  snappedPolyline.setMap(map);
  polylines.push(snappedPolyline);
}

// Gets speed limits (for 100 segments at a time) and draws a polyline
// color-coded by speed limit. Must be called after processing snap-to-road
// response.
function getAndDrawSpeedLimits() {
  for (var i = 0; i <= placeIdArray.length / 100; i++) {
    // Ensure that no query exceeds the max 100 placeID limit.
    var start = i * 100;
    var end = Math.min((i + 1) * 100 - 1, placeIdArray.length);

    drawSpeedLimits(start, end);
  }
}

// Gets speed limits for a 100-segment path and draws a polyline color-coded by
// speed limit. Must be called after processing snap-to-road response.
function drawSpeedLimits(start, end) {
    var placeIdQuery = '';
    for (var i = start; i < end; i++) {
      placeIdQuery += '&placeId=' + placeIdArray[i];
    }

    $.get('https://roads.googleapis.com/v1/speedLimits',
        'key=' + apiKey + placeIdQuery,
        function(speedData) {
          processSpeedLimitResponse(speedData, start);
        }
    );
}

// Draw a polyline segment (up to 100 road segments) color-coded by speed limit.
function processSpeedLimitResponse(speedData, start) {
  var end = start + speedData.speedLimits.length;
  for (var i = 0; i < speedData.speedLimits.length - 1; i++) {
    var speedLimit = speedData.speedLimits[i].speedLimit;
    var color = getColorForSpeed(speedLimit);

    // Take two points for a single-segment polyline.
    var coords = snappedCoordinates.slice(start + i, start + i + 2);

    var snappedPolyline = new google.maps.Polyline({
      path: coords,
      strokeColor: color,
      strokeWeight: 6
    });
    snappedPolyline.setMap(map);
    polylines.push(snappedPolyline);
  }
}

function getColorForSpeed(speed_kph) {
  if (speed_kph <= 40) {
    return 'purple';
  }
  if (speed_kph <= 50) {
    return 'blue';
  }
  if (speed_kph <= 60) {
    return 'green';
  }
  if (speed_kph <= 80) {
    return 'yellow';
  }
  if (speed_kph <= 100) {
    return 'orange';
  }
  return 'red';
}

$(window).load(initialize);

    </script>
  </head>

  <body>
    <div id="map"></div>
    <div id="bar">
      <p class="auto"><input type="text" id="autoc"/></p>
      <p><a id="clear" href="#">Click here</a> to clear map.</p>
    </div>
  </body>
</html>

Send feedback about...

Google Maps Roads API
Google Maps Roads API
Need help? Visit our support page.