Autocomplete and Suggestions with the Search API
Magdalena Korczynska·Dec 06, 2019

Autocomplete and Suggestions with the Search API

Magdalena Korczynska
Dec 06, 2019 · 8 min read

TomTom's Search API with autocomplete enables you to provide more meaningful results to your application's users. Take a look on how you can improve your search results within your app.

We previously discussed the TomTom Search API a bit with our previous article, Understanding Fuzzy Search.

Today we are going to dive a little bit deeper and discuss our Search Autocomplete API, a feature that allows you to provide more meaningful results to your users without the need to track them.* The autocomplete endpoint complements the ‘type ahead’ parameter in the Fuzzy search by providing related categories that the user might be looking for.

Table of Contents:Search API Technical AspectsOptional ParametersNext StepsScreenshot 2021-02-03 at 09.19.33

Here's an example of autocomplete in action. Keep reading to learn more!

Let’s review the explanation of the 'type ahead' parameter (mentioned above) from the documentation:

When the search enters in Predictive Mode, it also provides more matching results.

[First, the Technical aspects of the API]

The documentation for this endpoint can be found in the developer portal in the Search API documentation.

This REST API Call uses HTTPS-GET and has minimum parameters:

| Required Parameters | | | --- | --- | | Parameter | Description | | baseURL string | The base URL for calling the API. Value: api.tomtom.com | | versionNumber string | The service version. Value: The current value is 2. | | ext string | An API Key valid for the requested service. Value: Your valid TomTom API Key. | | language ​string | Language in which autocomplete results should be returned. Value: One of the TomTom supported IETF language tags. |

Let’s say we start looking for wine stores. So, I start typing “wine”, and at the 4th character we decide to provide some suggestions. Since I am in Madrid, a sample call will look like this:

https://api.tomtom.com/search/2/autocomplete/wine.json?key=<Your_API_Key>&language=en-GB&lat=40.41687&lon=3.70356 

Adding my private API key with the call, I get these results:

{
  "context": {
    "inputQuery": "wine",
    "geoBias": {
      "position": {
        "lat": 40.41687,
        "lon": 3.70356
      }
    }
  },
  "results": [
    {
      "segments": [
        {
          "type": "category",
          "value": "Wine & Spirits",
          "matches": {
            "inputQuery": [
              {
                "offset": 0,
                "length": 4
              }
            ]
          },
          "id": "9361025",
          "matchedAlternativeName": "Wine"
        }
      ]
    },
{
      "segments": [
        {
          "type": "category",
          "value": "Wine Bar",
          "matches": {
            "inputQuery": [
              {
                "offset": 0,
                "length": 4
              }
            ]
          },
          "id": "9379007",
          "matchedAlternativeName": "Wine"
        }
      ]
    },
    {
      "segments": [
        {
          "type": "category",
          "value": "Winery",
          "matches": {
            "inputQuery": [
              {
                "offset": 0,
                "length": 4
              }
            ]
          },
          "id": "7349",
          "matchedAlternativeName": "Wine"
        }
      ]
    }
  ]
}

Let’s examine the results:

  1. I see 3 sections.

  2. All of them are of the type “category”.

According to the documentation, we can get 3 different types of results: Brands, Categories and Plaintext.

For example, if we search for the term “jim” – assuming this refers to several brands, we can observe:

https://api.tomtom.com/search/2/autocomplete/jim.json?key=<API KEY>&language=en-GB&limit=10 
{
  "context": {
    "inputQuery": "jim"
  },
  "results": [
    {
      "segments": [
        {
          "type": "brand",
          "value": "Jim Thompson",
          "matches": {
            "inputQuery": [
              {
                "offset": 0,
                "length": 3
              }
            ]
          }
        }
      ]
    },
    {
      "segments": [
        {
          "type": "brand",
          "value": "Jimmy's Pizza",
          "matches": {
            "inputQuery": [
              {
                "offset": 0,
                "length": 3
              }
            ]
          }
        }
      ]
    },
    {
      "segments": [
        {
          "type": "brand",
          "value": "Jimmy John's",
          "matches": {
            "inputQuery": [
              {
                "offset": 0,
                "length": 3
              }
            ]
          }
        }
      ]
    },
{
      "segments": [
        {
          "type": "brand",
          "value": "Jimmy Chung's",
          "matches": {
            "inputQuery": [
              {
                "offset": 0,
                "length": 3
              }
            ]
          }
        }
      ]
    },
    {
      "segments": [
        {
          "type": "brand",
          "value": "Jimmy Choo",
          "matches": {
            "inputQuery": [
              {
                "offset": 0,
                "length": 3
              }
            ]
          }
        }
      ]
    }
  ]
}

