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.