Geocoding API Guide: Convert Addresses to Coordinates

Learn how to convert addresses to coordinates and vice versa using geocoding APIs. Practical examples and best practices.

Article featured image

User types “123 Main St” — you need latitude and longitude. GPS tracker sends coordinates — you need a readable address. Both are geocoding. One forward, one reverse.

Forward Geocoding

Address in, coordinates out.

const response = await fetch(
  `https://api.apiverve.com/v1/geocoding?address=${encodeURIComponent('350 5th Ave, New York')}`,
  { headers: { 'x-api-key': 'YOUR_API_KEY' } }
);

const { data } = await response.json();
// { lat: 40.7484, lng: -73.9857, formatted: "350 5th Ave, New York, NY 10118" }

The API also cleans up the address. Partial input, full output.

Forward geocoding is what most developers reach for first. You have a human-readable string — maybe from a form field, a CSV import, or a CRM record — and you need machine-usable coordinates. The API does the heavy lifting: parsing the address components, matching against its database, and returning the most likely coordinates.

The quality of your input directly affects the quality of your output. “350 5th Avenue, New York, NY 10118” will return a precise rooftop-level coordinate. “5th Ave, NY” will return… something. Probably the midpoint of the avenue. Close enough for some uses, wildly wrong for others.

Confidence Scores Matter

Most geocoding APIs return a confidence or accuracy score alongside the coordinates. Pay attention to it.

const { data } = await response.json();

if (data.confidence < 0.7) {
  // Flag for manual review — the API isn't sure
  await flagForReview(data);
} else {
  // Safe to use programmatically
  await processLocation(data);
}

A confidence of 0.95 means the API matched down to the building. A confidence of 0.4 means it guessed the general area. If you’re calculating delivery routes, that distinction is the difference between a package arriving at the right door and a driver circling the wrong neighborhood for 20 minutes.

Reverse Geocoding

Coordinates in, address out.

const response = await fetch(
  `https://api.apiverve.com/v1/geocoding/reverse?lat=51.5074&lng=-0.1278`,
  { headers: { 'x-api-key': 'YOUR_API_KEY' } }
);

const { data } = await response.json();
// { formatted: "10 Downing St, London SW1A 2AA, UK" }

Mobile apps do this constantly. User taps a spot on the map, you show them what’s there.

Reverse geocoding is trickier than forward in subtle ways. A coordinate might land between two addresses. It might be in the middle of a park with no street address at all. It might be offshore. The API has to make judgment calls about what “nearest address” means.

For most applications, the default behavior works fine. But if you’re building something where precision matters — legal property boundaries, emergency services, asset tracking — you need to understand that the returned address is the API’s best guess, not a surveyed fact.

Different Levels of Detail

Reverse geocoding can return different levels of specificity depending on the coordinate:

  • Rooftop level: “350 5th Ave, New York, NY 10118” — the exact building
  • Street level: “5th Avenue, New York, NY” — the nearest street
  • Neighborhood level: “Midtown Manhattan, New York, NY” — the general area
  • City level: “New York, NY, United States” — when there’s nothing more specific

Your application should handle all of these gracefully. A delivery app needs rooftop precision. A weather widget just needs the city.

The “Main Street” Problem

“123 Main Street” exists in basically every American city. Without context, the API picks one — probably not the one you wanted.

Add constraints:

const params = new URLSearchParams({
  address: '123 Main Street',
  city: 'Boston',
  state: 'MA',
  country: 'US'
});

const url = `https://api.apiverve.com/v1/geocoding?${params}`;

More context = better results. If your app serves one country, hardcode the country. If it’s regional, pass the region.

Accuracy Considerations

Not all geocoded coordinates are created equal. Understanding accuracy levels helps you build appropriate trust into your system.

Rooftop accuracy places the pin at the actual building entrance or centroid. This is the gold standard — you get it with complete, well-formatted addresses in well-mapped areas.

Interpolated accuracy is what happens when the API knows a street address range but not the exact building. It calculates an approximate position along the street. “142 Oak Lane” might be interpolated between known points at 100 and 200 Oak Lane. Usually within 50 meters of the real location, but not always.

