The Web Map Service (WMS) is one of the most widely adopted standards in geospatial web development. Published by the Open Geospatial Consortium (OGC), WMS defines a protocol for requesting georeferenced map images from a server over HTTP. Whether you are building a web mapping application, integrating satellite imagery into a dashboard, or overlaying thematic layers on a base map, WMS provides a standardized interface that works across servers like GeoServer, MapServer, and QGIS Server. This guide covers the core WMS operations, client integration with Leaflet and OpenLayers, caching strategies, public providers, and common troubleshooting techniques.
What Is the OGC WMS Standard?
The OGC WMS standard specifies three operations that a compliant server must or may support: GetCapabilities, GetMap, and GetFeatureInfo. A WMS server accepts HTTP GET requests with query parameters and returns either XML metadata or rendered raster images. The current version is WMS 1.3.0, though version 1.1.1 remains common in production environments. Because WMS returns pre-rendered images rather than raw vector data, it is well suited for displaying large or complex datasets without transferring heavy payloads to the client. For scenarios that require access to the underlying feature geometries, see our WFS vs WMS comparison.
GetCapabilities: Discovering Available Layers
The GetCapabilities request is the starting point for any WMS integration. It returns an XML document that describes the service metadata, available layers, supported coordinate reference systems (CRS), image formats, and bounding boxes. Clients parse this document to populate layer selectors, determine valid CRS options, and construct subsequent GetMap requests.
https://example.com/geoserver/wms?
SERVICE=WMS&
VERSION=1.1.1&
REQUEST=GetCapabilities
The response XML contains a <Capability> element listing each published layer with its name, title, abstract, spatial extent, and supported output formats. When integrating a third-party WMS, always start with GetCapabilities to verify which layers and CRS values the server supports before building your map requests.
GetMap: Requesting Rendered Tiles
The GetMap operation is the core of WMS. It accepts parameters that define exactly what image the server should render and return. The essential parameters are:
- LAYERS — Comma-separated list of layer names to render
- BBOX — Bounding box coordinates (minx, miny, maxx, maxy)
- WIDTH / HEIGHT — Pixel dimensions of the output image
- SRS (1.1.1) or CRS (1.3.0) — Coordinate reference system
- FORMAT — Output format (image/png, image/jpeg)
https://example.com/geoserver/wms?
SERVICE=WMS&
VERSION=1.1.1&
REQUEST=GetMap&
LAYERS=topp:states&
BBOX=-180,-90,180,90&
WIDTH=800&
HEIGHT=400&
SRS=EPSG:4326&
FORMAT=image/png&
STYLES=&
TRANSPARENT=true
Setting TRANSPARENT=true with FORMAT=image/png produces images with transparent backgrounds, which is essential when overlaying WMS layers on top of a base map. JPEG is smaller in file size but does not support transparency, making it better suited for opaque base layers like satellite imagery.
GetFeatureInfo: Querying Attributes at a Pixel
The GetFeatureInfo operation lets clients query attribute data for features rendered at a specific pixel location in a GetMap image. When a user clicks on the map, the client sends the same parameters as a GetMap request plus QUERY_LAYERS, X/Y (or I/J in WMS 1.3.0), and INFO_FORMAT. The server identifies which features intersect that pixel and returns their attributes in the requested format (HTML, XML, GeoJSON, or plain text). This bridges the gap between WMS image rendering and interactive feature inspection without requiring a separate WFS endpoint.
Integrating WMS in Leaflet
Leaflet provides the L.tileLayer.wms() method for adding WMS layers to a map. Leaflet automatically handles tiling by splitting the viewport into 256×256 pixel tiles and issuing individual GetMap requests for each tile:
const wmsLayer = L.tileLayer.wms('https://example.com/geoserver/wms', {
layers: 'topp:states',
format: 'image/png',
transparent: true,
version: '1.1.1',
attribution: '© GeoServer'
});
wmsLayer.addTo(map);
You can combine multiple WMS layers using L.control.layers() to let users toggle overlays on and off. For GetFeatureInfo support, listen for map click events, construct the query URL manually using the click coordinates and map bounds, then display the response in a popup.
Integrating WMS in OpenLayers
OpenLayers provides a dedicated ol/source/TileWMS source that handles WMS tile requests. It offers more control over request parameters, tile grid configuration, and server type optimizations:
import TileLayer from 'ol/layer/Tile';
import TileWMS from 'ol/source/TileWMS';
const wmsLayer = new TileLayer({
source: new TileWMS({
url: 'https://example.com/geoserver/wms',
params: {
LAYERS: 'topp:states',
TILED: true,
FORMAT: 'image/png',
TRANSPARENT: true
},
serverType: 'geoserver'
})
});
map.addLayer(wmsLayer);
Setting serverType: 'geoserver' enables GeoServer-specific optimizations like vendor parameters. OpenLayers also provides ol/source/ImageWMS for single-image (untiled) WMS requests, which can be useful when you need the server to render the entire viewport as one image rather than splitting it into tiles.
Tile Caching Strategies
Rendering map images on every request is expensive. Tile caching stores pre-rendered tiles so that repeated requests for the same area and zoom level are served from cache instead of triggering server-side rendering. Two widely used caching solutions are:
- GeoWebCache — Built into GeoServer, it intercepts WMS requests and serves cached tiles in standard tile grid formats (TMS, WMTS). GeoServer's integrated caching means zero additional infrastructure for most deployments.
- MapProxy — A standalone Python-based tile cache and proxy that sits in front of any WMS server. It supports seeding (pre-generating tiles), reprojection, and merging layers from multiple backend sources.
Both solutions dramatically reduce server load and response times. For production deployments serving public-facing maps, tile caching is not optional — it is essential for acceptable performance.
Public WMS Providers
Several organizations publish free WMS endpoints that you can use as base layers or thematic overlays in your applications:
| Provider | Description | Endpoint |
|---|---|---|
| NASA GIBS | Global satellite imagery (MODIS, VIIRS, Landsat) | https://gibs.earthdata.nasa.gov/wms/epsg4326/best/wms.cgi |
| USGS National Map | Topographic maps, hydrography, elevation of the US | https://basemap.nationalmap.gov/arcgis/services/USGSTopo/MapServer/WMSServer |
| Copernicus (EU) | European land monitoring, CORINE land cover | https://land.copernicus.eu/en/map-viewer (via service endpoints) |
| Mundialis (OpenStreetMap) | Global OSM-based WMS rendering | https://ows.mundialis.de/services/service |
| Terrestris (TopPlus) | German topographic base maps | https://sgx.geodatenzentrum.de/wms_topplus_open |
Always check the usage policies and attribution requirements before embedding third-party WMS layers in production applications.
Troubleshooting Common WMS Issues
CORS Errors
Browsers block cross-origin WMS requests unless the server sends the appropriate Access-Control-Allow-Origin header. If you encounter CORS errors, configure the WMS server to include CORS headers, or route requests through a reverse proxy on your own domain. GeoServer supports CORS configuration through its web.xml filter settings.
CRS Mismatch
Requesting a CRS that the server does not support results in an error or distorted output. Always verify supported CRS values via GetCapabilities. A common mistake is using EPSG:3857 (Web Mercator) when the server only supports EPSG:4326, or vice versa. Note that WMS 1.3.0 changed the parameter name from SRS to CRS and reversed the axis order for geographic coordinate systems.
Blank Tiles
Blank or white tiles typically indicate one of three problems: the BBOX does not intersect the layer's spatial extent, the layer name is misspelled, or the server returned an XML error wrapped in an image response. To debug, open the tile URL directly in a browser and inspect the response. Check that LAYERS matches the exact name from GetCapabilities (case-sensitive) and that the BBOX falls within the layer's advertised extent. Also verify that STYLES is set to an empty string or a valid style name.
Next Steps
WMS is the foundation for serving rendered map layers on the web. Combined with tile caching, it scales to serve millions of requests with minimal server resources. If you need to go beyond image rendering and access the underlying vector data, explore the WFS standard for feature-level access. For converting geospatial data between formats before publishing, GeoDataTools provides browser-based tools for tasks like KML to GeoJSON conversion and data inspection.
FAQ
What is the difference between WMS and WMTS?
WMS renders map images on the fly for arbitrary bounding boxes and sizes, while WMTS (Web Map Tile Service) serves pre-rendered tiles from a fixed tile grid. WMTS is faster because tiles are cached and served as static files, but it offers less flexibility — you cannot request arbitrary extents or custom image sizes. Most production deployments use WMTS or tile-cached WMS for performance, falling back to raw WMS only when dynamic rendering is required (for example, applying real-time style changes or CQL filters to layers).
Can I use WMS layers offline?
WMS is an online protocol that requires HTTP access to the server. However, you can pre-download tiles for a specific area and zoom range using tools like MapProxy's seeding feature, Mobile Atlas Creator, or QGIS's offline editing capabilities. The downloaded tiles are stored locally and served without network access. This approach works well for field applications where connectivity is limited, though you lose the ability to receive real-time data updates from the server.
How do I fix blank tiles from a WMS server?
Start by opening a failing tile URL directly in the browser. If the server returns an XML error, it will reveal the cause — usually an unsupported CRS, an invalid layer name, or a BBOX outside the data extent. Verify the layer name matches the GetCapabilities response exactly (names are case-sensitive). Confirm that the SRS/CRS parameter uses a system the server supports. Ensure the BBOX coordinates are in the correct axis order for the WMS version you are using (WMS 1.3.0 uses lat/lon order for EPSG:4326, while 1.1.1 uses lon/lat). If tiles load in the browser but not in your application, the issue is likely CORS.