The Quickest Way to Build an Address Autocomplete API
Published: 2023-02-27 14:21:30


An *address autocomplete* is an address form feature that’s kind of just what it says on the tin: it automatically suggests addresses to users as they type into an online form. It’s an elegant way to ensure accuracy as a user inputs all the components of a complete address, like country, city, postal code, and street.

But building a form to capture an address with auto-complete and validation can be quite a challenge. What should the form ask for first: the postal code or the region? Which data input should use auto-complete? Which reliable data source should be used? How to optimize UI responsiveness?

In this article you will learn all that’s required to build a backend API for address completion.
<br>
> The technicalities of building an API backend and frontend are beyond the scope of this article. They’re too dependent on your chosen programming language. As a personal recommendation, I favor React with [Material UI](https://mui.com/) for the frontend and Node.js with [Express](https://expressjs.com/) for the backend. But you will need some solid technical knowledge about building an API backend and frontend before you read on.

&nbsp;


## What Does an Address Autocomplete Feature Actually Look Like?

To expound on my earlier definition, an address autocomplete feature generates suggestions based on previously entered information as the user enters data into the form. The user can easily choose from a list of options, ensuring the accuracy of the input address. This is especially useful when someone needs to enter a long or complex address or when the user isn’t familiar with a specific address format.
<br>

![Address autocomplete API](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jb9yy8b0mnf9c9b1lv3o.png)
<br>
## Why Is Address Autocomplete Important?

An efficient address autocompletion form on your website prevents you from ingesting inaccurate data, like typos or nonexistent addresses. Unless you allow free entry, you could also lose sign-up or orders. But allowing that will even worsen the data quality.

Ensuring data quality right from the start is critical for proper data processing. Without it, you risk having incorrect shipping addresses, which can cause delays, extra costs, warnings in your billing system, or incorrect recommendations from a store locator feature—all bad for your business and bad for user experience.

But the feature isn’t just about preventing negative events. Address autocompletion can have quite a positive impact simply by making things easier on your users, like when someone has a time constraint and needs to complete a purchase quickly. It will also increase the overall quality of all the addresses you collect in your database and therefore decrease your operational costs.
<br>

## Building and Implementing an Address Autocomplete API

For the purposes of this article, I’m going to assume that you’re using a datasource with a structure similar to this:

* **Countries:** Lists all countries and their corresponding ISO code. This table should also include metadata cataloging which data is present or not, like streets that might be missing or whether no postal codes exist for a certain country.
* **Places:** Linked to a country, lists the cities and towns.
* **Postal codes:** Linked to a place, lists the related postal codes. Note that one postal code can be included in more than one place.
* **Streets:** Linked to a place and a postal code, lists all related streets. Note that the same street can cross multiple places or postal codes.

&nbsp;

### Keep a Few Tips in Mind

For building and apartment numbers, I work on the assumption that the datasource doesn’t provide accurate information. It’s truly difficult to have a complete and accurate source of house numbers, so I advise you to leave that as a free input. Otherwise your captured data quality will probably be impaired.

Note that some countries don’t have postal codes or your datasource might not have accurate data for that country. In that case, just show a free input for the fields that are missing data.

The form built in this tutorial calls a backend API that’s linked to a referential database. The API sends back and validates the data from the source, and provides autocomplete when necessary. It’s important to remember that the quality of the result depends a lot on the quality of the reference datasource. You can read the paragraph Ensuring the Quality of Your Datasource to learn more about this.
<br>
### Choose Your Field Order

There are two possible ways to approach building this form. You can enforce the fields to fill in this order:

**1. Country -> Postal code -> Locality -> Street.** This approach is easier technically, but some users might prefer to see a filtered list of postal codes.
**2. Country -> Locality -> Postal code -> Street.** This is a more traditional approach.

I actually recommend combining the two approaches in one form and letting the user fill whichever field they want first. The country should still be enforced as the first field to fill because it's information all the users can give quickly and correctly. It also narrows down the possible choices and allows you to hide or show some fields. As mentioned earlier, some countries don’t even have postal codes, so you wouldn’t need to show a field for them.

The final result for Approach 1 should look like this:

![Autofilling data with postal code first - Approach 1](https://i.imgur.com/rKUabna.png)
<br>
The final result for Approach 2 should look like this:

![Autofilling data with places first - Approach 2](https://i.imgur.com/Sh1hh81.png)
<br>
### Display the Data in the Form

For some endpoints, the data is returned based on what the user is currently typing. To avoid having too many hits on your API endpoint, I recommend a delay of 20 ms. In that time, the user might continue typing their query; by introducing a delay, you avoid sending useless queries to the backend.

A convenient way to implement that functionality is to use the [RxJS debounceTime feature](https://www.learnrxjs.io/learn-rxjs/operators/filtering/debouncetime).
<br>
### Build the API

Here I’ll describe all the endpoints you need to serve to have a complete API. But first, let me share a few quick insights that I’ve found helpful:

* If a path contains a colon (`:`), that indicates a parameter that will be reused in the query.
* For POST requests, the content’s structure is described as the *payload* in a JSON format.
* For all the API endpoints doing an autocomplete, don’t return anything if the user hasn’t started typing. It would make little sense in terms of user experience.
* When filtering on a user’s input, always do a case-insensitive search with wildcards before and after.
* The queries that might return a lot of data should be limited to 100 results to increase both the query performance and the response time.
* Consider that important entities like postal code and place will have a unique identifier. Depending on your datasource, the structure might slightly differ.
* Depending on your datasource’s license, you might want to implement a per user throttling and quota mechanism to avoid having all the data scrapped.
<br>
#### Approaches 1 and 2 — Country

**Endpoint:** `GET /countries`

This returns the list of countries without any filtering. The list is short, so it can be loaded entirely on the client side.

Again, remember that some countries don’t have postal codes and your datasource might not have street data for all the countries. This is a good place to return that information and simply show a free text field for the missing data.
<br>
#### Approach 1 — Postal codes from Country

**Endpoint:** `GET /countries/:iso/postcodes/:postcode`

This returns the autocompletion of a postal code for a given country. The data must be filtered on the postal code.
<br>
####Approach 1 — Places from Postcode

**Endpoint:** `GET /postcodes/:postcodeId/places`

Given a postal code, the API will return all the associated places.
<br>
#### Approach 2 — Places from Country

**Endpoint:** `POST /countries/:iso/places`
**Payload:** `{ place }`

This query should return all the places in a country. The data is filtered on the place entered by the user.
<br>
#### Approach 2 — Postal codes from Place

**Endpoint:** `GET /places/:placeId/postcodes/:postcode`

If the user chose a place from a country, this endpoint must be used to autocomplete the postal code.
<br>
#### Approach 1 and 2 — Street from Place

**Endpoint:** `POST /places/:placeId/streets`
**Payload:** `{ postcodeId, street }`

Note that both the place and the postal code should be necessary to correctly filter the street. This of course depends on your datasource, but combining both usually offers the most accurate discriminator.
<br>
## Improving Your Address Autocomplete API

The autocomplete mechanism presented in this article only works on perfect matches. That’s rarely good enough, so you’ll most likely want to improve on what we’ve already got here.
 <br>
### Implement Full Text Search

Users are going to make spelling mistakes. To alleviate that in simple projects, you can use trigrams or the full text search capability of your DBMS. 

For more complex solutions you can use a dedicated search engine such as [Elasticsearch](https://www.elastic.co/elasticsearch/), [OpenSearch](https://opensearch.org/), or [Typesense](https://typesense.org/).
<br>
### Use Additional Datasets

Additional data can significantly enhance the user experience.

For example, consider how *weighted data* can improve the autocompletion. The most important places have the heavier weight, which would sort the results in a useful order that’s comprehensible for the user while aiding in disambiguation. With correctly weighted data, `Boston (Massachusetts)` would appear first in a list of the many cities that are named Boston in the United States.

Another interesting improvement would be grouping places by the name people expect to find. For example, London doesn’t actually exist as a place within the fine-grained English administrative divisions, but is rather a group of boroughs. Your users will probably still be looking for `London`, though.
<br>
## Ensuring the Quality of Your Datasource

The quality of the datasource used to build your API is critical to the success of your autocomplete feature. Otherwise you’ll gather incomplete information at best and inaccurate information at worst. If a user enters data not present in your dataset, and you’ve made the use of your data mandatory, you could even lose the sign-up or the order, decreasing your overall conversion rates. This can be mitigated by allowing free text to be entered but will worsen the captured data quality.

The datasource you work with needs to include an up-to-date, exhaustive list of valid postal codes and places for all your target countries. Streets can be left optional but having a complete list of streets definitely helps. As it’s difficult to always have an up to date list of valid addresses, it’s best to allow free text. You can try to combine both approaches by trying auto-complete first and then allowing free text if nothing is found.

You’ve got 2 main options for your sources. 

If you’d like to use free or open source data providers, we would recommend to use a combination of  [GeoNames](https://www.geonames.org/) and [OpenStreetMap](https://www.openstreetmap.org). GeoNames links places to postal codes for 96 countries while OpenStreetMap offers street coverage for most countries.

If you’re willing to invest in a paid solution, I’d recommend our [GeoPostcodes](https://eu1.hubs.ly/H02_gy00) database. It contains places for all countries in the world, postal codes for all of the countries using them, and streets for a third of the countries. It’s updated on a weekly basis, relying on more than 1,500 sources. You would benefit from the fact that postal codes and streets are already linked in a unified structure. Based on our experience, it would increase the quality of your API and its speed of implementation. [Browse our datasets] (https://eu1.hubs.ly/H02_gyb0) yourself and access our map explorer for free.


The API described in this tutorial would benefit from GeoPostcodes products like:
 
* **Our [postal normalized street database](https://eu1.hubs.ly/H02_gy90).** It includes alternative place names in foreign languages.
* **[Town weights](https://eu1.hubs.ly/H02_7vL0).** This improves results sorting.
* **[City tags](https://eu1.hubs.ly/H02_gXg0).** You can natively incorporate large cities and metropoles in the search.
<br>

## Conclusion

Clearly, having an autocomplete address form is crucial to a lot of business processes, like logistics or online sales. It vastly improves data quality and ensures correct data processing. With all the information covered here—what it looks like to start with postal code or place for your form, and why you’ve got to have a reliable and updated datasource —you should be well on your way to creating the perfect form to capture accurate addresses.