Skip to content

Both copy text to your clipboard — Build with AI copies a setup prompt to paste into Claude Code, Cursor, Codex or Copilot; Copy page as Markdown copies this page to paste into a chat. How it works

Geocoding SDKs

Four typed client packages wrap the v2 geocoder so you don't hand-roll the autocomplete → retrieve loop, session billing, or error parsing yourself:

languagepackagesource
TypeScript / JavaScript@mapmetrics/geocoderNPM/
Dart / Fluttermapatlas_geocoderFlutter/
Swift (iOS / macOS)MapAtlasGeocoderSwift/
Kotlin (Android / JVM)mapatlas-geocoderAndroid/

Not published yet

None of these packages are on npm, pub.dev, Swift Package Index, or Maven Central yet. The install instructions on each language page show the form that will work once they ship (or, for Swift and Kotlin, the git/composite form that works today). Don't expect npm install/dart pub add to resolve against a public registry right now.

Why use an SDK instead of calling the gateway directly

The raw HTTP API (documented under Geocoder v2) has a handful of sharp edges that are easy to get wrong once and then debug for an hour, because most of them fail silently — HTTP 200 with an empty or subtly wrong result, not an error:

  • Sessions are billed, not requests. Autocomplete is billed per search session. Forgetting to carry a stable session_token across keystrokes doesn't error — it just charges roughly 5x more, silently. Every SDK here manages the token for you: one session per search box interaction, automatically.
  • Debounce is your job otherwise. Without it, a fast typist fires a request per keystroke. All four SDKs debounce suggest() calls (150ms by default).
  • Retrieval is keyed on ord, not id. Retrieving by id 404s on every layer. Every SDK takes the suggestion object straight from suggest() and reads ord off it for you — there's no id to get wrong.
  • Some suggestions can't be retrieved at all. The gateway injects locality rows (e.g. two of the fifteen results for q=Amsterdam) that carry no ord. Every SDK exposes isRetrievable on a suggestion so you can filter or disable those rows before the user taps one.
  • Batch retrieval has one specific encoding. /v2/retrieve-batch/ accepts exactly one URL-encoded JSON items parameter — repeated ord=/ords=/ids= params silently return count: 0. The SDKs build that payload for you from an array of suggestion objects.
  • Errors come back as HTTP status + a code string, not an exception hierarchy. Each SDK turns them into typed errors/exceptions — a distinct type per failure (ScopeError, OriginRequiredError, QuotaExceededError, …) — so you can catch/switch on what actually went wrong instead of parsing error.status and error.code yourself.
  • Response shape is easy to get wrong. Forward/reverse geocode return a different, flat shape unless you pass format=pelias. Every SDK forces the GeoJSON envelope on every search/reverse call — you always get a FeatureCollection.

None of this is exotic — it's mechanical, and it's exactly the kind of thing worth doing once, in a typed client, instead of every app re-deriving it from the endpoint docs.

What's the same across all four

  • A MapAtlas client constructed with an API key (or a getToken callback, for rotating credentials).
  • client.geocoding.createSession()session.suggest(query)session.retrieve(suggestion) / session.retrieveBatch(suggestions).
  • A reactive controller for the common "search box" UI shape — see the per-language page for its name and idiom (React hook, Dart Stream, Swift @Observable, Kotlin StateFlow).
  • One-shot search() / reverse() calls for when there's no user typing to debounce.
  • A free tier: 'osm' (naming varies per language) backed by the osm-geocode scope, and a dedicated self-hosted constructor for MapMetrics/atlas-osm-geocoder — see each page's "OSM tier" section.
  • Typed errors/exceptions for every documented gateway failure mode — see API Keys & Security for what each one means.

What differs

  • Routing, matrix, and isochrones are implemented in the TypeScript and Dart packages only. Swift and Kotlin are geocoding-only for now — see their pages for exactly what's covered.
  • Native platforms (Swift, Kotlin, Flutter) need an unrestricted API key. Origin restriction only works for browsers — see Choosing a key for a native app below.

Choosing a key for native apps

Origin restriction is enforced by checking the browser's Origin header — native apps, and any server-side code, send no Origin header at all, so an origin-restricted key can never satisfy that check. This is the single most common integration error a mobile developer hits with these SDKs: reuse a web key in a Flutter/Swift/Kotlin app, and every request throws an origin-required error.

Use an unrestricted key for the Flutter, Swift, and Kotlin SDKs. Origin restriction is still the right call for a browser key used with the TypeScript SDK. See API Keys & Security for the full scope and origin model, and Sessions for the billing model shared by all four SDKs.

Next