DEV Community

Marc Newstead
Marc Newstead

Posted on

We built a GB-first Maps & Places API because the mapping bill stopped making sense

The bill nobody budgeted for

If you've shipped anything with a map in it lately, you've had a version of this conversation with your finance person.

The short history: in March 2025 Google Maps Platform retired the flat $200 monthly credit and replaced it with much smaller per-SKU allowances. Subscription tiers followed. The practical effect is that workloads which used to vanish under the credit now bill from a low threshold — and place search sits at the expensive end. Text Search on the Places API (New) runs around $32 per 1,000 calls above a 5,000-call monthly allowance. Request a rating field and the call moves up an SKU tier. Request reviews and it moves up again.

None of that is unreasonable for what Google provides. It's an excellent global dataset and you're paying global-dataset prices.

But plenty of us aren't building for the globe. We're building a UK checkout. A UK store locator. A UK field-service dispatcher. And we're paying for planet-scale coverage, a consumer-search-optimised ranking model, and a session-token billing abstraction we then have to reverse-engineer to forecast next month's spend.

So we built the thing we wanted instead.

Goggle Places

Goggle Places is a Maps & Places API for Great Britain: predictive search, unified place search, nearby lookup, hosted vector maps and routing, behind one key, priced per request.

GB-first is the whole design constraint, and it buys things a global provider can't easily give you:

  • Postcodes are first-class, not a special case bolted onto a generic geocoder. Full and partial input, typo-tolerant, ranked sensibly.
  • Full national coverage — every GB postcode, street, town and landmark, plus amenities, in one index.
  • Real GB public transport — National Rail plus London bus/tube/DLR/ferry, on live timetables.
  • Sub-50ms typeahead from the edge, because autocomplete that lands after the user stops typing isn't autocomplete.

Two search endpoints, and the difference matters

This is the bit worth reading properly, because picking the wrong one is the most likely way to have a bad time.

GET /predict is the addresses-only typeahead — postcodes, streets, towns, landmarks. It's what you want behind a checkout address field.

curl "https://api.goggleplaces.com/predict?q=York" \
  -H "x-api-key: gk_live_pk_..."
Enter fullscreen mode Exit fullscreen mode
{ "hits": [ { "name": "York", "type": "town", "geo_point": { "lat": 53.96, "lon": -1.08 } } ] }
Enter fullscreen mode Exit fullscreen mode

GET /search is the single-field façade. It fans out server-side to the gazetteer and the amenity index, then blends both into one ranked list. So Premier Inn York, Nando's and Pizza Express resolve here — where /predict returns nothing, because they aren't addresses.