Centroid accuracy means the API matched the city, ZIP code, or neighborhood but couldn’t pinpoint the exact address. You get the geographic center of that area. For a small town, that might be close enough. For “Los Angeles, CA,” the centroid is miles from most actual addresses.

Think about what your application actually needs. A “find restaurants near me” feature works fine with interpolated accuracy. A drone delivery system does not.

Batch Geocoding

Single lookups are straightforward. But what about geocoding 50,000 customer addresses from a CSV import?

Don’t make 50,000 individual API calls in a tight loop. You’ll hit rate limits, waste credits on retries, and your import will take hours.

async function batchGeocode(addresses, concurrency = 5) {
  const results = [];
  const chunks = [];

  // Split into chunks
  for (let i = 0; i < addresses.length; i += concurrency) {
    chunks.push(addresses.slice(i, i + concurrency));
  }

  for (const chunk of chunks) {
    const promises = chunk.map(addr => geocodeWithRetry(addr));
    const chunkResults = await Promise.all(promises);
    results.push(...chunkResults);

    // Respect rate limits
    await sleep(200);
  }

  return results;
}

async function geocodeWithRetry(address, maxRetries = 3) {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      return await geocodeAddress(address);
    } catch (err) {
      if (err.status === 429) {
        // Rate limited — back off exponentially
        await sleep(1000 * Math.pow(2, attempt));
      } else {
        throw err;
      }
    }
  }
}

Key principles for batch geocoding:

  • Deduplicate first. If 200 customers share the same address, geocode it once.
  • Limit concurrency. 5-10 parallel requests is usually the sweet spot. Check the provider’s rate limits documentation.
  • Cache progressively. Write results to your database as you go, so a failure at record 40,000 doesn’t lose the first 39,999.
  • Handle partial failures gracefully. Some addresses will fail. Log them, skip them, continue. Review failures separately.

Multiple Results

Sometimes the API finds several matches. “Springfield” returns about 30 in the US alone.

const { data } = await response.json();

if (data.results.length > 1) {
  // Let user pick, or take the first (highest confidence)
  console.log('Multiple matches:', data.results.map(r => r.formatted));
}

Don’t just grab the first one silently. Either show options or tell the user to be more specific.

Caching (Do This)

Addresses don’t move. Once you’ve geocoded “350 5th Ave, New York” there’s zero reason to geocode it again tomorrow.

// Redis example
const cacheKey = `geo:${address.toLowerCase().trim()}`;
const cached = await redis.get(cacheKey);

if (cached) return JSON.parse(cached);

const result = await geocodeAddress(address);
await redis.setex(cacheKey, 60 * 60 * 24 * 30, JSON.stringify(result)); // 30 days

return result;

30-day cache is conservative. Addresses change less often than you’d think.

Cache Key Normalization

The sneaky problem with caching geocoding results: “350 5th Ave” and “350 Fifth Avenue” and “350 5th Avenue, NYC” are all the same place but produce different cache keys.

Normalize before caching:

