Javascript Tutorial: How to search addresses with Geocoding API

Search single and multiple addresses in JavaScript using Geoapify Geocoding API
Search single and multiple addresses in JavaScript using Geoapify Geocoding API

One of the most common geocoding tasks is getting coordinates for a list of addresses, usually customer or client addresses. This is a common requirement for delivery planning, service coverage checks, route optimization, and map visualization.

This is exactly what a Geocoding API is used for. Geocoding converts an address or place name into geographic coordinates such as latitude and longitude, so you can place locations on a map, calculate routes, or analyze service areas. Along with coordinates, the API can also return parsed and normalized address data, which helps validate user input, standardize records, and work with address components in your application.

In this tutorial we will look at how to geocode addresses with Geoapify Geocoding API in JavaScript. We will cover single-address geocoding with free-form and structured input, and multiple-address geocoding with a rate-limit-friendly request flow.

Below are two JavaScript examples that cover the most common geocoding scenarios:

TitleDescriptionLink
Single address geocodingGeocode one address with free-form or structured input and read the best match from the response.Open CodePen
Multiple addresses geocodingGeocode a list of addresses, keep input-to-result mapping, and respect API rate limits.Open CodePen

Geocoding API overview

In this tutorial, we will use the Geoapify Geocoding API to convert addresses into coordinates. The API accepts both free-form input through the text parameter and structured input through separate parameters like name, housenumber, street, postcode, city, state, and country.

The request endpoint is:

https://api.geoapify.com/v1/geocode/search

The most important request parameters for this tutorial are:

  • text: a free-form address string
  • name, housenumber, street, postcode, city, state, country: structured address fields
  • apiKey: your Geoapify API key. You can register and get a free API key at Geoapify MyProjects. The free plan includes up to 3000 geocoding requests per day.
  • format: response format such as json or geojson
  • limit: maximum number of results to return
  • filter: restrict results to a specific area
  • bias: prefer results near a location or within an area

The API returns one or more matching results. Each result includes coordinates and normalized address properties, so you can choose the best match and use it in your application.

For the full parameter reference, see the Forward Geocoding API documentation. You can also experiment with requests in the Geoapify Geocoding Playground.

Geocode a single address

Let's start with the most common case: geocoding a single address in JavaScript. The example below uses fetch() and builds the request URL from parameters, which is a clean way to work with free-form input and additional options like format and limit.

const apiKey = "YOUR_API_KEY";

async function geocodeSingleAddress(address) {
  const params = new URLSearchParams({
    text: address,
    format: "json",
    limit: "1",
    apiKey
  });

  const url = `https://api.geoapify.com/v1/geocode/search?${params.toString()}`;
  const response = await fetch(url);
  const result = await response.json();

  return result;
}

geocodeSingleAddress("1600 Amphitheatre Parkway, Mountain View, CA")
  .then(result => console.log(result))
  .catch(error => console.error(error));

In this example, we build the request URL with the following parameters:

  • text: the free-form address to geocode
  • format=json: return the result as a JSON object
  • limit=1: return only the best match
  • apiKey: authenticate the request

You can also build the URL directly as a string:

const apiKey = "YOUR_API_KEY";
const address = "1600 Amphitheatre Parkway, Mountain View, CA";

const url = `https://api.geoapify.com/v1/geocode/search?text=${encodeURIComponent(address)}&format=json&limit=1&apiKey=${apiKey}`;

fetch(url)
  .then(response => response.json())
  .then(result => console.log(result))
  .catch(error => console.error(error));

When you use URLSearchParams, parameter values are encoded automatically. When you build the URL manually, you should use encodeURIComponent() for address values, otherwise spaces, commas, and other special characters may break the request.

JavaScript docs: URLSearchParams, encodeURIComponent()

If you already have separate address fields, you can send a structured query instead of a free-form text value:

const apiKey = "YOUR_API_KEY";

async function geocodeStructuredAddress() {
  const params = new URLSearchParams({
    housenumber: "1600",
    street: "Amphitheatre Parkway",
    city: "Mountain View",
    state: "CA",
    country: "United States",
    format: "json",
    limit: "1",
    apiKey
  });

  const url = `https://api.geoapify.com/v1/geocode/search?${params.toString()}`;
  const response = await fetch(url);
  const result = await response.json();

  return result;
}

Structured queries are useful when the address is already split into fields, for example from a checkout form or CRM record. Free-form queries work well when users enter the whole address into a single input.

Try the example

Use the live CodePen example below to test single-address geocoding in the browser and inspect the request and response flow.

See the Pen Geoapify Geocoding API: Build, Encode, Send Request on CodePen.

Geocode multiple addresses

Geocoding a list of addresses requires a slightly different approach than geocoding a single address. If you send too many requests at once, you may hit API rate limits and get 429 Too Many Requests responses. Read more in How to avoid 429 Too Many Requests with API rate limiting.

