Places (Search) API Developer's Guide

Filtering Searches by Location

The Places (Search) API allows you to filter results when you can determine relevance by a specific location or by a location area. Provide the relevant location information in the form of location contexts. The Places (Search) API supports the following kind of location contexts:
  • explicit – included in the request query parameters

    Examples of explicit location contexts include providing a specific position, circle or bounding box based on user input by specifying a value for the query parameters at or in. For more information on the available query parameters, see the API Reference.

  • implicit – included in the request header

    Examples of implicit location contexts include providing the current location from a device GPS unit or the map view displayed in the request header in the headers Geolocation and X‑Map‑Viewport. For more information on the available location context headers, see HTTP Request Headers.

You can also filter search results by category for relevance. For more information, see Filtering by Category.

All Places (Search) API entrypoints require at least one location context. We strongly recommend that you should always provide as much implicit location context information as possible and explicit location context information where relevant. For more information on best practices, see Best Practice.

Explicit Location Context

When the user explicitly indicates a location to your application, for example by clicking on a map position to trigger a discovery query at that location, your application should provide an explicit location context to the Places (Search) API using one of the following query string parameters:

Name Availiability Format Description
at Always Position Specifies an explicit position as a point
in Selected request types Circle or Bounding Box Specifies an explicit area

Implicit Location Context

Your application will often have location information available to it that is not explicitly provided by the user, such as the user's geolocation or a map area currently being displayed to the user. Sending at least one type of implicit location context information is required in the absence of an explicit location context, and you are strongly encouraged to send implicit location context information to ensure you get optimal results even when providing an explicit location.

Applications should always send the following implicit location context headers when the values are known:

Name Format Description
Geolocation Position Specifies the physical position of a user
X‑Map‑Viewport Bounding Box Specifies the map area currently displayed to the user

Best Practice

To get the best results, applications should always send implicit location context information when available, and only send an explicit location context parameter when the user has explicitly indicated (selected) a specific location. Therefore, applications should always send the X-Map-Viewport header when displaying a map to user, and the Geolocation header when the user's position is known. This is sufficient in many use cases, and an explicit location context (via a query string parameter) is often not required.

For example, if the application always displays a map to the user and provides a textbox for free-text search that makes use of the Places (Search) API search entrypoint. When the user performs a search, the application should supply the X-Map-Viewport header. If the user's position is also known, the application should include the Geolocation header as well. In this scenario, the user does not indicate an explicit location related to the search (other than possibly positioning the map viewport), so there is no need to specify an explicit location context.

