An Area Guide Powered by the Google Places API

Auto-fetching hours and ratings while staying within policy and budget

Google Places APInearby placesmapspolicy compliancecaching
6 min read

Introduction

One thing that quietly never gets done on a property website is information about nearby businesses. You'd like to list "the closest supermarket" and "places we recommend for dinner," but opening hours change and shops close down. Hand-written information is usually stale within six months.

In this article, we share how we built an area guide page by combining the Google Places API with our own data. Freshness is maintained automatically, while the question of what to recommend stays firmly a decision of the property.

"Why we recommend it" is ours; "how it is right now" is Google's

Drawing a clear line between the two

The first thing we decided was who owns which piece of information. Which places to list and why we recommend them: the property decides. Changing details like opening hours and ratings: pull from Google. Holding that line without wavering became the starting point for every other design choice.

In the admin panel, each place has individual toggles for whether to show opening hours and whether to show ratings. That lets you hide ratings for categories where they aren't useful, like convenience stores.

What you may store, and what you may not

The Google Places API comes with an important rule in its terms of service: of the data you fetch, the only thing you may store indefinitely is the Place ID (the identifier for a business). Opening hours and ratings may only be held temporarily as a cache.

So our database stores nothing but the Place ID, and we fetch from the API each time we render. Results are cached for just six hours, so repeated visits to the same page don't multiply API calls.

Keep the page intact even when things break

External APIs go down eventually — that's a given. If the whole area guide page errors out because Google didn't respond, we've defeated the purpose.

So the fetch logic never throws on failure; it returns "no information" instead. Only the opening hours and ratings disappear, while the descriptions and directions written by the property keep showing. The page always holds together. That principle applies to every feature that depends on an external service.

How you use the API changes the bill enormously

Don't fetch what you won't use

The Places API charges differently depending on which fields you request. In one real incident, a screen that doesn't display photos was still fetching photo data, generating more than 2,000 wasted calls a month.

So we added an option on the calling side to explicitly say "no photos needed," and stopped fetching them in contexts where they aren't used — like when the AI assistant looks up nearby information. Fetch only what you use. Simple, but it goes straight to the bill.

Being smarter about how results are sorted

Search for nearby businesses and you'll sometimes find a place with a perfect score from a single review sitting at the top. That's not much help to anyone.

So we implemented our own sorting: prioritize places with at least 15 reviews, then order by rating within that group. Note that we only lower the priority of places with few reviews — we don't exclude them.

Keeping API keys in separate places

We split the Google Maps-related keys by what they're used for.

Separating API keys by purpose
Server-only key

Place details, photos, text search. Never handed to the browser

Browser-exposed key

Embedded map display only, restricted by referring domain

Photos are served after the server resolves the URL, so the server key never leaks into the browser. For the embedded-map key, which has to be exposed to the browser, we always apply a restriction that only allows calls from our own site.

Embedding place cards in blog posts too

Keep only the Place ID in the article

When you write about a business on the blog, putting the name and opening hours into the body of the post means it goes stale, same as anywhere else. So we built a "search for a place and insert it" feature into the admin panel's editor, and what actually gets embedded in the article is just the Place ID.

The moment the article renders, it pulls the current name and rating from the API and shows them alongside the property's own comment. Even in a five-year-old post, the name and rating are today's. The only thing that persists as an asset of the article is the recommendation the operator wrote.

Preventing rapid-fire searches

If the place search in the admin panel called the API on every keystroke, the charges would pile up. So we set a rate limit of a little over a second between searches, cutting out wasted calls from rapid typing. It's not "the admin panel is safe" — it's that the admin panel is exactly where costs creep up without you noticing.

Wrapping up

Three things mattered most in designing the area guide page.

  1. Decide who owns what — the reason to recommend is ours, the current state is Google's. Don't mix them
  2. Respect the terms and the budget — store Place IDs only, and don't fetch what you won't use
  3. Hold together when things break — during an API outage, keep the page running on our own information

This nearby-places data also feeds the answers given by the AI assistant for staying guests. See "The big picture of an AI assistant for staying guests" for more.