There are several brands represented here based on our input; if we keep typing and we make a following query with “jimm”, we see:

{
  "context": {
    "inputQuery": "jimm"
  },
  "results": [
    {
      "segments": [
        {
          "type": "brand",
          "value": "Jimmy's Pizza",
          "matches": {
            "inputQuery": [
              {
                "offset": 0,
                "length": 4
              }
            ]
          }
        }
      ]
    },
    {
      "segments": [
        {
          "type": "brand",
          "value": "Jimmy John's",
          "matches": {
            "inputQuery": [
              {
                "offset": 0,
                "length": 4
              }
            ]
          }
        }
      ]
    },
    {
      "segments": [
        {
          "type": "brand",
          "value": "Jimmy Chung's",
          "matches": {
            "inputQuery": [
              {
                "offset": 0,
                "length": 4
              }
            ]
          }
        }
      ]
    },
{
      "segments": [
        {
          "type": "brand",
          "value": "Jimmy Choo",
          "matches": {
            "inputQuery": [
              {
                "offset": 0,
                "length": 4
              }
            ]
          }
        }
      ]
    },
    {
      "segments": [
        {
          "type": "brand",
          "value": "Jimmy's Killer Prawns",
          "matches": {
            "inputQuery": [
              {
                "offset": 0,
                "length": 4
              }
            ]
          }
        }
      ]
    }
  ]
}

Now the brand “Jim Thompson” is gone from the list after tacking on more of the letter “m”, and we have a new “Jimmy’s Killer Prawns” brand name.

Returning to our original query (wine), as specified in the documentation, I get only 5 results by default. I think I am going to need more than that for my users, so maybe I'll try 10 next time.

Getting back to my first attempt, I already added some optional parameters (Lat and Long of most central place in Madrid: La Puerta del Sol). Next, we will go through some optional parameters.

Optional parameters

Let’s take a look at the optional parameters:

| Optional Parameters | | | --- | --- | | Parameter | Description | | [limit] | Maximum number of autocomplete results that will be returned. Default value: 5 Max value: 10 | | [lat] | Latitude, e.g., lat=37.337. It must be used in conjunction with the lon parameter. Results should be biased to the position defined by the lat, lon parameters. | | [lon] | Longitude, e.g., lon=-121.89. It must be used in conjunction with the lat parameter. Results should be biased to the position defined by the lat, lon parameters. | | [radius] | A radius in meters. It must be used in conjunction with lat, lon parameters. | | [countrySet] | A comma-separated string of country codes (e.g., FR,ES). This will limit the autocomplete results to the specified countries. | | [resultSet] | Restricts the result space based on their segment types |

So, let’s see what we get if we exchange the location area for the country (ES=Spain) and add a limit of 10 results.

My new URL looks like:

https://api.tomtom.com/search/2/autocomplete/wine.json?key=<API_KEY>&language=en-GB&countrySet=ES&limit=10 

And this time I get the following result:

{
  "context": {
    "inputQuery": "wine"
  },
  "results": [
    {
      "segments": [
        {
          "type": "category",
          "value": "Wine Bar",
          "matches": {
            "inputQuery": [
              {
                "offset": 0,
                "length": 4
              }
            ]
          },
          "id": "9379007",
          "matchedAlternativeName": "Wine"
        }
      ]
    },
    {
      "segments": [
        {
          "type": "category",
          "value": "Wine & Spirits",
          "matches": {
            "inputQuery": [
              {
                "offset": 0,
                "length": 4
              }
            ]
          },
          "id": "9361025",
          "matchedAlternativeName": "Wine"
        }
      ]
    },
{
      "segments": [
        {
          "type": "category",
          "value": "Winery",
          "matches": {
            "inputQuery": [
              {
                "offset": 0,
                "length": 4
              }
            ]
          },
          "id": "7349",
          "matchedAlternativeName": "Wine"
        }
      ]
    }
  ]
}

