Skip to content

Guide

Reverse geocoding in JavaScript

Turn latitude and longitude into an address in the browser and in Node.js with the geolith reverse geocoding API, including the user's current location and error handling.

By · 8 min · updated

Reverse geocoding turns coordinates into a place: given a latitude and longitude, GET https://api.geolith.app/v1/reverse?point.lat=…&point.lon=… returns the nearest addresses and places as GeoJSON, nearest first, each with its distance in kilometres. Below are a browser example that names the user's current location and a Node.js function for servers.

The request

curl "https://api.geolith.app/v1/reverse?point.lat=48.858262&point.lon=2.294496&size=1" \
  -H "Authorization: Bearer YOUR_API_KEY"
{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "geometry": { "type": "Point", "coordinates": [2.294496, 48.858262] },
      "properties": {
        "gid": "geolith:venue:4611686018432401268",
        "layer": "venue",
        "label": "Tour Eiffel, Paris 7e Arrondissement, Paris, Île-de-France, France",
        "distance": 0,
        "street": "Avenue Anatole France",
        "postalcode": "75007",
        "region": "Île-de-France",
        "country_code": "FR"
      }
    }
  ]
}

Parameters:

ParameterMeaning
point.lat, point.lonThe point. Required.
boundary.circle.radiusSearch radius in km. Default 1, maximum 100.
sizeNumber of results, 1 to 40. Default 10.
layersFor example address (street addresses only) or venue,address.
langNames in a language, for example hi.

In the browser: "use my location"

Use a publishable key (gc_pk_...) with your site's origin on its allowed list.

<button id="locate">Use my location</button>
<p id="where"></p>

<script type="module">
  const API_KEY = 'YOUR_API_KEY'; // publishable key, gc_pk_...

  async function reverseGeocode(lat, lon) {
    const url = new URL('https://api.geolith.app/v1/reverse');
    url.searchParams.set('point.lat', String(lat));
    url.searchParams.set('point.lon', String(lon));
    url.searchParams.set('size', '1');
    url.searchParams.set('layers', 'address,street,venue');
    url.searchParams.set('api_key', API_KEY);
    const res = await fetch(url);
    if (!res.ok) throw new Error(`geolith ${res.status}: ${await res.text()}`);
    const { features } = await res.json();
    return features[0] ?? null;
  }

  document.getElementById('locate').addEventListener('click', () => {
    const out = document.getElementById('where');
    navigator.geolocation.getCurrentPosition(
      async ({ coords }) => {
        try {
          const place = await reverseGeocode(coords.latitude, coords.longitude);
          out.textContent = place
            ? `${place.properties.label} (${Math.round(place.properties.distance * 1000)} m away)`
            : 'No address found within 1 km.';
        } catch (err) {
          out.textContent = err.message;
        }
      },
      (err) => (out.textContent = `Location unavailable: ${err.message}`),
      { enableHighAccuracy: true, timeout: 10000 },
    );
  });
</script>

Browsers only allow navigator.geolocation on HTTPS pages (and localhost).

In Node.js

Use a secret key (gc_sk_...) from an environment variable. Node 18 and later have fetch built in.

// reverse.mjs — run with: GEOLITH_API_KEY=YOUR_API_KEY node reverse.mjs 35.6586 139.7454
const API = 'https://api.geolith.app/v1/reverse';

export async function reverseGeocode(lat, lon, { radiusKm = 1, layers } = {}) {
  const url = new URL(API);
  url.searchParams.set('point.lat', String(lat));
  url.searchParams.set('point.lon', String(lon));
  url.searchParams.set('boundary.circle.radius', String(radiusKm));
  url.searchParams.set('size', '1');
  if (layers) url.searchParams.set('layers', layers);

  const res = await fetch(url, {
    headers: { Authorization: `Bearer ${process.env.GEOLITH_API_KEY}` },
  });
  if (res.status === 429) throw new Error('geolith: rate limited or monthly quota used up');
  if (!res.ok) throw new Error(`geolith ${res.status}: ${await res.text()}`);

  const { features } = await res.json();
  if (features.length === 0) return null;
  const f = features[0];
  return {
    label: f.properties.label,
    gid: f.properties.gid,
    layer: f.properties.layer,
    distanceKm: f.properties.distance,
    postalcode: f.properties.postalcode ?? null,
    lon: f.geometry.coordinates[0],
    lat: f.geometry.coordinates[1],
  };
}

const [lat, lon] = process.argv.slice(2).map(Number);
if (Number.isFinite(lat) && Number.isFinite(lon)) {
  console.log(await reverseGeocode(lat, lon, { radiusKm: 2 }));
}

Places around a point

To list several places near a point (shops near a delivery partner, stations near a flat), call /v1/nearby with the same point.lat and point.lon. It searches up to 50 km and returns places nearest first:

const url = new URL('https://api.geolith.app/v1/nearby');
url.searchParams.set('point.lat', '12.9716');
url.searchParams.set('point.lon', '77.5946');
url.searchParams.set('layers', 'venue');
url.searchParams.set('size', '10');

Attribution

Show © OpenStreetMap contributors (ODbL), Overture Maps Foundation wherever you display the result. Coverage is worldwide.

Questions

Quick answers

What radius does reverse geocoding search?
1 km by default. Set boundary.circle.radius up to 100 (km) for rural points.
Why is the first result a shop and not a street address?
Reverse returns the nearest places of any layer. Add layers=address for street addresses only, or layers=locality for the town.
Can I cache reverse geocoding results?
Yes. geolith results may be stored permanently on every plan.

Geocode your first address in a minute.

100,000 requests a month free. Commercial use with attribution. No card.