function normalizeAddress(address) {
  return address
    .toLowerCase()
    .trim()
    .replace(/\s+/g, ' ')           // collapse whitespace
    .replace(/\bst\b/g, 'street')   // expand abbreviations
    .replace(/\bave\b/g, 'avenue')
    .replace(/\bdr\b/g, 'drive')
    .replace(/[.,#]/g, '');          // remove punctuation
}

const cacheKey = `geo:${normalizeAddress(address)}`;

This won’t catch everything — “NYC” vs “New York City” still won’t match — but it eliminates the most common duplicates and saves credits on repeated lookups.

Common Use Cases in Practice

Store Locator

The classic. Geocode all store addresses once at import time, store the coordinates in your database. When a user searches, geocode their input, calculate distances, return a sorted list.

async function findNearestStores(userAddress, maxDistance = 25) {
  const userCoords = await geocode(userAddress);

  const stores = await db.query(`
    SELECT *, haversine(?, ?, lat, lng) as distance
    FROM stores
    WHERE haversine(?, ?, lat, lng) < ?
    ORDER BY distance ASC
    LIMIT 10
  `, [userCoords.lat, userCoords.lng, userCoords.lat, userCoords.lng, maxDistance]);

  return stores;
}

Pro tip: pre-geocode your store addresses during data import, not at query time. A user searching “coffee shops near me” shouldn’t wait for 500 geocoding calls to complete.

Delivery Routing and Zones

Geocode the destination, check if coordinates fall within your delivery polygon. Simple point-in-polygon math determines whether you deliver there.

This is where accuracy really matters. An address geocoded to the wrong side of a street could fall outside your delivery zone boundary. For zone boundaries, add a small buffer — if a point is within 100 meters of your polygon edge, flag it for manual review rather than auto-rejecting.

Analytics and Visualization

Geocoding turns boring address data into map visualizations. Plot your customer distribution, identify geographic clusters, find underserved areas.

Combine geocoding with IP Lookup for even richer location intelligence — you can compare where users say they are (billing address) versus where they actually are (IP geolocation). Useful for fraud detection, not just analytics.

Address Validation

User enters address, you geocode it, and if it fails or returns low confidence, flag for review. This catches typos, incomplete addresses, and outright fake addresses before they cause downstream problems.

Distance Between Two Points

Once you have coordinates, you probably want distance:

function haversine(lat1, lon1, lat2, lon2) {
  const R = 6371; // Earth radius in km
  const dLat = (lat2 - lat1) * Math.PI / 180;
  const dLon = (lon2 - lon1) * Math.PI / 180;

  const a = Math.sin(dLat/2) ** 2 +
            Math.cos(lat1 * Math.PI/180) * Math.cos(lat2 * Math.PI/180) *
            Math.sin(dLon/2) ** 2;

  return R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
}

// NYC to LA
haversine(40.7128, -74.0060, 34.0522, -118.2437); // ~3936 km

That’s straight-line distance. Driving distance requires a routing API — different beast entirely.

Edge Cases That Will Bite You

Every geocoding integration eventually runs into weird cases. Here’s what to watch for:

Rural and New Addresses

A farmhouse on “County Road 47” three miles past the gas station doesn’t geocode well. Rural addresses often lack the structured data geocoding APIs depend on. New housing developments face the same problem — the streets exist physically but haven’t propagated to the geocoding database yet. Expect a 3-6 month lag for new construction.

Your fallback: accept a ZIP or postal code and geocode that instead. You lose precision but at least get the right general area.

International Address Formats

Japanese addresses work differently than American ones — they describe areas hierarchically from large to small, not building-to-city like Western addresses. Arabic addresses might read right-to-left. Some countries don’t use street numbers at all.

The API handles most of this internally, but your UI might not display it correctly. Don’t assume all addresses fit into a “street, city, state, ZIP” template. Use the formatted field the API returns rather than trying to reconstruct the address from parsed components.

Coordinates at Sea

Reverse geocoding a point in the middle of the Pacific Ocean returns… what, exactly? Some APIs return the nearest landmass. Some return nothing. Some return the ocean name.

If your application processes GPS data from ships, aircraft, or IoT devices, you’ll hit this. Check how your geocoding provider handles maritime coordinates before you discover it in production.

Edge of Map Tiles and Time Zones

A coordinate right on a country border might return either country depending on the provider’s data. Same for time zones — a point on the border of two zones could go either way. If this matters for your application (tax calculations, regulatory compliance), use the IP Lookup API or a dedicated timezone service as a cross-reference rather than relying on geocoding alone.

What Can Go Wrong

Ambiguous addresses: “Airport Road” exists everywhere. Add context or expect wrong results.

New construction: Brand new addresses might not exist in the geocoding database yet. Usually takes a few months.

International formats: Japanese addresses work differently than American ones. The API handles this, but your UI might not display it correctly.

Typos: “123 Main Stret” might work (fuzzy matching) or might fail completely. Depends on the provider.

Rate limits: Batch geocoding 100,000 addresses without throttling will get you rate-limited fast. Build in delays and respect the error handling patterns documented by your provider.

Keep Reading


That covers 90% of geocoding use cases. Grab an API key and try it — the free tier handles plenty of testing. For the other location APIs, check out IP Lookup (geolocate by IP, no address needed) and Timezone (get timezone from coordinates).

Try geocoding for free

Convert addresses to coordinates with our Geocoding API. Start free today.

Get Free API Key