Skip to content

Migrating to the v2 Geocoding APIs

Version 2 of our geocoding APIs are an important step in the evolution of spatial search. We're launching with brand-new /v2/autocomplete and /v2/place_detail endpoints, and more are on the way.

In this guide, we'll cover what's new and what you need to do to migrate your apps.

How to use this guide

In a rush? Read the "What you need to know" sections first. Then, if you're using one of our official SDKs, check out the CHANGELOG on GitHub for any important code changes.

The actual migration should take less than 5 minutes.

The rest of this page is an in-depth look into the details of the change, for anyone who prefers reading prose rather than API docs / exploring with IDE autocompletion. We also discuss the rationale for each change, and how you can build better apps! But we won't be offended if you skim over some of it.

Query parameters work as-is!

What you need to know

  • The query string format is NOT changing.
  • We may add parameters in the future.

First off, let's take a look at what's not changing. We are not breaking anything with how you query; the parameters in the query string will stay as they are. Easy!

Major changes to the autocomplete endpoint

What you need to know

  • We're making autocomplete even more affordable!
  • The v2 autocomplete response format is highly streamlined, with no geometry and a slimmed down properties object.
  • The distance field (still) lets you show how far away something is.
  • The new coarse_location field is tailor-made for the second line of an autocomplete result cell.
  • Call the Place Details endpoint with the result's GID for full details.

The v1 autocomplete API returns the full details for every result. As such, we charge the same price as for a "full search," even though the majority of the results were discarded immediately!

For v2, we are dramatically reducing the credit cost of our autocomplete APIs, better aligning our pricing with the value you derive from each keystroke. And by streamlining the response format and adding some more focused properties, we're able to deliver results even faster. Win-win!

When you're ready to get the full details for a result (e.g. when the user selects a result from the list), hit the Place Details endpoint with the result GID.

More improvements in the pipeline!

We're also working on a taxonomy for POIs which will let you build even better search experiences that distinguish between restaurants, parks, shops, etc. This will be included in v2 autocomplete responses as soon as it becomes available.

Improved context

When we look at the ways our APIs are used, one thing that stands out is the need to present results with good local context. Our biggest changes in the v2 API are designed to make it easier for app developers to communicate the geographic context to end users.

Introducing coarse_location

What you need to know

  • All v2 responses include a coarse_location string with localized, coarse-grained context information.
  • This field is tailor-made for the second line of a search result cell!

Most user-facing experiences don't need the full administrative hierarchy for a place: you just want a short string! We're making this easier with a new coarse_location property, which is tailor-made for that second line in an autocomplete result cell. No more guessing about the best way to combine components, and inevitably forgetting about Arabic commas, lack of commas in Korean, and so on.

Here are some examples:

  • Tallinn, Harju, Estonia
  • London, England
  • Toronto, ON, Canada
  • 한국 서울
  • 日本東京

A new context model

What you need to know

  • We've removed all of the top-level keys like country, locality_gid, and region_a from the `properties object.
  • We've added a new model, context, under properties which has the Who's on First hierarchy asd ISO identifiers.

For v2, we've dramatically improved how we communicate local context with a new model that looks like this:

{
  "whosonfirst": {
    "country": {
      "gid": "whosonfirst:country:85633135",
      "name": "Estonia",
      "abbreviation": "EST"
    },
    "region": {
      "gid": "whosonfirst:region:85683055",
      "name": "Harju",
      "abbreviation": "HA"
    },
    "county": {
      "gid": "whosonfirst:county:1713305645",
      "name": "Tallinn"
    },
    "borough": {
      "gid": "whosonfirst:borough:1713348883",
      "name": "Pőhja-Tallinna"
    },
    "neighbourhood": {
      "gid": "whosonfirst:neighbourhood:85907845",
      "name": "Vanalinn"
    },
    "locality": {
      "gid": "whosonfirst:locality:101748153",
      "name": "Tallinn"
    },
    "localadmin": {
      "gid": "whosonfirst:localadmin:1713306175",
      "name": "Pőhja-Tallinna"
    }
  },
  "iso_3166_a2": "EE",
  "iso_3166_a3": "EST"
}

The new format includes structure that groups similar items and makes it clearer what data sources were used for each result. While v1 API expresses the local context only in terms of the Who's on First taxonomy, we're working to incorporate additional sources soon. The v2 API paves the way for this, and also resolves some long-standing ambiguity with country_code and country_a. We've added some top-level context properties for unambiguous ISO identifiers.

Better localized address formatting

What you need to know

  • All v2 APIs except autocomplete will get two new formatted address properties.
  • Use formatted_address_line when you want to display an address on a single line.
  • Use formatted_address_lines in contexts where you want a fuller format that spans multiple lines.
  • In all cases, we handle the formatting in a locale-aware manner so you don't have to!

Localizing addresses is hard. Besides localizing place names, we need to know which order the components belong in, where to put separators, how to join multiple lines, and more.

The v2 geocoding API makes huge strides toward localizing addresses correctly, worldwide. We've added two properties: formatted_address_line and formatted_address_lines. The primary difference between the two is that formatted_address_line is optimized for display on a single line, and will join lines together with an appropriate separator (typically commas; this varies by country).

{
  "formatted_address_lines": [
    "서울",
    "중구 세종대로 172",
    "광화문"
  ],
  "formatted_address_line": "서울 중구 세종대로 172 광화문"
}

What about street names?

You may notice that, while we pretty reliably localize country, region, and other place names, we don't currently localize street names. This is a slightly more complex topic from a data gathering perspective, but rest assured we are working on it!

