Early this month, we moved every Static Maps request to a new rendering system. The API didn't change, so you don't need to update anything on your side.
Responses got faster and more consistent. The old system was fast, most of the time. The problem was the slowest requests: 1%-5% of them regularly took 1-4s or more, even with caching. When traffic spiked, we kept the service up by slowing requests down or rejecting them.
Fewer Tiles, Faster Maps
We built our original Static Maps API by stitching together tiles from our tile servers. Like web maps, we fetched tiles from our internal systems, stitched them together, and overlaid your pins, lines, and labels to render the final static map image. This approach began to show its limits as our services scaled, and spikes in Static Maps often slowed all our Map products. We needed to fix that, so we completely overhauled the system.
We rewrote Static Maps in Rust using MapLibre Native. Instead of stitching tiles together to create the static map image, we now render the entire map as one image, with all overlays rendered directly in MapLibre Native. As a result, median response time halved. The slowest 1% of requests went from up to 8s to about 1s.
Here's a typical hour before the change. You can't even see the p75 or p50 times, because p99 dominates the timing so much:

Before, all percentiles

Before, p75 and p50

After, all percentiles

After, p75 and p50
The results speak for themselves. Worst-case, loaded performance is now faster than the previous system's baseline.
Here's the before and after. Each row shows how long it takes for 50%, 95%, or 99% of requests to finish:
| Percentile | Before | After |
|---|---|---|
| p50 | ~333ms | ~170ms |
| p95 | 1-4s | 600-700ms |
| p99 | 2-8s | ~1s |
Handling Traffic Spikes Without Rejected Requests
Because the new system renders maps directly, we can now scale automatically with load. Before, absorbing a spike meant adding capacity by hand or throttling requests. On launch day, a traffic spike we see regularly came through in full, with no rate limiting. For months, we'd slowed that same spike down or rejected part of it.
With this headroom and ability to scale on demand, we've raised rate limits on Static Maps requests. Your map tiles also benefit. Our tile servers used to render static maps, so a burst of static map traffic added load there. Static Maps now runs on its own stack.

Raster map tiles, before

Raster map tiles, after
But Wait, There's More
Static Maps now accepts fractional zoom levels, such as 12.5. You can frame a map exactly, instead of choosing between two whole zoom levels that are each a little off. Each image also now renders in a single pass. Labels no longer get cut off at internal boundaries, and a style or data update can't produce an image with mismatched sections.
What's Next
We're still tuning performance and reliability as the new system settles in. By building a faster, more stable Static Maps platform and relieving our other Maps systems of the burden of Static Maps, we not only make every response faster, but also allow us to launch more of your most-requested features across our entire Maps platform.
As always, reach out to us at support@stadiamaps.com with any questions.