- Go 99.6%
- Nix 0.4%
| cmd/stadia | ||
| doc | ||
| .gitignore | ||
| AGENTS.md | ||
| bulk.go | ||
| download_area.go | ||
| elevation.go | ||
| error.go | ||
| example_test.go | ||
| export_test.go | ||
| flake.lock | ||
| flake.nix | ||
| geocode_autocomplete.go | ||
| geocode_bygid.go | ||
| geocode_raw.go | ||
| geocode_structured.go | ||
| go.mod | ||
| go.sum | ||
| logger.go | ||
| map_tile_raster.go | ||
| raster_types.go | ||
| README.md | ||
| request.go | ||
| request_type.go | ||
| response_type.go | ||
| reverse_geocode.go | ||
| stadia.go | ||
| stadia_test.go | ||
| static_map.go | ||
| tile_cache.go | ||
| tile_math.go | ||
| tile_math_test.go | ||
| vector_tile.go | ||
go-stadia
A Go client library for Stadia Maps, a SaaS platform providing geocoding, reverse geocoding, autocomplete, place details, bulk geocoding, and raster map tile services.
Installation
go get source.gleipnir.technology/Gleipnir/go-stadia
Quick Start
package main
import (
"context"
"fmt"
"os"
"source.gleipnir.technology/Gleipnir/go-stadia"
)
func main() {
client := stadia.NewStadiaMaps(os.Getenv("STADIA_MAPS_API_KEY"))
defer client.Close()
ctx := context.Background()
resp, err := client.GeocodeRaw(ctx, stadia.RequestGeocodeRaw{
Text: "1600 Pennsylvania Ave NW, Washington DC",
})
if err != nil {
panic(err)
}
for _, feature := range resp.Features {
fmt.Println(feature.Properties.Label)
}
}
API Reference
Client
client := stadia.NewStadiaMaps(apiKey)
defer client.Close()
The client is built on resty.dev/v3. Use AddResponseMiddleware
to attach custom response middleware (e.g., for logging or caching).
The environment variable STADIA_INSECURE_SKIP_VERIFY (any non-empty value) disables
TLS certificate verification — only use in development or proxy environments.
Geocoding
All geocoding methods accept a context.Context and return *GeocodeResponse.
Raw Search — GeocodeRaw
Freeform text search. Calls GET /geocoding/v1/search.
resp, err := client.GeocodeRaw(ctx, stadia.RequestGeocodeRaw{
Text: "Berlin Hauptbahnhof",
Size: intPtr(5),
})
Supports boundary rectangle, boundary circle, focus point, language, layers, and sources parameters.
Structured Search — GeocodeStructured
Search by discrete address components. Calls GET /geocoding/v1/search/structured.
resp, err := client.GeocodeStructured(ctx, stadia.RequestGeocodeStructured{
Address: strPtr("Põhja pst 27a"),
Locality: strPtr("Tallinn"),
Country: strPtr("EE"),
})
Fields: Address, Neighbourhood, Borough, Locality, County, Region,
PostalCode, Country, plus boundary, focus, layer, and source options.
Autocomplete — GeocodeAutocomplete
Type-ahead / incremental search. Calls GET /geocoding/v2/autocomplete.
resp, err := client.GeocodeAutocomplete(ctx, stadia.RequestGeocodeAutocomplete{
Text: "1600 Penn",
})
Supports the same boundary, focus, layer, and source options as raw search, plus
BoundaryCountry and BoundaryGID.
Reverse Geocode — ReverseGeocode
Find addresses near a point. Calls GET /geocoding/v2/reverse.
resp, err := client.ReverseGeocode(ctx, stadia.RequestReverseGeocode{
Latitude: 40.7128,
Longitude: -74.0060,
})
Supports boundary circle radius, boundary country, boundary GID, layers, sources, and result count.
Place Details — GeocodeByGID
Look up one or more features by their Stadia Maps GID. Calls
GET /geocoding/v2/place_details.
resp, err := client.GeocodeByGID(ctx, stadia.RequestGeocodeByGID{
GIDs: []string{"openaddresses:address:us/ca/tulare-addresses-county:fe9dfab3d45c4550"},
})
Bulk Geocoding — BulkGeocode
Send multiple queries in a single HTTP request. Calls
POST /geocoding/v1/search/bulk.
requests := []stadia.BulkGeocodeQuery{
stadia.RequestGeocodeStructured{
Address: strPtr("12932 Ave 404"),
PostalCode: strPtr("93615"),
},
stadia.RequestGeocodeRaw{
Text: "Empire State Building",
},
}
results, err := client.BulkGeocode(requests)
Only RequestGeocodeStructured and RequestGeocodeRaw implement
BulkGeocodeQuery (they have an endpoint() method).
Map Tiles
Fetch raster map tiles with configurable style, format, and resolution.
TileRasterRequest returns a *Tile with geographic bounds and image data.
// Primary API — full control over style, format, and retina scale.
tile, err := client.TileRasterRequest(ctx, stadia.RequestTileRaster{
Z: 16,
X: 11241,
Y: 26142,
Style: stadia.StyleSatellite,
Format: stadia.FormatJPEG,
})
// tile.Bounds — geographic extent (North, South, East, West)
// tile.Data — raw image bytes
// tile.ContentType — e.g. "image/jpeg"
Available raster styles:
| Constant | Style ID | Description |
|---|---|---|
StyleSatellite |
alidade_satellite |
Satellite imagery (JPEG only) |
StyleSmooth |
alidade_smooth |
Clean general-purpose map |
StyleSmoothDark |
alidade_smooth_dark |
Dark theme |
StyleOutdoors |
outdoors |
Topographic / outdoors |
StyleOSMBright |
osm_bright |
OpenStreetMap bright |
StyleStamenToner |
stamen_toner |
Stamen high-contrast B&W |
StyleStamenTonerLite |
stamen_toner_lite |
Stamen toner (lite) |
StyleStamenTerrain |
stamen_terrain |
Stamen terrain shading |
StyleStamenWatercolor |
stamen_watercolor |
Stamen watercolor art |
Available formats: FormatPNG, FormatJPEG, FormatWebP.
Retina tiles (@2x / @3x) are requested via the Retina field:
tile, _ := client.TileRasterRequest(ctx, stadia.RequestTileRaster{
Z: 16, X: 11241, Y: 26142,
Style: stadia.StyleOutdoors,
Format: stadia.FormatPNG,
Retina: stadia.Scale2x, // 512×512 px tile
})
Use EnsureSize: true to guarantee 256×256 output — retina tiles are
automatically resampled down.
Deprecated: TileRaster(ctx, z, y, x uint) and TileRasterLatLng still
work but delegate to the new API with StyleSatellite / FormatJPEG defaults.
Prefer TileRasterRequest.
Maximum zoom discovery
MaxAvailableZoom probes for the highest zoom level with imagery at a point.
MaxAvailableZoomArea checks multiple sample points and returns the minimum
(slightly pessimistic, avoids missing-tile gaps). Results are memoized.
zoom, _ := client.MaxAvailableZoom(ctx, stadia.StyleSatellite, 40.7128, -74.0060)
zoom, _ = client.MaxAvailableZoomArea(ctx, stadia.StyleSatellite,
36.35021, 36.30616, -119.26937, -119.35014,
)
Coordinate utilities
| Function | Returns | Description |
|---|---|---|
LatLngToTile(z, lat, lng) |
(row, column uint) |
GPS → tile coordinates |
TileToLatLng(z, x, y) |
(lat, lng float64) |
Tile center → GPS |
Bounds(z, x, y) |
TileBounds |
Geographic extent of a tile |
BBoxToTileRange(n, s, e, w, z) |
(xMin, xMax, yMin, yMax) |
Bounding box → tile grid range |
TileCount(n, s, e, w, z) |
int |
Estimated tile count for a bbox |
Requests go to tiles.stadiamaps.com rather than the API host.
Area download
DownloadArea streams all tiles covering a bounding box with tunable
concurrency, retry with exponential backoff, and optional caching. Use
z = 0 to auto-discover the maximum available zoom.
tileCh, errCh := client.DownloadArea(ctx, 36.35021, 36.30616, -119.26937, -119.35014, 0,
stadia.DownloadAreaConfig{
Style: stadia.StyleSatellite,
Format: stadia.FormatJPEG,
Concurrency: 8,
MaxRetries: 3,
Cache: stadia.NewFSStore("./tile_cache"),
},
)
for tile := range tileCh {
fmt.Printf("tile %d/%d/%d: %d bytes\n", tile.Bounds.Z, tile.Bounds.X, tile.Bounds.Y, len(tile.Data))
}
Retry behavior: 5xx and 429 responses are retried with jittered exponential backoff. 4xx errors (other than 429) are not retried. Progress is logged every 30 seconds.
Static Maps
StaticMap fetches a single rendered map image for an area — useful for
web frontends and overview thumbnails.
tile, err := client.StaticMap(ctx, stadia.RequestStaticMap{
Latitude: 40.7128, Longitude: -74.0060,
Zoom: 12,
Width: 512, Height: 512,
Style: stadia.StyleOSMBright,
})
The returned *Tile includes geographic bounds derived from the center,
zoom, and image dimensions.
Tile cache
TileCache is a pluggable interface. FSStore stores tiles on the local
filesystem at {root}/{style}/{z}/{x}/{y}.{fmt}. Used by DownloadArea
to skip already-downloaded tiles (enables resumable downloads).
Elevation tiles
ElevationTile fetches an elevation raster tile and decodes pixel values
into heights in meters. Supports both Terrain RGB and Terrarium encodings.
heights, rawPNG, err := client.ElevationTile(ctx, 12, 2345, 1234, stadia.EncodingTerrainRGB)
// heights is a []float64 with 65536 values (256×256 tile)
// rawPNG is the original PNG data
Encoding formulas:
| Encoding | Formula |
|---|---|
EncodingTerrainRGB |
height = -10000 + ((R×256 + G + B/256) × 0.1) |
EncodingTerrarium |
height = (R×256 + G + B/256) - 32768 |
Vector tiles
VectorTile fetches a Mapbox Vector Tile (.mvt) with road networks,
building footprints, and administrative boundaries as geometry.
data, err := client.VectorTile(ctx, 14, 4567, 2345)
// data is raw MVT bytes — decode with a library like go-mvt
Response Types
All geocoding endpoints return *GeocodeResponse, which wraps a GeoJSON
FeatureCollection:
type GeocodeResponse struct {
BBox []float64
Features []GeocodeFeature
Geocode GeocodeMeta
Type string // "FeatureCollection"
}
GeocodeFeature provides convenience accessor methods that fall back through
multiple response formats:
| Method | Returns | Fallback chain |
|---|---|---|
CountryCode() |
string | CountryCode → Context.ISO3166A3 → WhosOnFirst.Country.Abbreviation |
Locality() |
string | Locality → WhosOnFirst.Locality.Name |
Number() |
string | AddressComponents.Number → HouseNumber |
PostalCode() |
string | PostalCode → AddressComponents.PostalCode |
Region() |
string | Region → WhosOnFirst.Region.Name |
Street() |
string | Street → AddressComponents.Street |
Boundary & Focus Helpers
RequestGeocodeRaw, RequestGeocodeStructured, and RequestGeocodeAutocomplete
all implement the RequestGeocode interface:
type RequestGeocode interface {
SetBoundaryRect(xmin, ymin, xmax, ymax float64)
SetFocusPoint(x, y float64)
}
They also expose the individual BoundaryRect*, BoundaryCircle*, and
FocusPoint* fields directly.
CLI
The cmd/stadia directory contains a unified CLI with subcommands for all
API features. Requires STADIA_MAPS_API_KEY in the environment.
export STADIA_MAPS_API_KEY=your-key
go run ./cmd/stadia [-v] <command> [subcommand] [flags]
| Global flag | Description |
|---|---|
-v, --verbose |
Enable debug-level logging (default: info level) |
The -v flag can appear anywhere on the command line (e.g., stadia -v tiles area ...
or stadia tiles -v area ...).
Geocoding
Raw search — geocode raw
Freeform text search.
go run ./cmd/stadia geocode raw -query "Berlin Hauptbahnhof" -size 5
| Flag | Description |
|---|---|
-query |
Search text (required) |
-focus-lat, -focus-lng |
Bias results toward a point (both required if either set) |
-boundary-rect-min-lat, -boundary-rect-max-lat |
Bounding box (all four required if any set) |
-boundary-rect-min-lng, -boundary-rect-max-lng |
|
-size |
Maximum number of results |
-lang |
Language preference |
Structured search — geocode structured
Search by discrete address fields.
go run ./cmd/stadia geocode structured \
-address "12932 Ave 404" \
-postal-code "93615" \
-city "Orosi"
| Flag | Description |
|---|---|
-address |
Street address (required) |
-postal-code |
Postal/ZIP code (required) |
-city |
Locality (optional) |
-focus-lat, -focus-lng |
Bias results toward a point |
-boundary-rect-* |
Bounding box (all four required if any set) |
Autocomplete — geocode autocomplete
Type-ahead search with optional boundary and focus point filtering.
go run ./cmd/stadia geocode autocomplete -query "1600 Penn"
| Flag | Description |
|---|---|
-query |
Search text (required) |
-focus-lat, -focus-lng |
Bias results toward a point (both required if either set) |
-boundary-rect-min-lat, -boundary-rect-max-lat |
Bounding box (all four required if any set) |
-boundary-rect-min-lng, -boundary-rect-max-lng |
|
-size |
Maximum number of results |
-lang |
Language preference |
Reverse geocode — geocode reverse
Find addresses at a given latitude/longitude.
go run ./cmd/stadia geocode reverse -lat 40.7128 -lng -74.0060
Place details — geocode by-gid
Look up a single feature by its GID.
go run ./cmd/stadia geocode by-gid -gid "openaddresses:address:us/ca/tulare-addresses-county:fe9dfab3d45c4550"
Bulk geocoding — geocode bulk
Sends two hardcoded structured-geocode requests in a single bulk call. No command-line flags — modify the source to change the queries.
go run ./cmd/stadia geocode bulk
Tiles
Single tile — tiles download
Download a raster tile for a given lat/lng with configurable style and format.
go run ./cmd/stadia tiles download -lat 40.7128 -lng -74.0060 -zoom 16
| Flag | Description |
|---|---|
-lat, -lng |
Coordinates (required) |
-zoom |
Zoom level (default: 16) |
-style |
Raster style ID (default: alidade_satellite) |
-format |
Output format: png, jpg, webp (default: jpg) |
-retina |
Retina scale: 1, 2, or 3 (default: 1) |
-ensure-size |
Resample retina tiles to 256×256 (default: false) |
-output |
Output file path (default: tile.raw) |
Area download — tiles area
Download all tiles covering a bounding box. Use -zoom 0 to auto-discover
the maximum available zoom.
go run ./cmd/stadia tiles area \
-north 36.35021 -south 36.30616 \
-west -119.35014 -east -119.26937 \
-zoom 20
| Flag | Description |
|---|---|
-north, -south, -west, -east |
Bounding box (required) |
-zoom |
Zoom level (0 = auto-discover max available) |
-style |
Raster style ID (default: alidade_satellite) |
-format |
Output format (default: jpg) |
-retina |
Retina scale: 1, 2, or 3 (default: 1) |
-ensure-size |
Resample retina tiles to 256×256 (default: false) |
-output-dir |
Output directory (default: tiles) |
Static map — tiles static-map
go run ./cmd/stadia tiles static-map -lat 40.7128 -lng -74.0060 -zoom 12 -width 512 -height 512
| Flag | Description |
|---|---|
-lat, -lng |
Center coordinates (required) |
-zoom |
Zoom level (default: 12) |
-width, -height |
Image dimensions in pixels (default: 512) |
-style |
Raster style ID (default: alidade_satellite) |
-format |
Output format (default: auto) |
-retina |
Retina scale: 1, 2, or 3 (default: 1) |
-output |
Output file path (default: map.raw) |
Elevation — tiles elevation
go run ./cmd/stadia tiles elevation -lat 36.330 -lng -119.300 -zoom 14
| Flag | Description |
|---|---|
-lat, -lng |
Coordinates (required) |
-zoom |
Zoom level (default: 14) |
-encoding |
Elevation encoding: terrain_rgb or terrarium (default: terrain_rgb) |
Vector tile — tiles vector
go run ./cmd/stadia tiles vector -lat 40.7128 -lng -74.0060 -zoom 14
| Flag | Description |
|---|---|
-lat, -lng |
Coordinates (required) |
-zoom |
Zoom level (default: 14) |
-output |
Output file path (default: tile.mvt) |
Development
Nix Flake
nix develop
Dependencies
- resty.dev/v3 — HTTP client
- github.com/google/go-querystring — URL query encoding
- github.com/rs/zerolog — Structured logging
Go Module
module source.gleipnir.technology/Gleipnir/go-stadia
Requires Go 1.26.3+.
License
Proprietary — Gleipnir Technology.