Features Pricing Docs Contact Dashboard

Grayscale Map Style

Grayscale renders the entire map in neutral grey tones. It is print-ready, accessibility-friendly, and works exceptionally well as a neutral canvas for coloured choropleth or heat-map overlays.

Style URL

https://tiles.latlng.work/v1/styles/grayscale.json?key=YOUR_KEY

Raster PNG tiles

https://tiles.latlng.work/v1/tiles/{z}/{x}/{y}.png?key=YOUR_KEY&style=grayscale

Compatible with

MapLibre GL JS · Leaflet · React Map GL · iOS · Android

Data source

OpenStreetMap contributors · ODbL

Code samples

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <link rel="stylesheet" href="https://unpkg.com/maplibre-gl@4/dist/maplibre-gl.css" />
  <style>
    body { margin: 0; padding: 0; }
    #map { width: 100vw; height: 100vh; }
  </style>
</head>
<body>
  <div id="map"></div>
  <script src="https://unpkg.com/maplibre-gl@4/dist/maplibre-gl.js"></script>
  <script>
    const map = new maplibregl.Map({
      container: 'map',
      style: 'https://tiles.latlng.work/v1/styles/grayscale.json?key=YOUR_KEY',
      center: [0, 20],
      zoom: 3,
    });

    map.addControl(new maplibregl.NavigationControl());
  </script>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9/dist/leaflet.css" />
  <link rel="stylesheet" href="https://unpkg.com/maplibre-gl@4/dist/maplibre-gl.css" />
  <style>
    body { margin: 0; }
    #map { width: 100vw; height: 100vh; }
  </style>
</head>
<body>
  <div id="map"></div>
  <script src="https://unpkg.com/leaflet@1.9/dist/leaflet.js"></script>
  <script src="https://unpkg.com/maplibre-gl@4/dist/maplibre-gl.js"></script>
  <script src="https://unpkg.com/@maplibre/maplibre-gl-leaflet@0.0.22/leaflet-maplibre-gl.js"></script>
  <script>
    const map = L.map('map').setView([20, 0], 3);

    L.maplibreGL({
      style: 'https://tiles.latlng.work/v1/styles/grayscale.json?key=YOUR_KEY',
    }).addTo(map);
  </script>
</body>
</html>
import requests

API_KEY = 'YOUR_KEY'
STYLE   = 'grayscale'

# 1. Fetch the style JSON
style = requests.get(
  f'https://tiles.latlng.work/v1/styles/{STYLE}.json',
  params={'key': API_KEY},
).json()

tile_template = style['sources']['latlng']['tiles'][0]
print('Tile URL template:', tile_template)

# 2. Download a single vector tile (z=5, x=16, y=11 — Western Europe)
url = tile_template.replace('{z}','5').replace('{x}','16').replace('{y}','11')
tile = requests.get(url)
print(f'Vector tile: {len(tile.content)} bytes')

# 3. Download a raster PNG tile in this style
png = requests.get(
  'https://tiles.latlng.work/v1/tiles/5/16/11.png',
  params={'key': API_KEY, 'style': STYLE},
)
with open('tile.png', 'wb') as f:
  f.write(png.content)
print('Raster tile saved to tile.png')
# 1. Fetch the full style JSON
curl "https://tiles.latlng.work/v1/styles/grayscale.json?key=YOUR_KEY"

# 2. Download a vector tile (z=5, x=16, y=11 — Western Europe)
curl "https://tiles.latlng.work/v1/tiles/5/16/11.pbf?key=YOUR_KEY" \
  -H "Accept: application/x-protobuf" \
  --output tile.pbf

# 3. Download a raster PNG tile rendered in the grayscale style
curl "https://tiles.latlng.work/v1/tiles/5/16/11.png?key=YOUR_KEY&style=grayscale" \
  --output tile.png
// npm install react-map-gl maplibre-gl
import Map, { NavigationControl } from 'react-map-gl/maplibre';
import 'maplibre-gl/dist/maplibre-gl.css';

const STYLE_URL = 'https://tiles.latlng.work/v1/styles/grayscale.json?key=YOUR_KEY';

export default function App() {
  return (
    <Map
      initialViewState={{ longitude: 0, latitude: 20, zoom: 3 }}
      style={{ width: '100%', height: '100vh' }}
      mapStyle={STYLE_URL}
    >
      <NavigationControl position="bottom-right" />
    </Map>
  );
}
// Swift — MapLibre Native iOS
// Add to Podfile: pod 'MapLibre', '~> 6.0'

import MapLibre

class MapViewController: UIViewController {

  override func viewDidLoad() {
    super.viewDidLoad()

    let styleURL = URL(string: "https://tiles.latlng.work/v1/styles/grayscale.json?key=YOUR_KEY")!
    let mapView  = MLNMapView(frame: view.bounds, styleURL: styleURL)

    mapView.autoresizingMask    = [.flexibleWidth, .flexibleHeight]
    mapView.allowsRotating      = true
    mapView.allowsTilting       = true
    mapView.zoomLevel           = 3
    mapView.centerCoordinate    = CLLocationCoordinate2D(latitude: 20, longitude: 0)

    view.addSubview(mapView)
  }
}
// Kotlin — MapLibre Native Android
// build.gradle: implementation 'org.maplibre.gl:android-sdk:11.+'

import org.maplibre.android.MapLibre
import org.maplibre.android.camera.CameraPosition
import org.maplibre.android.geometry.LatLng
import org.maplibre.android.maps.MapView

class MainActivity : AppCompatActivity() {

  private lateinit var mapView: MapView

  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    MapLibre.getInstance(this)
    setContentView(R.layout.activity_main)

    mapView = findViewById(R.id.mapView)
    mapView.onCreate(savedInstanceState)

    mapView.getMapAsync { map ->
      map.setStyle("https://tiles.latlng.work/v1/styles/grayscale.json?key=YOUR_KEY")

      map.cameraPosition = CameraPosition.Builder()
        .target(LatLng(20.0, 0.0))
        .zoom(3.0)
        .build()
    }
  }

  // forward lifecycle events
  override fun onStart()   { super.onStart();   mapView.onStart() }
  override fun onResume()  { super.onResume();  mapView.onResume() }
  override fun onPause()   { super.onPause();   mapView.onPause() }
  override fun onStop()    { super.onStop();    mapView.onStop() }
  override fun onDestroy() { super.onDestroy(); mapView.onDestroy() }
  override fun onSaveInstanceState(out: Bundle) {
    super.onSaveInstanceState(out); mapView.onSaveInstanceState(out)
  }
}
Get Free API Key → Browse all styles

Free tier includes 3,000 tile requests/day. No credit card required.