On this page
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:
| Title | Description | Link |
|---|---|---|
| Single address geocoding | Geocode one address with free-form or structured input and read the best match from the response. | Open CodePen |
| Multiple addresses geocoding | Geocode 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/searchThe most important request parameters for this tutorial are:
text: a free-form address stringname,housenumber,street,postcode,city,state,country: structured address fieldsapiKey: 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 asjsonorgeojsonlimit: maximum number of results to returnfilter: restrict results to a specific areabias: 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 geocodeformat=json: return the result as a JSON objectlimit=1: return only the best matchapiKey: 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-limiterThen 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:
requestsis an array of functions, where each function sends one geocoding requestMAX_REQUESTS_PER_INTERVALandRATE_LIMIT_INTERVAL_MScontrol how many requests can run within the time window- each request returns either a
resultor anerror, while preserving the original inputaddress
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:
latandlon: the coordinates of the matched locationformatted: the full normalized address stringhousenumber,street,city,state,postcode,country: parsed address componentsresult_type: what kind of object was found, for examplebuildingrank: confidence and match quality informationbbox: 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
latandlonto place the address on a map or use it in routing - show
formatted,address_line1, oraddress_line2in the UI - inspect
rank.confidenceandrank.match_typeto 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 resultmatch_type: "full_match": the input closely matches the returned addressconfidence_city_level: 1: the city-level match is strongconfidence_street_level: 1: the street-level match is strongconfidence_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.

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

Batch Geocoding - Bulk Convert Addresses to Lat/Long

Python Geocoding Tutorial: From Address List to Saved Results
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.