Removing the label property

What you need to know

  • We removed the label property.
  • Depending on your needs, you can replace it with name, formatted_address_line, or a combination of name and coarse_location.
  • NB: formatted_address_line and formatted_address_lines are not present on layers like country and locality, which have no logical address!

Given all the other improvements in labeling, we felt it was time to remove the label property. The label property in v1 is effectively a synthesis of name and coarse_location (which didn't exist in v1). This works for a few basic use cases, but we can do better.

For example, in a search UI, you probably want to display name and coarse_location on two separate lines with distinct typography. And in contexts where you have more space, and you're displaying something with an address, you probably want either formatted_address_line or formatted_address_lines.

In short, we're replacing the single label with a suite of labels that do the job better, either alone or together.

Reduced English language bias

What you need to know

  • We no longer auto-localize everything to English for requests without a language preference.
  • You should indicate a language preference, either via headers or a query string lang parameter!

The v1 APIs assume English as a default for everything unless you specify otherwise. For v2, we're taking steps to reduce this bias towards the English language.

The geocoding APIs understand two forms of language preference. First, most web browsers (and some other user agents) send an Accept-Language header. Second, you can explicitly set a language preference with a lang query string argument. The query string is more natural for most non-web use cases, and, if present, it will override the Accept-Language header preferences.

Previously, the API would assume that if you sent neither the lang parameter or the Accept-Language header, you wanted everything localized in English. This behavior has been removed for v2, as we believe the ground truth should always be the default unless specified otherwise.

Some datasets still have an Anglophone bias, which can result in a mix of English and local language components in the search result. We are working with the upstream data sources to improve this, so that the "default" configuration will match the ground truth.

We highly recommend setting an explicit language preference whenever possible, as this will result in a better user experience. In general, web frontend use cases will not need to worry about this, as the browser sends these headers automatically. Backend and mobile developers though should take care to set an appropriate value explicitly.

Improved source attribution

What you need to know

  • Source attribution is now an array of objects, names sources, which replaces the source and source_id properties.

We've made a number of improvements around how data sources are attributed. Attribution is now an array of objects rather than a simple pair of strings. This enables two important things:

  1. We can include backlinks to improve open datasets like OpenStreetMap and Foursquare OS Places.
  2. It allows us combine data from multiple sources (for example, OpenStreetMap and Foursquare) in a single result. This was not possible in v1!

Here's what it looks like:

[
  {
    "source": "foursquare",
    "source_id": "60cc413d7f4109105c623a7d",
    "fixit_url": "https://foursquare.com/placemakers/review-place/60cc413d7f4109105c623a7d"
  },
  {
    "source": "openstreetmap",
    "source_id": "node/11744981946",
    "fixit_url": "https://www.openstreetmap.org/edit?node=11744981946"
  }
]

Restructuring addendum

The addendum field is the kitchen sink of miscellaneous data we have on a place, and it's highly specific to the source where the place comes from. We've taken the v2 reshuffle as an opportunity to document the fields we can return in detail, as well as to rename some of the fields to be a bit less obtuse.

And since things are fully documented, you'll get all the goodies like IDE suggestions and (for certain programming languages) compile time checks on the property names, and strong types in supported programming languages.

We're also taking this opportunity to remove some fields that were only available for a small subset of records. For example, nyt:id was only present on about 1,000 places, and isn't exactly a widely recognized identifier. We hope this provides more signal and less noise overall.

Here's a diff for the addendum for Seoul, South Korea:

{
-  "concordances": {
+  "whosonfirst_concordances": {
-    "dbp:id": "Seoul",
-    "fb:id": "en.seoul",
-    "fct:id": "14700d1c-8f76-11e1-848f-cfd5bf3ef515",
+    "factual_id": "14700d1c-8f76-11e1-848f-cfd5bf3ef515",
-    "gn:id": 1835848,
+    "geonames_id": 1835848,
-    "gp:id": 1132599,
+    "geoplanet_id": 1132599,
-    "loc:id": "n79066627",
-    "nyt:id": "57074030312950130901",
-    "qs_pg:id": 1073966,
+    "quattroshapes_pg_id": 1073966,
-    "wd:id": "Q8684"
+    "wikidata_id": "Q8684"
  }
}

More improvements in the pipeline!

Stay tuned for some useful additions to the addendum structure. We're evaluating adding some new tags from OSM and other data sources. If you have any suggestions or special requests, let us know!

Other small improvements

What you need to know

  • Address components are now collected under an address_components field.
  • The venue layer has been renamed to poi; queries for venue will still work though.
  • The accuracy field has been renamed to precision.

On to some smaller updates that don't require as much proverbial ink...

Better structure for address components

We've broken out the various address fields into their own address_components object. There is no change in what fields are available or how they are formatted; only the structure has changed.

Clarifying confusing names

We're renaming the venue layer to poi for v2 to better reflect the breadth of things you can search for. Central Park and the Statue of Liberty, for example, would not commonly be referred to as "venues" in common English usage.

Similarly, we've renamed the accuracy field to precision for v2, This field never communicated about the accuracy of the data, but rather its precision from a spatial perspective. The valid values remain centroid and point, and indicate whether the point geometry was reduced from a higher dimensionality.

Wrapping up

We've put a lot of thought into the details of the v2 API. But we certainly haven't thought of everything! Reach out to us if you have any suggestions or spot a bug. Or just drop us a line to let us know what you're building; we love that too!