This is why requests per second (RPS) matter. Geoapify's free plan includes up to 5 requests per second and 3000 requests per day, so when you process multiple addresses you should queue requests and send them in a controlled flow.

Here is one way to do that with the @geoapify/request-rate-limiter package. It helps process a list of requests while staying within the allowed rate limit.

Install the package:

npm install @geoapify/request-rate-limiter

Then create one request function per address and pass them to the rate limiter:

// Create one async request function per address.
const requestRateLimiter = getRequestRateLimiter();
const requests = addresses.map((address) => createGeocodingRequest(address));

// Run the requests through the rate limiter.
const geocodingResults = await requestRateLimiter.rateLimitedRequests(
  requests,
  MAX_REQUESTS_PER_INTERVAL,
  RATE_LIMIT_INTERVAL_MS
);

function createGeocodingRequest(address) {
  return async () => {
    try {
      const response = await fetch(buildGeocodingRequestUrl(address));

      if (!response.ok) {
        // Preserve the original input together with the error.
        return {
          address,
          error: `Request failed with status ${response.status}`,
        };
      }

      const data = await response.json();
      // Return the best matching result for this address.
      return {
        address,
        result: data.results && data.results.length ? data.results[0] : null,
      };
    } catch (error) {
      return {
        address,
        error: String(error),
      };
    }
  };
}

In this example:

  • requests is an array of functions, where each function sends one geocoding request
  • MAX_REQUESTS_PER_INTERVAL and RATE_LIMIT_INTERVAL_MS control how many requests can run within the time window
  • each request returns either a result or an error, while preserving the original input address

This pattern makes it easier to geocode address lists safely and keep the mapping between the original input address and the returned result.

Try the example

Use the live CodePen example below to test multiple-address geocoding with rate limiting in the browser.

See the Pen Geoapify Geocoding API: Multiple Addresses with Rate Limiting on CodePen.

Read and use the geocoding response

Once a request is complete, the next step is to read the returned data. When you use format=json, the API returns a results array with one or more matches. If you set limit=1, the first item in results is the best match for the address.

Here is an example response:

{
  "results": [
    {
      "datasource": {
        "sourcename": "openstreetmap",
        "attribution": "© OpenStreetMap contributors",
        "license": "Open Database License",
        "url": "https://www.openstreetmap.org/copyright"
      },
      "country": "United States",
      "country_code": "us",
      "state": "Oregon",
      "county": "Multnomah County",
      "city": "Portland",
      "postcode": "97239",
      "suburb": "Southwest Hills",
      "street": "Southwest Patrick Place",
      "housenumber": "4155",
      "iso3166_2": "US-OR",
      "lon": -122.6990396,
      "lat": 45.4937284,
      "state_code": "OR",
      "result_type": "building",
      "formatted": "4155 Southwest Patrick Place, Portland, OR 97239, United States of America",
      "address_line1": "4155 Southwest Patrick Place",
      "address_line2": "Portland, OR 97239, United States of America",
      "category": "building.residential",
      "timezone": {
        "name": "America/Los_Angeles",
        "offset_STD": "-08:00",
        "offset_STD_seconds": -28800,
        "offset_DST": "-07:00",
        "offset_DST_seconds": -25200,
        "abbreviation_STD": "PST",
        "abbreviation_DST": "PDT"
      },
      "plus_code": "84QVF8V2+F9",
      "plus_code_short": "F8V2+F9, 97239 Portland, United States",
      "rank": {
        "importance": 0.0000753574425878846,
        "popularity": 4.139753383392894,
        "confidence": 1,
        "confidence_city_level": 1,
        "confidence_street_level": 1,
        "confidence_building_level": 1,
        "match_type": "full_match"
      },
      "place_id": "51f9269710bdac5ec0599f8d017e32bf4640f00102f901e755ed1500000000c00203",
      "bbox": {
        "lon1": -122.6991816,
        "lat1": 45.4935932,
        "lon2": -122.6988161,
        "lat2": 45.4938858
      }
    }
  ],
  "query": {
    "text": "4155 Southwest Patrick Place, Portland, OR 97239, United States of America",
    "parsed": {
      "housenumber": "4155",
      "street": "southwest patrick place",
      "postcode": "97239",
      "city": "portland",
      "state": "or",
      "country": "united states of america",
      "expected_type": "building"
    }
  }
}

The most useful fields are:

  • lat and lon: the coordinates of the matched location
  • formatted: the full normalized address string
  • housenumber, street, city, state, postcode, country: parsed address components
  • result_type: what kind of object was found, for example building
  • rank: confidence and match quality information
  • bbox: the bounding box of the matched feature