And… it is exactly the same as before! At least I see consistency (these categories are in the database for Spain.) With these 3 categories, I can present them to the user and if any of those are selected, we can take the “id” provided in the Segment and perform a normal POI category search. In this case I see that the category “Wine & Spirits" is the closest to what I want.

I’ll make a quick category search and see what I get.

We’ll use the POI search documentation here.

This time we are going to use the [lat, lon] for “Puerta del Sol” as a Bias guideline.

https:// https://api.tomtom.com/search/2/categorySearch/.json?key=<API_KEY>&lat=40.41687&lon=-3.70356&categorySet=9361025 

Before we check the results, let’s examine this URL closely:

  1. I didn’t pass any text in the query: I want all possible POIs in this category and close to this location.

  2. The Category is added in the optional parameter “categorySet”

Now this REST API Call gave some interesting results, and since it returns a minimum of 10, is good enough to present to the user.

Let’s see the first item in the results:

{
  "type": "POI",
  "id": "ES/POI/p0/1486801",
  "score": 1.21439,
  "dist": 295.90900560698543,
  "info": "search:ta:724009006287107-ES",
  "poi": {
    "name": "David Borda Juan Oscar",
    "categorySet": [
      {
        "id": 9361025
      }
    ],
    "categories": [
      "food drinks: wine spirits",
      "shop"
    ],
    "classifications": [
      {
        "code": "SHOP",
        "names": [
          {
            "nameLocale": "en-US",
            "name": "food drinks: wine spirits"
          },
          {
            "nameLocale": "en-US",
            "name": "shop"
          }
        ]
      }
    ]
  },
  "address": {
    "streetNumber": "9",
    "streetName": "Calle del Príncipe",
    "municipalitySubdivision": "Madrid",
    "municipality": "Madrid",
    "countrySecondarySubdivision": "Madrid",
    "countrySubdivision": "Comunidad de Madrid",
    "postalCode": "28012",
    "countryCode": "ES",
    "country": "España",
    "countryCodeISO3": "ESP",
    "freeformAddress": "Calle del Príncipe 9, 28012 Madrid",
    "localName": "Madrid"
  },
  "position": {
    "lat": 40.41593,
    "lon": -3.70029
  },
  "viewport": {
    "topLeftPoint": {
      "lat": 40.41683,
      "lon": -3.70147
    },
    "btmRightPoint": {
      "lat": 40.41503,
      "lon": -3.69911
    }
  },
  "entryPoints": [
    {
      "type": "main",
      "position": {
        "lat": 40.41593,
        "lon": -3.70035
      }
    }
  ]
}

As you can see there is a wealth of information related to this POI (point of interest), but point your attention to the the field named “categories”. This is an array of assigned categories that this Place relates to. If I can present this to the user, they can refine the autocomplete search to be improved in the future.

[Next Steps]

To learn more about using the Extended Search API to fetch details, photos, reviews and ratings from Points of Interest and using the SearchBox and the Autocomplete feature with the Search APIs, check out our video tutorial here:

The Autocomplete feature in the TomTom Search is an extremely valuable addition to the rest of our APIs. We saw in this small example how easy it can be to provide continuous search results to your application, so that the user can narrow their focus and get more specific results.

Check out the many possibilities in our Developer Portal and don’t forget to add questions and comments in our Developer Forum.

To read more about the power of POI data and how to add search capabilities to your web or mobile app, check out these suggested articles:

Happy mapping… and searching!


*Note: Privacy protection is paramount for TomTom, and all APIs available in the developer portal (developer.tomtom.com) keep this policy so your users can be reassured that all data collected is only to make our APIs better (and with your consent), and only out of necessity to perform the actions you require in your application.

Get the developer newsletter.
No marketing fluff. Tech content only.

* Required field. By submitting your contact details to TomTom, you agree that we can contact you about marketing offers, newsletters, or to invite you to webinars and events. We could further personalize the content that you receive via cookies. You can unsubscribe at any time by the link included in our emails. Review our privacy policy.