docker-staticmaps is an open-source API for rendering static map images. Easily create maps with markers, polygons, circles, polylines or text, making it perfect for embedding map images on websites or apps. Comes with built-in rate limiting and image caching to optimize performance and protect against abuse.
- β Generate static maps with markers, polygons, circles, polylines and text.
- π Supports multiple basemaps (OpenStreetMap, Esri, Stamen, Carto, custom tile server).
- β‘ Easy-to-use REST API - simple integration with any frontend or backend.
- π³ Docker-ready for fast, lightweight deployment.
- π§ Tile and image caching for performance.
- π¦ Built-in rate limiting per IP to protect against abuse.
Run the service with Docker:
docker run -p '3000:3000/tcp' mxdcodes/docker-staticmaps:latest
Send a sample request:
curl "http://localhost:3000/api/staticmaps?width=1000&height=1000¢er=-18.2871,147.6992&zoom=9&basemap=satellite"
A small demo UI is available at http://localhost:3000
Name | Type | Default Value | Description |
---|---|---|---|
PORT |
number |
3000 |
Port number for the API |
API_KEY |
string |
(none) | Optional key to restrict access |
LOG_LEVEL |
string |
INFO |
Logging level (DEBUG , INFO , WARN or ERROR ) |
TILE_CACHE_TTL |
number |
3600 |
Tile cache TTL in seconds. |
DISABLE_TILE_CACHE |
boolean |
false |
Set to true to disable tile caching |
RATE_LIMIT_MS |
number |
60000 |
Rate limit window in milliseconds |
RATE_LIMIT_MAX |
number |
60 |
Max requests per IP per window |
To run the container in detached mode:
docker run -d \
--name='docker-staticmaps' \
-p '3000:3000' \
-e API_KEY="your_api_key" \
-e LOG_LEVEL="INFO" \
-e TILE_CACHE_TTL=3600 \
-e DISABLE_TILE_CACHE=false \
-e RATE_LIMIT_MS=60000 \
-e RATE_LIMIT_MAX=60 \
mxdcodes/docker-staticmaps:latest
Or use docker-compose.yml
:
services:
docker-staticmaps:
image: mxdcodes/docker-staticmaps:latest
container_name: docker-staticmaps
restart: always
ports:
- "3000:3000"
environment:
- API_KEY=your_api_key
- LOG_LEVEL=INFO
- TILE_CACHE_TTL=3600
- DISABLE_TILE_CACHE=false
- RATE_LIMIT_MS=60000
- RATE_LIMIT_MAX=60
A Healthcheck endpoint is available at /health
.
Request static maps from the /api/staticmaps
endpoint using the following parameters:
Parameter | Default | Description |
---|---|---|
center |
(required) | Center of map (lon,lat , e.g. -119.49280,37.81084 ) |
zoom |
(required) | Zoom level (1 to 18 ). |
Parameter | Default | Description |
---|---|---|
width |
800 |
Image width in pixels |
height |
800 |
Image height in pixels |
paddingX |
0 |
Horizontal padding in pixels |
paddingY |
0 |
Vertical padding in pixels |
format |
png |
Output format: png , jpg , webp or pdf |
quality |
100 |
Image quality (0β100) for jpg /webp |
basemap |
osm |
Tile layer (see Basemap for supported types) |
attribution |
Attribution text (see Attribution) | |
tileUrl |
Tile URL with {x} , {y} , {z} or {quadkey} placeholders |
|
tileSubdomains |
[] |
Tile subdomains like ['a', 'b', 'c'] |
tileLayers |
[] |
Multiple tile layers with tileUrl and tileSubdomains |
tileSize |
256 |
Size of tiles in pixels |
tileRequestTimeout |
Tile request timeout (ms) | |
tileRequestHeader |
{} |
Extra headers for tile requests |
tileRequestLimit |
2 |
Max parallel tile requests |
zoomRange |
{ min: 1, max: 17 } |
Min and max zoom to try |
reverseY |
false |
Use TMS-style Y axis if true |
Use the basemap
parameter to select a predefined basemap or specify a custom
tile server with the tileUrl
parameter.
Key | Provider / Type |
---|---|
osm |
Open Street Map |
otm |
OpenTopoMap |
streets |
Esri Streets |
satellite |
Esri Satellite |
hybrid |
Esri Hybrid (satellite + labels) |
topo |
Esri Topographic |
gray |
Esri Gray w/ labels |
gray-background |
Esri Gray background only |
hillshade |
Esri Hillshade |
national-geographic |
National Geographic |
stamen-toner |
Stamen Toner (B/W) |
stamen-watercolor |
Stamen Watercolor |
carto-light |
Carto Light |
carto-dark |
Carto Dark |
Make sure to respect the usage policy of each provider!
The map service supports an optional attribution
query parameter to control whether and how attribution is rendered on the generated image.
- Attribution is shown by default (if nothing is passed).
- If no custom text is provided, the service uses the default attribution for the selected basemap.
The attribution
parameter accepts key-value pairs separated by |
, for example:
&attribution=show:true|text:Β© OpenStreetMap contributors
Key | Description | Example |
---|---|---|
show | true or false β controls visibility |
show:false |
text | Custom attribution text (URL-encoded) | text:%C2%A9%20Your%20Company |
To add one or more polylines, use the polyline
parameter one or multiple times in the URL query in the following format:
polyline=polylineStyle|polylineCoord1|polylineCoord2|...
-
polylineCoord:
- Lat, Lon Coordinates: Coordinates in
lat, lon
format, separated by|
. You need at least two coordinates. - Encoded Polylines: You can also use Google Encoded Polyline format.
- Lat, Lon Coordinates: Coordinates in
-
polylineStyle: Customize the polyline with:
Parameter Default Description weight
6
Sets the stroke width of the polyline. color
#0000ff
Defines the stroke color of the polyline. fill
Specifies the fill color of the polyline. strokeDasharray
(none) Pattern of dashes and gaps, e.g., 5,5
see stroke-dasharray.
Note: For each pair of coordinates in the input, a geodesic line is generated between them.
Regular Coordinates example with no zoom
, weight:6
, color:0000ff
http://localhost:3000/api/staticmaps?width=1200&height=800&format=png&basemap=national-geographic&polyline=weight:6|color:red|37.2159,-7.0050|28.0997,-17.1092&polyline=weight:6|color:red|28.0997,-17.1092|24.0617,-74.4767&polyline=weight:6|color:red|24.0617,-74.4767|24.2000,-74.5000&polyline=weight:6|color:red|24.2000,-74.5000|23.1167,-82.3833&polyline=weight:6|color:red|23.1167,-82.3833|19.0000,-72.7000
Multiple Encoded Polylines
http://localhost:3000/api/staticmaps?width=1200&height=800&format=png&basemap=national-geographic&polyline=weight:6|color:red|kvcbFfdwi@fosv@fnt|@ntsWzqc}Ik_ZrpCrqrErubo@j`cXsgbz@&polyline=weight:6|color:red|strokeDasharray:10,15|_}}rB~evzLs}iwBseqtG?_{jmBfddHc~_L
To add a polygon, use the polygon
parameter in this format:
polygon=polygonStyle|polygonCoord1|polygonCoord2|...
-
polygonCoord: List of coordinates in
lat, lon
format, separated by|
. The first and last coordinates should be the same to close the polygon. -
polygonStyle: Customize the polygon with:
Parameter Default Description color
#4874db
Defines the stroke color of the polygon. weight
5
Sets the stroke width of the polygon. fill
Specifies the fill color of the polygon. strokeDasharray
(none) Pattern of dashes and gaps, e.g., 5,5
see stroke-dasharray.
Example: Polygon with color 4874db
, weight 7
, and fill eb7a34
http://localhost:3000/api/staticmaps?width=800&height=800&basemap=satellite&polygon=color:332fd0|weight:3|fill:00FF003F|54.82446670532232,9.421944618225211|54.81986236572277,9.426388740539608|54.818473815918026,9.426388740539608|54.8165283203125,9.428054809570256|54.814861297607365,9.428054809570256|54.812637329101676,9.431389808654785|54.81124877929693,9.43194580078125|54.81069564819336,9.435277938842773|54.80847167968744,9.43972206115734|54.80736160278332,9.43972206115734|54.806526184082145,9.43861007690441|54.8051376342774,9.435277938842773|54.803470611572266,9.435277938842773|54.802917480468864,9.43194580078125|54.800971984863395,9.429166793823185|54.79875183105469,9.429720878601074|54.79375076293945,9.434721946716252|54.7926406860351,9.434721946716252|54.791805267333984,9.433055877685604|54.791526794433594,9.43416786193859|54.78985977172863,9.43416786193859|54.788471221923885,9.435277938842773|54.788749694824276,9.436389923095703|54.79013824462902,9.435833930969238|54.79041671752941,9.436944007873592|54.79569625854498,9.436945915222168|54.79680633544933,9.435833930969238|54.79902648925787,9.435833930969238|54.79930496215826,9.436944007873592|54.80152893066412,9.436944007873592|54.803195953369254,9.438055992126522|54.80458450317383,9.43972206115734|54.80764007568365,9.453055381774902|54.81013870239258,9.454723358154297|54.81124877929693,9.454723358154297|54.81124877929693,9.453055381774902|54.812362670898494,9.453055381774902|54.81402587890625,9.455277442932186|54.81541824340832,9.455277442932186|54.8165283203125,9.457498550415039|54.81735992431646,9.456946372985897|54.81930541992199,9.460277557373104|54.82041549682617,9.460833549499569|54.82152938842768,9.464165687561035|54.82263946533203,9.4647216796875|54.82291793823242,9.468609809875431|54.823749542236385,9.469721794128361|54.824028015136776,9.473056793212947|54.82291793823242,9.47583293914795|54.82319259643566,9.483611106872559|54.82273864746105,9.482230186462402|54.815219879150504,9.482759475708065|54.81542968750006,9.488989830017147|54.80834197998047,9.501990318298454|54.80062103271496,9.496249198913574|54.79687118530285,9.496500015258846|54.793331146240234,9.502988815307617|54.789379119873104,9.496978759765625|54.77442932128912,9.497907638549862|54.77051162719732,9.491870880126896|54.7703094482423,9.48559856414795|54.773860931396484,9.479109764099235|54.77759170532232,9.478879928588924|54.77740097045904,9.472619056701717|54.77347946166992,9.466569900512752|54.76604080200195,9.466990470886344|54.765670776367244,9.454428672790527|54.75452041625982,9.4550399780274|54.75062942504883,9.448939323425293|54.75045013427746,9.44265079498291|54.75416183471691,9.442468643188477|54.75226974487316,9.373150825500545|54.75595855712902,9.372980117797795|54.76689147949213,9.366157531738338|54.77040863037115,9.359689712524414|54.777629852295036,9.353049278259391|54.78133010864258,9.352879524230957|54.78186035156256,9.371758460998592|54.78573989868164,9.377868652343864|54.789451599121094,9.377679824829158|54.78963851928722,9.383960723876953|54.79391860961914,9.402589797973633|54.80508041381847,9.401970863342285|54.816478729248104,9.40755939483654|54.82001113891596,9.401079177856445|54.823760986328125,9.400839805603084|54.82446670532232,9.421944618225211&polygon=color:FF5733|weight:2|fill:FF00003F|54.780,9.390|54.782,9.392|54.784,9.391|54.785,9.389|54.784,9.387|54.782,9.386|54.780,9.387|54.779,9.388|54.780,9.390
To add one or more markers, use the markers
parameter in this format:
markers=markerStyle|markerCoord1|markerCoord2|...
-
markerCoord: Coordinates for each marker in
lat, lon
format, separated by|
. You need at least one coordinate. -
markerStyle: Customize the marker with:
Parameter Default Description img
(optional) URL or file path for a custom marker image. color
#d9534f
Color of the Marker. width
28
Width of marker image in px. height
28
Height of marker image in px. drawWidth
width
Resize marker image to width in px. drawHeight
height
Resize marker image to height in px. offsetX
13.5
Horizontal offset for the marker position. offsetY
27.5
Vertical offset for the marker position. resizeMode
cover
Applied resize method if needed. See: https://sharp.pixelplumbing.com/api-resize
Example: Multiple Markers
http://localhost:3000/api/staticmaps?width=1200&height=800&format=png&basemap=national-geographic&markers=color:red|37.2159,-7.0050|28.0997,-17.1092|24.0617,-74.4767|24.2000,-74.5000|23.1167,-82.3833|19.0000,-72.7000|38.7169,-27.2231|38.7169,-9.1399|37.2159,-7.0050&markers=color:green|36.5271,-6.2886|15.4150,-61.3710|16.2650,-61.5510|18.4655,-66.1057|18.4861,-69.9312|21.5218,-77.7812&markers=color:orange|36.7781,-6.3515|14.9167,-23.5167|10.6000,-61.2000|8.5833,-62.4000|18.4861,-69.9312&markers=color:blue|36.5271,-6.2886|17.9352,-76.8419|15.9194,-85.9597|9.3547,-79.9014|21.5218,-77.7812|36.5271,-6.2886
To add a circle, use the circle
parameter in this format:
circle=circleStyle|circleCoord
-
circleCoord: Coordinates for the circle's center in lat, lon format, separated by |. You need at least one coordinate.
-
circleStyle: Customize the circle with:
Parameter Default Description radius
(required) Specifies the radius of the element. color
#0000bb
Defines the stroke color of the element. width
3
Sets the stroke width of the element. fill
{color}
Specifies the fill color of the element.
Example: Circle with a radius of 20
meters.
http://localhost:3000/api/staticmaps?width=600&height=600&basemap=osm&circle=radius:20|color:4874dbb2|fill:0000bbbd|width:10|48.726304979176675,-3.9829935637739382
To add text, use the text
parameter in this format:
text=textStyle|textCoord
-
textCoord: Coordinates for the text's anchor in lat, lon format.
-
textStyle: Customize the text with:
Parameter Default Description text
(required) The text to render. color
#000000BB
Stroke color of the text width
1
Stroke width of the text fill
#000000
Fill color of the text size
12
Font-size of the text font
Arial
Font-family of the text anchor
start
Determines the text anchor alignment. offsetX
0
Horizontal offset relative to the coordinate. offsetY
0
Vertical offset relative to the coordinate.
Example: Text "Hello World" with custom styling.
http://localhost:3000/api/staticmaps?width=600&height=600&text=text:Hello%20World|size:20|48.8566,2.3522
Example with width=500
, height=500
, center=-73.99515,40.76761
, zoom=10
, basemap=national-geographic
http://localhost:3000/api/staticmaps?width=500&height=500Β’er=40.76761,-73.99515&zoom=10&format=webp&basemap=national-geographic
Multiple Markers and multiple Polylines with encodedPolyline aswell as lon,lat coordinatesExample and a custom attribution
http://localhost:3000/api/staticmaps?width=1200&height=800&format=png&basemap=national-geographic&polyline=weight:6|color:red|kvcbFfdwi@fosv@fnt|@ntsWzqc}Ik_ZrpCrqrErubo@j`cXsgbz@&polyline=weight:6|color:red|strokeDasharray:10,15|_}}rB~evzLs}iwBseqtG?_{jmBfddHc~_L&polyline=weight:6|color:green|ke}}Evfke@rmz_C~geoIo_eD~cb@cxlLzqxZw_CjdjVc|oQne|n@&polyline=weight:6|color:orange|cfn_Fzowe@vxldCnqwgBjbjYr__eFj{hK~jiFocm{@~|}l@@&polyline=weight:6|color:blue|ke}}Evfke@jfnpBb}rmLvuhKfysv@jdag@kg~c@kkgiAgb}KcvqzAwkjsL&text=text:First%20Voyage%20(1492%E2%80%931493)|size:20|color:red|38.7169,-27.2231&text=text:Second%20Voyage%20(1493%E2%80%931496)|size:20|color:green|offsetX:-230|18.4655,%20-66.1057&text=text:Third%20Voyage%20(1498%E2%80%931500)|size:20|offsetY:-10|color:orange|8.5833,-62.4000&&text=text:Fourth%20Voyage%20(1502%E2%80%931504)|size:20|color:blue|offsetY:-30|offsetX:50|9.3547,-79.9014&markers=color:red|37.2159,-7.0050|28.0997,-17.1092|24.0617,-74.4767|24.2000,-74.5000|23.1167,-82.3833|19.0000,-72.7000|38.7169,-27.2231|38.7169,-9.1399|37.2159,-7.0050&markers=color:green|36.5271,-6.2886|15.4150,-61.3710|16.2650,-61.5510|18.4655,-66.1057|18.4861,-69.9312|21.5218,-77.7812&markers=color:orange|36.7781,-6.3515|14.9167,-23.5167|10.6000,-61.2000|8.5833,-62.4000|18.4861,-69.9312&markers=color:blue|36.5271,-6.2886|17.9352,-76.8419|15.9194,-85.9597|9.3547,-79.9014|21.5218,-77.7812|36.5271,-6.2886&attribution=text:Esri,%20USGS%20Esri,%20TomTom,%20FAO,%20NOAA,%20USGS
Also, POST
requests are supported:
Example with markers, polyline, polygon and circle
curl -X POST http://localhost:3000/api/staticmaps \
-H "Content-Type: application/json" \
-H "x-api-key: yourSecretApiKeyHere" \
-d '{
"width": 600,
"height": 600,
"polyline": [
{
"weight": 6,
"color": "#0000ff",
"coords": [
[-74.006, 40.7128],
[18.424055, -33.924869]
]
},
{
"weight": 6,
"color": "red",
"coords": [
[2.352222, 48.856614],
[18.424055, -33.924869]
]
}
],
"markers": {
"coords": [
[2.352222, 48.856614],
[-74.006, 40.7128],
[18.424055, -33.924869]
]
}
}' --output custom_map.png
To run the project locally, follow these steps:
- Clone the repository:
git clone https://github.com/dietrichmax/docker-staticmaps
- Install the dependencies:
npm install
- Start the development server:
npm run dev
Enjoy building and customizing your static maps! πβ¨