The response also includes a query object. The query.parsed section shows how the API interpreted the input address, which can be useful for debugging or validating user input.

To read the best result, access the first item in the results array:

const firstResult = data.results[0];

console.log(firstResult.formatted);
console.log(firstResult.lat, firstResult.lon);
console.log(firstResult.result_type);

Once you have the first result, you can use it in different ways:

  • save lat and lon to place the address on a map or use it in routing
  • show formatted, address_line1, or address_line2 in the UI
  • inspect rank.confidence and rank.match_type to understand match quality

Check match quality

To check match quality, look at the rank object. It contains confidence values and information about how closely the returned address matches the input.

In the sample response above, the rank object contains:

  • confidence: 1: the API is highly confident that this is the correct result
  • match_type: "full_match": the input closely matches the returned address
  • confidence_city_level: 1: the city-level match is strong
  • confidence_street_level: 1: the street-level match is strong
  • confidence_building_level: 1: the building-level match is strong

This combination usually means the address was matched very precisely, down to the building level. If these values are lower, or if the match_type is less exact, you may want to review the result more carefully before using it in a user-facing workflow.

Before reading the first item, it is a good idea to check that the API returned at least one result:

if (!data.results || !data.results.length) {
  console.log("No geocoding results found");
} else {
  const firstResult = data.results[0];

  console.log(firstResult.formatted);
  console.log(firstResult.lat, firstResult.lon);
  console.log(firstResult.rank?.confidence);
  console.log(firstResult.rank?.match_type);
}

Not every response contains every field. The available properties depend on the input address, the result type, and the underlying data source.

Conclusion

In this tutorial, we looked at how to geocode single addresses and lists of addresses in JavaScript with the Geoapify Geocoding API. We also covered how to build request URLs, handle rate limits, and read the returned results so you can use them in your application.

Ready to try it? Open the Geoapify Geocoding Playground and send your first request.

Learn more

Continue with the resources below to explore related geocoding workflows and integration patterns. These guides cover reverse geocoding, batch processing, and additional ways to work with Geoapify in your applications.

Geoapify Reverse Geocoding API JSFiddle

Javascript Tutorial: How to get address by coordinates with Reverse Geocoding API

Learn how to call Reverse Geocoding API to get an address by coordinates a user clicked on.
Geocode up to 1000 addresses at once

Batch Geocoding - Bulk Convert Addresses to Lat/Long

Batch geocoding lets you convert a list of addresses to lat/long in one request. Get results in JSON or CSV format. Visit Geoapify for more info.
Convert addresses to latitude and longitude using Python

Python Geocoding Tutorial: From Address List to Saved Results

Step-by-step guide to geocoding addresses with Python, handling responses, and respecting Geoapify API rate limits in your code.

FAQ

What is geocoding?

Geocoding is the process of converting an address or place name into geographic coordinates such as latitude and longitude. These coordinates can then be used in maps, routing, and other location-based workflows.

What is the difference between free-form and structured geocoding?

Free-form geocoding sends the whole address as one text string using the text parameter. Structured geocoding sends separate fields such as housenumber, street, city, and postcode, which is useful when your address data is already split into fields.

How do I geocode a single address in JavaScript?

You can send a request to the Geoapify Geocoding API with fetch(), either by building the URL with URLSearchParams or by creating the query string manually. In most cases, setting limit=1 is enough to get the best matching result.

How do I geocode multiple addresses without hitting rate limits?

Queue the requests and send them in a controlled flow instead of firing all of them at once. In this tutorial, we use @geoapify/request-rate-limiter to respect the Geoapify rate limits.

What does 429 Too Many Requests mean?

A 429 Too Many Requests response means your application sent more requests than allowed within the current time window. To avoid it, throttle requests, process address lists in batches, or use a rate limiter. Read more in our guide on avoiding 429 errors.

What fields are returned by the Geoapify Geocoding API?

A typical response includes coordinates like lat and lon, a normalized address in formatted, separate address components such as street, city, and postcode, as well as metadata such as result_type, rank, and bbox.

How do I get the best geocoding match from the response?

When you request format=json and use limit=1, the first item in data.results is the best match. You can also inspect rank.confidence and rank.match_type to better understand the quality of the match.

What should I do if the API returns no results?

Always check whether data.results exists and contains at least one item before reading data.results[0]. If there are no results, you can ask the user to review the address, try a broader query, or fall back to structured input if available.

Should I use URLSearchParams or encodeURIComponent() in JavaScript?

If you build query strings with URLSearchParams, parameter values are encoded automatically. If you construct the URL manually as a string, you should use encodeURIComponent() for address values to avoid issues with spaces, commas, and other special characters.

How do I get a Geoapify API key and test requests?

You can create a free API key in Geoapify MyProjects. To test and tweak requests before coding, use the Geoapify Geocoding Playground.