tileserver-rs includes a powerful static image API similar to Mapbox Static Images. Generate PNG, JPEG, or WebP images for:
- Social media cards and Open Graph images
- Email thumbnails
- Print exports
- Image placeholders before map loads
- Server-side map rendering
Basic Usage
Center-Based Images
Specify center coordinates and zoom level:
GET /styles/{style}/static/{lon},{lat},{zoom}/{width}x{height}.{format}
# San Francisco at zoom 12, 800x600 PNG
curl "http://localhost:8080/styles/bright/static/-122.4194,37.7749,12/800x600.png" > sf.png
# Tokyo at zoom 14, 1200x630 JPEG (Open Graph size)
curl "http://localhost:8080/styles/bright/static/139.6917,35.6895,14/1200x630.jpeg" > tokyo.jpg
# WebP format (smaller file size)
curl "http://localhost:8080/styles/bright/static/2.3522,48.8566,13/800x600.webp" > paris.webp
With Bearing and Pitch
Add rotation (bearing) and tilt (pitch) for 3D-style views:
GET /styles/{style}/static/{lon},{lat},{zoom}@{bearing},{pitch}/{width}x{height}.{format}
# 45-degree rotation, 60-degree tilt
curl "http://localhost:8080/styles/bright/static/-122.4,37.8,15@45,60/800x600.png" > tilted.png
# North-up (0 bearing), slight tilt
curl "http://localhost:8080/styles/bright/static/11.255,43.77,16@0,30/800x600.png" > florence.png
Bounding Box Images
Fit a specific geographic area:
GET /styles/{style}/static/{minLon},{minLat},{maxLon},{maxLat}/{width}x{height}.{format}
# Bay Area bounding box
curl "http://localhost:8080/styles/bright/static/-122.6,37.4,-121.8,37.9/1024x768.png" > bay-area.png
# Manhattan
curl "http://localhost:8080/styles/bright/static/-74.02,40.7,-73.97,40.8/800x1000.png" > manhattan.png
Retina/HiDPI Images
Add @2x or @3x for high-resolution displays:
# 2x resolution (1600x1200 actual pixels for 800x600 display)
curl "http://localhost:8080/styles/bright/static/-122.4,37.8,12/[email protected]" > [email protected]
# 3x resolution
curl "http://localhost:8080/styles/bright/static/-122.4,37.8,12/[email protected]" > [email protected]
Retina images are larger in file size but provide crisp maps on high-DPI displays like Retina MacBooks, iPhones, and modern Android devices.
Overlays
Path/Route Overlays
Draw lines on the map using the path query parameter:
?path=path-{strokeWidth}+{color}({lon1},{lat1}|{lon2},{lat2}|...)
# Red route, 5px wide
curl "http://localhost:8080/styles/bright/static/-122.4,37.8,12/800x600.png?\
path=path-5+ff0000(-122.42,37.78|-122.41,37.79|-122.40,37.78)" > route.png
# Blue dashed path
curl "http://localhost:8080/styles/bright/static/auto/800x600.png?\
path=path-3+0066ff(-122.5,37.7|-122.4,37.8|-122.3,37.75)" > blue-route.png
Path format:
path-5= 5 pixel stroke width+ff0000= stroke color (hex, 3/4/6/8 digits)-00ff0080= fill color for closed polygons (optional, hex with alpha)(coords)= pipe-separated lon,lat pairs
Filled Polygons
Add a fill color after the stroke color with -:
?path=path-{strokeWidth}+{strokeColor}-{fillColor}({lon1},{lat1}|{lon2},{lat2}|...)
# Red stroke, semi-transparent green fill
curl "http://localhost:8080/styles/bright/static/-122.4,37.8,12/800x600.png?\
path=path-3+ff0000-8000ff00(-122.42,37.78|-122.40,37.80|-122.38,37.78|-122.42,37.78)" > polygon.png
# Blue stroke, semi-transparent blue fill
curl "http://localhost:8080/styles/bright/static/auto/800x600.png?\
path=path-2+0000ff-400000ff(-122.5,37.7|-122.3,37.7|-122.3,37.9|-122.5,37.9|-122.5,37.7)" > area.png
The fill color supports 8-digit hex for alpha transparency (e.g., 8000ff00 = green at 50% opacity). Polygons are auto-closed when the first and last points are more than 0.5px apart.
Multiple Paths
Separate multiple paths with ~:
curl "http://localhost:8080/styles/bright/static/auto/800x600.png?\
path=path-4+ff0000(-122.4,37.8|-122.5,37.85)~path-4+0000ff(-122.45,37.78|-122.35,37.82)" > multi-route.png
Marker Overlays
Add markers using the marker query parameter:
?marker=pin-{size}[-{label}]+{color}({lon},{lat})
# Small red pin
curl "http://localhost:8080/styles/bright/static/-122.4,37.8,14/800x600.png?\
marker=pin-s+ff0000(-122.4,37.8)" > marker.png
# Medium blue pin with label "A"
curl "http://localhost:8080/styles/bright/static/-122.4,37.8,14/800x600.png?\
marker=pin-m-A+0066ff(-122.4,37.8)" > labeled-marker.png
# Large green pin
curl "http://localhost:8080/styles/bright/static/-122.4,37.8,14/800x600.png?\
marker=pin-l+00ff00(-122.4,37.8)" > large-marker.png
Marker sizes:
pin-s= small (20x50 pixels)pin-m= medium (30x70 pixels)pin-l= large (40x100 pixels)
Multiple Markers
curl "http://localhost:8080/styles/bright/static/auto/800x600.png?\
marker=pin-s-A+ff0000(-122.42,37.78)~pin-s-B+00ff00(-122.40,37.79)~pin-s-C+0000ff(-122.41,37.77)" > abc-markers.png
GeoJSON Overlays
Pass a GeoJSON geometry, Feature, or FeatureCollection via the geojson query parameter:
# Point marker from GeoJSON
curl "http://localhost:8080/styles/bright/static/-122.4,37.8,12/800x600.png?\
geojson=%7B%22type%22%3A%22Point%22%2C%22coordinates%22%3A%5B-122.4%2C37.8%5D%7D" > point.png
# Polygon with fill from GeoJSON Feature
curl "http://localhost:8080/styles/bright/static/auto/800x600.png?\
geojson=%7B%22type%22%3A%22Feature%22%2C%22geometry%22%3A%7B%22type%22%3A%22Polygon%22%2C%22coordinates%22%3A%5B%5B%5B-122.5%2C37.7%5D%2C%5B-122.3%2C37.7%5D%2C%5B-122.3%2C37.9%5D%2C%5B-122.5%2C37.9%5D%2C%5B-122.5%2C37.7%5D%5D%5D%7D%2C%22properties%22%3A%7B%22fill%22%3A%22%2300ff00%22%2C%22stroke%22%3A%22%23ff0000%22%7D%7D" > geojson.png
Supported GeoJSON types: Point, MultiPoint, LineString, MultiLineString, Polygon, MultiPolygon, Feature, FeatureCollection.
Styling via simplestyle-spec properties:
| Property | Type | Description | Default |
|---|---|---|---|
stroke | hex color string | Stroke color (e.g., "#ff0000") | #0000ff |
stroke-width | number | Stroke width in pixels | 3 |
fill | hex color string | Fill color for polygons | none |
marker-color | hex color string | Marker color for points | #ff0000 |
marker-size | string or number | "small" (8px), "medium" (12px), "large" (18px), or numeric px | 12 |
The geojson parameter value must be URL-encoded. You can combine geojson with path and marker parameters — all overlays are drawn together.
Auto-Fit Mode
Use auto to automatically fit the map to your overlays:
# Fit to route
curl "http://localhost:8080/styles/bright/static/auto/800x600.png?\
path=path-5+ff0000(-122.5,37.7|-122.4,37.8|-122.3,37.9)" > auto-route.png
# Fit to markers
curl "http://localhost:8080/styles/bright/static/auto/800x600.png?\
marker=pin-s+ff0000(-122.5,37.7)~pin-s+ff0000(-122.3,37.9)" > auto-markers.png
Auto-Fit Options
| Parameter | Description | Default |
|---|---|---|
padding | Padding ratio around content | 0.1 (10%) |
maxzoom | Maximum zoom level | 18 |
# More padding (20%)
curl "http://localhost:8080/styles/bright/static/auto/800x600.png?\
path=path-5+ff0000(-122.5,37.7|-122.3,37.9)&padding=0.2" > padded.png
# Limit max zoom to 14
curl "http://localhost:8080/styles/bright/static/auto/800x600.png?\
marker=pin-s+ff0000(-122.4,37.8)&maxzoom=14" > limited-zoom.png
Use Cases
Open Graph / Social Cards
Generate images for social media sharing (1200x630 is the recommended OG size):
# Generate OG image for a location page
curl "http://localhost:8080/styles/bright/static/${LON},${LAT},14/1200x630.png" > og-image.png
<meta property="og:image" content="https://yourdomain.com/og-image.png" />
Email Thumbnails
Static images work in all email clients (unlike interactive maps):
<img
src="https://tiles.yourdomain.com/styles/bright/static/-122.4,37.8,12/400x300.png"
alt="Map of San Francisco"
/>
Route Preview
Show a route preview before loading the full interactive map:
// Generate static image URL
const routeCoords = route.map((c) => `${c[0]},${c[1]}`).join('|');
const staticUrl = `http://localhost:8080/styles/bright/static/auto/800x400.png?path=path-4+3388ff(${routeCoords})`;
// Show as placeholder
document.getElementById('map-placeholder').src = staticUrl;
Print Export
Generate high-resolution images for printing:
# A4 landscape at 300 DPI (3508x2480 pixels)
curl "http://localhost:8080/styles/bright/static/-122.4,37.8,12/3508x2480.png" > print-a4.png
# Use @2x for even higher quality
curl "http://localhost:8080/styles/bright/static/-122.4,37.8,12/[email protected]" > print-a4-hd.png
Performance
Static image generation involves server-side rendering:
| Scenario | Typical Time |
|---|---|
| Warm cache (tiles cached) | ~100-200ms |
| Cold cache (fetching tiles) | ~500-800ms |
| Large image (3000x2000) | ~1-2s |
| With overlays | +50-100ms |
Optimization Tips
- Use caching - Set up a CDN or reverse proxy cache for static images
- Limit dimensions - Larger images take longer to render
- Use WebP - Smaller file sizes than PNG/JPEG
- Pre-generate - For common images, generate ahead of time
# nginx caching example
location ~ ^/styles/.*/static/ {
proxy_pass http://tileserver:8080;
proxy_cache static_maps;
proxy_cache_valid 200 1h;
proxy_cache_key $uri$is_args$args;
}
Error Handling
| HTTP Code | Meaning |
|---|---|
200 | Success |
400 | Invalid parameters (bad coordinates, dimensions) |
404 | Style not found |
500 | Rendering error |
Common errors:
# Invalid coordinates
curl "http://localhost:8080/styles/bright/static/invalid,coords,12/800x600.png"
# Returns 400 Bad Request
# Style doesn't exist
curl "http://localhost:8080/styles/nonexistent/static/-122.4,37.8,12/800x600.png"
# Returns 404 Not Found
API Reference
See the full Static Image API Reference for all parameters and options.