Search docs

JavaScript and TypeScript

Call api.geolith.app from JavaScript or TypeScript with fetch: typed search, autocomplete and reverse helpers for browsers, Node.js, Deno, Bun and Workers.

By · Updated

The API needs no SDK: every endpoint is a GET that returns GeoJSON. This client works in browsers, Node.js 18+, Deno, Bun and Cloudflare Workers.

Use a publishable key (gc_pk_…) in browser code and a secret key (gc_sk_…) on servers. See API keys.

A typed client

// geolith.ts
export interface GeolithFeature {
  type: 'Feature';
  geometry: { type: 'Point'; coordinates: [number, number] };
  properties: {
    id: string;
    gid: string;
    layer: string;
    name: string;
    label: string;
    importance: number;
    street?: string;
    postalcode?: string;
    locality?: string;
    region?: string;
    country?: string;
    country_code?: string;
    category?: string[];
    confidence?: number;
    distance?: number;
  };
}

export interface GeolithCollection {
  type: 'FeatureCollection';
  features: GeolithFeature[];
  bbox?: [number, number, number, number];
}

export class GeolithError extends Error {
  readonly status: number;
  readonly code: string;

  constructor(status: number, code: string, message: string) {
    super(message);
    this.status = status;
    this.code = code;
  }
}

const BASE = 'https://api.geolith.app';

export function createGeolith(apiKey: string) {
  async function get(path: string, params: Record<string, string | number | undefined>) {
    const url = new URL(path, BASE);
    for (const [key, value] of Object.entries(params)) {
      if (value !== undefined) url.searchParams.set(key, String(value));
    }
    url.searchParams.set('api_key', apiKey);
    const res = await fetch(url);
    const body = await res.json();
    if (!res.ok) {
      const code = body.error?.code ?? 'invalid_request';
      const message = body.error?.message ?? body.geocoding?.errors?.join('; ') ?? res.statusText;
      throw new GeolithError(res.status, code, message);
    }
    return body as GeolithCollection;
  }

  return {
    search: (text: string, opts: { size?: number; country?: string; layers?: string } = {}) =>
      get('/v1/search', {
        text,
        size: opts.size,
        'boundary.country': opts.country,
        layers: opts.layers,
      }),
    autocomplete: (text: string, focus?: { lat: number; lon: number }, size = 5) =>
      get('/v1/autocomplete', {
        text,
        size,
        'focus.point.lat': focus?.lat,
        'focus.point.lon': focus?.lon,
      }),
    reverse: (lat: number, lon: number, size = 1) =>
      get('/v1/reverse', { 'point.lat': lat, 'point.lon': lon, size }),
  };
}

Use it

import { createGeolith } from './geolith';

const geolith = createGeolith(process.env.GEOLITH_API_KEY ?? '');

const { features } = await geolith.search('eiffel tower', { size: 1, country: 'FR' });
const [lon, lat] = features[0].geometry.coordinates;
console.log(features[0].properties.label, lat, lon);

const near = await geolith.reverse(18.922, 72.8347);
console.log(near.features[0]?.properties.label);

In a browser, pass a publishable key instead of reading process.env.

Show the attribution

Show © OpenStreetMap contributors (ODbL), Overture Maps Foundation wherever results appear. See Attribution.