If, however, the application additionally allows the user to click on the map and find out what is at that location using the here entrypoint and the user does select a location in this way, the application should provide that location as an explicit location context in the at query string parameter. The application should still send the implicit context information via the X-Map-Viewport header (and the Geolocation if the user's location is available), but the explicit location takes precedence in determining the primary location for the request.

Distance Calculation

Places in results have a distance field indicating the distance from the user's location or from an explicit reference point to the place. An explicit location context in the request provides the location from which the distance is calculated. In the absence of an explicit location context, the position from the Geolocation header is used. If the only available location context is from the X-Map-Viewport, no distance calculation occurs and the distance is not set.

Position Format

The Geolocation header (implicit context) and at parameter (explicit context) specify a position as a 'geo' URI. The position is given as comma-separated values for latitude and longitude (in the WGS 84 coordinate system), and optionally altitude (in meters above sea level), and a semicolon-separated list of position parameters.

Applications should specify the source for the position by passing one of the following values for the cgen parameter:

  • map for points on a map, for example, geo:53.12,10.15;cgen=map.
  • gps for values from a GPS device, for example,geo:53.12,10.15;cgen=gps.
  • sgps for shifted GPS coordinates from a device fulfilling the legal requirements in China, for example, geo:53.12,10.15;cgen=sgps.

Uncertainty in the geo-coordinates should be given in the u parameter as the uncertainty in meters, for example, geo:53.12,10.15;cgen=gps;u=100. This might be the uncertainty of a GPS coordinate fix, or uncertainty resulting from the resolution of a map. An absolutely accurate position should be specified with u=0. If the u parameter is not provided, the uncertainty is unspecified rather than 0. For example, 39.91,116.40;cgen=gps;u=16 specifies a position derived from a GPS device with an uncertainty of 16 meters.

Circle Format

A circular area can be specified as a location context by providing a position (as described in Position) and an additional radius. The radius is given by setting the r parameter to the radius in meters. For example,53.12,10.15;r=10500 specifies an area with a 10.5km radius.

Bounding Box Format

A bounding box can be used to specify a geographic area as a location context. The rectangle spanning the area is specified in the WGS 84 coordinate system as four comma-separated values in the following order: west longitude, south latitude, east longitude, north latitude. For example, 13.125,52.362,13.661,52.693 specifies a bounding box for Berlin.

For maps applications using HERE map tiles, the zoom level should be sent as a fifth parameter. For example, if the zoom level is 4.3, the above example would become 13.125,52.362,13.661,52.693,4.3.

HERE polyline encoding

HERE polyline encoding is used for the compressedRoute parameter. The polyline encoding is a compressed representation of a list of coordinate pairs. It achieves that by
  • reducing precision to 5 decimal places
  • encoding only the offset from the previous point
  • using variable length for each coordinate delta
  • using 64 URL-safe characters to display the result
Assuming the input is given as a sequence of coordinates, e.g. { latitude: 52.0, longitude: 13.1 }, iterate over this sequence and append the encoded latitude delta and then the longitude delta to the end result. For the first coordinate you have to encode the absolute value, for every other coordinate subtract the previous values from the current one to get the delta. Also, it may be desired to specify whether a route segment is located in a city or on a highway, this can be done by marking the starting point of the segment with .C or .H respectively. This will modify the search distance and possibly algorithm for every segment thereafter. The first segment affected is the one starting with the point preceding .C or .H. This is reflected by the following Javascript snippet:

function hereEncodePolyline(positions) {
  var lastLat = 0, lastLon = 0;
  var result = [];
  var width = "D"
  var newWidth;
  for (var i = 0; i < positions.length; ++i) {
    var position = positions[i];
    if (i > 0) {
      if (isCityRoad(lastLat, lastLon, position.latitude, position.longitude)) {
        newWidth = "C";
      } else if (isHighway(lastLat, lastLon, position.latitude, position.longitude)) {
        newW idth = "H";
      } else {
        newWidth = "D"
      }
      if (newWidth != width) {
        result.push("." + newWidth);
        width = newWidth;
      }
    }
    // it is an actual route point
    result.push(hereEncodeFloat(position.latitude - lastLat));
    result.push(hereEncodeFloat(position.longitude - lastLon));
    lastLat = position.latitude;
    lastLon = position.longitude;

  }
  return result.join('');
}
          
A floating point number is encoded in the following way.
  1. Multiply with 1e5 and round to the nearest integer
  2. Shift left to make room on the lowest bit
  3. Invert negative numbers
  4. Divide the number into 5bit chunks and encode them starting from least significant part to most significant
  5. As it is a variable-length encoding, add 0x20 to signal that the another chuck follows

function hereEncodeFloat(value) {
  var ENCODING_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';
  var result = [];

  // convert to fixed point
  var fixedPoint = Math.round(value * 100000);

  // make room on the lowest bit
  fixedPoint = fixedPoint << 1;

  // flip bits of negative numbers and ensure that the last bit is set
  // (should actually always be the case, but for readability it is ok to do it explicitly)
  if (fixedPoint > 0) {
    fixedPoint = ~(fixedPoint) | 0x01
  }

  // var-length encode the number in chunks of 5 bits starting with the least significant
  // to the most significant
  while (fixedPoint > 0x1F) {
    result.push(ENCODING_CHARS[(fixedPoint & 0x1F) | 0x20]);
    fixedPoint >>= 5;
  }
  result.push(ENCODING_CHARS[fixedPoint]);
  return result.join('');
}
          
Given below are some examples of input lists of latitude/longitude pairs and the corresponding encoded representations

input1 = "[50.1022829,8.6982122|50.1020076,8.6956695|50.1006313,8.6914960|50.0987800,8.6875156]"
encoded1 = "oz5xJ67i1B3B7PzIhaxL7Y"

input2 = "[52.5199356,13.3866272|52.5100899,13.2816896|52.4351807,13.1935196|" +
     "52.4107285,13.1964502|52.38871,13.1557798|52.3727798,13.1491003|" +
     "52.3737488,13.1154604|52.3875198,13.0872202|52.4029388,13.0706196|52.4105797,13.0755529]"
encoded2 = "05xgKuy2xCx9B7vUl0OhnR54EqSzpEl-HxjD3pBiGnyGi2CvwFsgD3nD4vB6e"

inputWithWidths = "[52.5160,13.3771|CW|52.5111,13.3712|52.5355,13.3634|52.5400,13.3704|" +
           "52.56 26,13.3307|52.5665,13.3076|52.6007,13.2806|HW|52.6135,13.2484|52.6303,13.2406|" +
           "52.6651,13.2410|52.7074,13.1926|52.7045,13.0661|52.7191,12.9621|52.76 36,12.8263|" +
           "52.7861,12.8000|52.8335,12.7919|52.9002,12.7451|52.9708,12.6311|53.0526,12.5392|" +
           "53.0867,12.5169|53.1146,12.4687|53.1334,12.4644|53.1415,12.4225|53.1666,12.3722|" +
           "53.1785,12.3050|53.2570,12.1618|53.2893,12.0618|53.3000,11.9373|53.3316,11.8724|" +
           "53.3463,11.8190|53.3669,11.7328|53.3725,11.6427|53.4154,11.5505|53.4309,11.4906|" +
           "53.4342,11.4000|53.4655,11.3370|53.4873,11.2631|53.4860,11.2011|53.5110,10.9647|" +
           "53.5128,10.8414|53.5495,10.6892|53.5692,10.5155|53.5596,10.4259|53.5682,10.2999|" +
           "53.5571,10.2020|CW|53.5672,10.1279|53.5534,9.9924];w=1000"
encodedWithWidth = "ghxgK820xC.Cze7kBw4E3wBkc4rBotEj4HsYrwE41G3oF.H" +
           "gwCnpGgpD3wBw5GwCsoIvuJjSz2Yo7C_pUk2I3wa0sErkFooJzyB8gNvkJo5NvoWo_Pr-Rk1GrrEsuFntJw1D7" +
           "a0yB7lI88Er6JsqC_jN0qP_-b8pG_wT8iCjqYwlGz1M87C3tK4gE36QgjBjzRksIngS8gDr2L0Un2R0jG3pM" +
           "ooE7tOjIvjMo8EvluBoLziYslHn3dk7Dz9hB_7B_vR41BvzYrlC7jT.Ck_BjvOn2C7ua;w=1000"
        

We also recommend to use a lossy compression on client side to e.g. combine segments into straight line if the deviation to the route geometrie is small. There are several open source implementations available that can be used as a template for this.