Reverse Geocoding
Getting Started
Section titled “Getting Started”| Downloads |
Reverse geocoding turns a Position into a readable address: street, city, region, postal code and country. Shiny uses the
geocoder built into iOS, Mac Catalyst and Android, and the free OpenStreetMap Nominatim API
everywhere else, so there is no API key to manage on any platform. Every geocoder needs network access.
| Platform | Geocoder |
|---|---|
| iOS / Mac Catalyst 26+ | MapKit MKReverseGeocodingRequest |
| iOS / Mac Catalyst 15-25 | CoreLocation CLGeocoder |
| Android 33+ | android.location.Geocoder (listener API) |
| Android < 33 | android.location.Geocoder (run off the calling thread) |
| Android without a geocoding backend (no Google Play Services) | OpenStreetMap Nominatim |
| Windows, Linux, macOS, Blazor WebAssembly | OpenStreetMap Nominatim |
using Shiny;
services.AddGeocoding();Reverse geocoding doesn’t need a location permission, because you pass it the position. Getting that position from the GPS still does.
If you register your own IGeocoder before calling AddGeocoding(), Shiny keeps yours.
Inject IGeocoder:
public class AddressService(IGeocoder geocoder, IGpsManager gps){ public async Task<string?> GetCurrentAddress(CancellationToken ct) { if (!geocoder.IsSupported) return null;
var reading = await gps.GetLastReadingOrCurrentPosition(cancellationToken: ct); if (reading == null) return null;
var placemarks = await geocoder.ReverseGeocode(reading.Position, ct); return placemarks.FirstOrDefault()?.FormattedAddress; }}ReverseGeocode returns the matches, most relevant first, and an empty list when nothing matched.
OpenStreetMap Nominatim
Section titled “OpenStreetMap Nominatim”On Windows, Linux, macOS, Blazor WebAssembly and Android devices without Play Services, IGeocoder calls Nominatim’s
reverse API. The implementation is internal: inject IGeocoder as usual, and configure it through AddGeocoding:
services.AddGeocoding(o =>{ o.Email = "support@myapp.com"; // lets the server's operators reach you before they block you o.Language = "en"; // defaults to the current UI culture // o.BaseUri = new Uri("https://nominatim.mycompany.com/"); // your own server, for heavy use});| Option | Default | Description |
|---|---|---|
BaseUri |
NominatimOptions.PublicServer (https://nominatim.openstreetmap.org/) |
The Nominatim server. Point it at a self-hosted or other Nominatim-compatible server to get past the public rate limit |
UserAgent |
<entry assembly>/<version> (Shiny.Gps) |
Identifies your app, as the public server requires. Browsers don’t let a page set it, so Blazor WebAssembly doesn’t send it and the browser’s Referer identifies the app instead |
Email |
null |
A contact address sent with each request. The public server asks for one if you send a lot of requests |
Language |
current UI culture | The language results come back in (en, fr-CA). null lets the server use local names |
MinimumRequestInterval |
1 second | The minimum time between requests. Lower it only for a server you run yourself |
CacheSize |
100 | How many results are kept in memory, keyed on the position rounded to about a metre. 0 turns the cache off |
The public server is free, but its usage policy limits clients
to one request a second, requires an identifying User-Agent, and asks clients to cache results. Shiny keeps to it: requests
run one at a time and are spaced by MinimumRequestInterval, so calls made close together queue up. A failed request still
counts toward the limit. Nominatim returns one placemark at most. Don’t reverse geocode every GPS reading against the
public server. Geocode when the user asks, or after a significant move.
Placemark
Section titled “Placemark”| Property | Description |
|---|---|
Position |
The position the placemark describes |
Name |
Name of the place: a landmark or business, or the street address |
SubThoroughfare |
Street number |
Thoroughfare |
Street name |
SubLocality |
Neighbourhood or district |
Locality |
City or town |
SubAdministrativeArea |
County or equivalent |
AdministrativeArea |
State, province or equivalent |
PostalCode |
Postal or zip code |
CountryCode |
ISO 3166-1 alpha-2 country code |
CountryName |
Localized country name |
FormattedAddress |
The full address on one line, formatted by the platform |
A component the geocoder couldn’t resolve is null. Results come back in the device’s language (with Nominatim,
NominatimOptions.Language, which defaults to it). With Nominatim, CountryCode is upper-cased to match the native
geocoders, and Position is the point Nominatim matched rather than the one you asked about.
AI Coding Assistant
Section titled “AI Coding Assistant”Step 1 — Add the marketplace:
claude plugin marketplace add shinyorg/skillsStep 2 — Install the plugin:
claude plugin install shiny@shinyOne plugin installs all 48 Shiny skills. Your agent loads only the skill relevant to what you're building, so there's no cost to having them all available.
Step 1 — Add the marketplace:
copilot plugin marketplace add https://github.com/shinyorg/skillsStep 2 — Install the plugin:
copilot plugin install shiny@shinyOne plugin installs all 48 Shiny skills. Your agent loads only the skill relevant to what you're building, so there's no cost to having them all available.


