The problem: a bill that spikes with every traffic surge
VoglioMap is an interactive map that locates Voglio Bene resellers around the world. On every visit, the browser loads the map, geolocates the user, geocodes their address, computes routes, displays markers. Multiply that by a few hundred visitors a month, and the Google Maps bill climbs fast.
Early on, I was sitting at around €250/month. Not catastrophic, but pointless: most of those calls were redundant. With a few targeted optimizations, I dropped under €50/month - that's -80% - without losing any functionality.
Here are the 4 techniques that made the difference.
1. Cache geocoding in the database
Geocoding (turning an address into GPS coordinates) is the most expensive call in the Maps API. It's also the most frequent one: every time a new reseller gets added, every time you re-geocode addresses on a visit.
But an address doesn't change every day.
I added a geocode_cache table in MySQL:
CREATE TABLE geocode_cache (
address_hash VARCHAR(64) PRIMARY KEY,
address TEXT,
lat DECIMAL(10, 7),
lng DECIMAL(10, 7),
geocoded_at DATETIME
);
Before each call to the Geocoding API, I compute the SHA-256 hash of the normalized address and check whether it already exists in the cache. If yes, I return the stored coordinates. If no, I call Google, store the result, and reuse it for every future request.
Result: 95% of Geocoding calls eliminated. The bill on that line went from ~€80/month down to ~€5/month.
2. Rate limiting on public endpoints
Without rate limiting, anyone can hammer your frontend (a script that reloads the page, a malicious bot) and blow up the bill in a few hours. It happened to my site once - and the unpleasant surprise showed up on the next month's invoice.
I added a PHP-side middleware:
function checkRateLimit($ip) {
$key = "rate:$ip";
$count = apcu_fetch($key) ?: 0;
if ($count >= 60) return false; // 60 requests / hour max
apcu_store($key, $count + 1, 3600);
return true;
}
60 requests per IP per hour is way more than enough for human use and it blocks abuse. I also added an API-side check for sensitive endpoints (search, navigation), with a lower threshold (10/h for navigation).
Result: zero abnormal spikes since. The bill became predictable.
3. Lazy load markers and clustering
Rendering all markers at once when you have a few hundred of them overloads the browser and triggers more API calls. The fix: only load markers visible in the viewport.
I use Google Maps' bounds_changed event to grab the visible coordinates, then I fetch the markers inside that area. On the server side, it's a simple WHERE lat BETWEEN x AND y AND lng BETWEEN x AND y - fast with spatial indexes.
I also enabled MarkerClusterer: instead of showing 200 individual markers when you zoom out, they're grouped into numbered clusters. Much more readable, and far less DOM to manage.
Result: fewer calls to places.nearbySearch() and a site that stays smooth even with a lot of resellers.
4. Static Maps for non-interactive views
Not every page needs an interactive map. On individual reseller pages, for example, the user just wants to see the location - they're not going to zoom or explore.
For those cases, I swapped the JavaScript embed for the Static Maps API, which returns a PNG image. The cost is ~10 times cheaper per call, and it's also faster to load (a simple image vs. a JS script initializing the map).
<img src="https://maps.googleapis.com/maps/api/staticmap?
center=43.6108,3.8767
&zoom=14
&size=400x300
&markers=color:red%7C43.6108,3.8767
&key=YOUR_API_KEY"
/>
Bonus: images are cached by the browser, so coming back to the same page = zero new call.
Result: ~30% of JavaScript calls converted into Static Maps, at ~10x cheaper.
The numbers
| Line item | Before | After |
|---|---|---|
| Geocoding API | €80/month | €5/month |
| Maps JavaScript API | €130/month | €30/month |
| Places API | €40/month | €8/month |
| Total | €250/month | €43/month |
And the user experience? No visible degradation. On the contrary, the site loads faster (Static Maps + lazy-loaded markers) and is protected against abuse.
What I take away from this
The Google Maps API isn't expensive in absolute terms - it's expensive by default, because it does no optimization for you. You pay for every call, useful or redundant.
Cache, rate-limit, lazy-load: it's basic stuff, but it's rarely done on standard implementations. If you're starting from an unoptimized map, cutting your bill by 3x or 5x is probably within a few hours of dev work.
And if your traffic blows up one day: your optimizations shield you from the pricing shock. That's also what ROI looks like.