curl "https://api.goggleplaces.com/search?q=premier%20inn%20york&mode=all&key=gk_live_pk_..."
Enter fullscreen mode Exit fullscreen mode
{
  "q": "premier inn york",
  "mode": "all",
  "total": 3,
  "hits": [
    {
      "display_name": "Premier Inn York South West, York",
      "kind": "place",
      "type": "lodging",
      "locality": "York",
      "geo_point": { "lat": 53.93, "lon": -1.13 }
    },
    {
      "display_name": "York, North Yorkshire",
      "kind": "address",
      "type": "town",
      "geo_point": { "lat": 53.96, "lon": -1.08 }
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

mode takes all (default), addresses (gazetteer only — identical to /predict) or places (amenities only, for a store locator). Pass lat/lng as a location bias and the amenity half gets a distance decay, so typing travelodge with the map over Manchester surfaces Manchester branches first.

One gotcha, documented but easy to miss: businesses are matched by name. Nando's Manchester won't match, because amenities aren't named with their city. Bias by coordinates instead.

Nearby lookup

Proximity and category rather than typed name — anchored on a point, or on the map viewport so you load exactly what's on screen as the user pans.

# around a point (radius in km, default 5, max 25)
curl "https://api.goggleplaces.com/nearby?lat=53.4808&lng=-2.2426&radius=2&categories=restaurant,bar&key=gk_live_pk_..."

# within a viewport (bbox = minLng,minLat,maxLng,maxLat)
curl "https://api.goggleplaces.com/nearby?bbox=-2.26,53.46,-2.20,53.50&categories=lodging,charging&key=gk_live_pk_..."
Enter fullscreen mode Exit fullscreen mode

Categories: restaurant, bar, attraction, transport, hospital, parking, lodging, charging. Hits come back nearest-first with distance, plus opening_hours, website, phone, cuisine and wheelchair where we have them. Coverage on those secondary fields varies by area, so don't build a UI that assumes opening hours are always present.

Routing

POST /directions, self-hosted over GB data, engine-normalised so the response shape is stable regardless of which engine served it.

curl -X POST "https://api.goggleplaces.com/directions" \
  -H "x-api-key: gk_live_sk_..." \
  -H "content-type: application/json" \
  -d '{
    "origin": [-2.2426, 53.4808],
    "destination": [-1.8904, 52.4862],
    "mode": "auto",
    "alternatives": true
  }'
Enter fullscreen mode Exit fullscreen mode

Modes are auto, bicycle, pedestrian and transit (with the obvious aliases). Up to 25 waypoints, optimize to reorder them as a TSP, GeoJSON LineString geometry, turn-by-turn legs. Set mode=transit and each leg carries the service name, board/alight stops and live times.

Points accept [lon, lat] arrays or {lat, lon} / {lat, lng} objects, so a geo_point from /search drops straight in — you can route to a hotel, not just to an address.

There's a convenience GET for simple two-point routes:

curl "https://api.goggleplaces.com/directions?from=53.4808,-2.2426&to=52.4862,-1.8904" \
  -H "x-api-key: gk_live_sk_..."
Enter fullscreen mode Exit fullscreen mode

Maps

import { map } from '@goggleplaces/sdk'

map({ container: 'map', key: 'gk_live_pk_...' })
Enter fullscreen mode Exit fullscreen mode

A full UK vector map in your <div>. Tiles stream from our API — nothing to self-host, no tile server to operate, no per-tile line item on the invoice.

Keys

Publishable (gk_live_pk_…) are safe to ship in a browser but must be origin-locked; anything else is rejected at the edge with a 403. Secret (gk_live_sk_…) are server-side only. Both are scoped per service, rotatable and metered.

Pricing

Free allowance on every service, then a flat per-1,000 rate. Priced per service, no bundles to decode.

Service Free / month Rate Above 5M*
/predict 30,000 £1.68 / 1k £1.34 / 1k
/nearby 30,000 £2.96 / 1k £2.37 / 1k
/tiles 30,000 £4.15 / 1k £3.32 / 1k
/directions 10,000 £2.96 / 1k £2.37 / 1k

*Directions steps down above 1M rather than 5M. Rates as at August 2026 — check /pricing for current figures.

A card is required to activate the account. You aren't charged unless you exceed the free allowance.

Worked example

The Google comparison depends on your field profile, but a checkout session terminating in a Place Details Pro request is commonly cited around $17 per 1,000 sessions — so ~$1,700 (c £1,260) for 100,000 sessions, against our pricing which would (at an average of 4 debounced calls per session and including the free tier) would work out at £621.60 for the same number of sessions.

Add a map to that page and Google's dynamic map loads run around $7/1,000 against our £4.15/1,000 with 30,000 free — that gap is wider and more straightforward.

When you should not use this

Worth saying plainly, because you'd find out in week three otherwise:

  • You need coverage outside Great Britain. We don't have it. Use Google, HERE or Mapbox.
  • You depend on ratings and review text. We don't return either. If your UI shows star ratings, this isn't a swap you can make.
  • You need Street View or equivalent imagery. Not something we offer.
  • Your POI depth requirement is high in long-tail commercial categories. Coverage is strongest on transport, infrastructure, hospitality and chains, and thinner on small independents in some areas.

Try it

The search box on goggleplaces.com hits the live predictive endpoint on every keystroke — same endpoint your app would call, no demo mode. Open the network tab and throw real queries at it before you sign up for anything.

Docs: goggleplaces.com/docs. Keys: app.goggleplaces.com.

If predictive search mis-ranks somewhere you know well, or the router sends you a stupid way round, put it in the comments. GB coverage is the product, so local knowledge is the most useful bug report we can get.

Top comments (0)